diff --git a/.eslintrc.js b/.eslintrc.js index 3059df17f..c1cc4dc4c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,6 +2,7 @@ module.exports = { plugins: [ "matrix-org", "import", + "jsdoc", ], extends: [ "plugin:matrix-org/babel", @@ -45,7 +46,7 @@ module.exports = { // restrict EventEmitters to force callers to use TypedEventEmitter "no-restricted-imports": ["error", { name: "events", - message: "Please use TypedEventEmitter instead" + message: "Please use TypedEventEmitter instead", }], "import/no-restricted-paths": ["error", { @@ -61,6 +62,9 @@ module.exports = { files: [ "**/*.ts", ], + plugins: [ + "eslint-plugin-tsdoc", + ], extends: [ "plugin:matrix-org/typescript", ], @@ -84,6 +88,23 @@ module.exports = { "quotes": "off", // We use a `logger` intermediary module "no-console": "error", + + }, + }, { + // We don't need amazing docs in our spec files + files: [ + "src/**/*.ts", + ], + rules: { + "tsdoc/syntax": "error", + // We use some select jsdoc rules as the tsdoc linter has only one rule + "jsdoc/no-types": "error", + "jsdoc/empty-tags": "error", + "jsdoc/check-property-names": "error", + "jsdoc/check-values": "error", + // These need a bit more work before we can enable + // "jsdoc/check-param-names": "error", + // "jsdoc/check-indentation": "error", }, }, { files: [ diff --git a/package.json b/package.json index 76529468d..2685e5d28 100644 --- a/package.json +++ b/package.json @@ -88,8 +88,8 @@ "@types/node": "18", "@types/sdp-transform": "^2.4.5", "@types/uuid": "7", - "@typescript-eslint/eslint-plugin": "^5.6.0", - "@typescript-eslint/parser": "^5.6.0", + "@typescript-eslint/eslint-plugin": "^5.45.0", + "@typescript-eslint/parser": "^5.45.0", "allchange": "^1.0.6", "babel-jest": "^29.0.0", "babelify": "^10.0.0", @@ -101,7 +101,9 @@ "eslint-config-google": "^0.14.0", "eslint-import-resolver-typescript": "^3.5.1", "eslint-plugin-import": "^2.26.0", + "eslint-plugin-jsdoc": "^39.6.4", "eslint-plugin-matrix-org": "^0.8.0", + "eslint-plugin-tsdoc": "^0.2.17", "eslint-plugin-unicorn": "^45.0.0", "exorcist": "^2.0.0", "fake-indexeddb": "^4.0.0", diff --git a/spec/TestClient.ts b/spec/TestClient.ts index 02d26b6a7..8b54fd92a 100644 --- a/spec/TestClient.ts +++ b/spec/TestClient.ts @@ -105,7 +105,7 @@ export class TestClient { /** * stop the client - * @return {Promise} Resolves once the mock http backend has finished all pending flushes + * @returns Promise which resolves once the mock http backend has finished all pending flushes */ public async stop(): Promise { this.client.stopClient(); @@ -135,7 +135,7 @@ export class TestClient { * set up an expectation that the keys will be uploaded, and wait for * that to happen. * - * @returns {Promise} for the one-time keys + * @returns Promise for the one-time keys */ public awaitOneTimeKeyUpload(): Promise> { if (Object.keys(this.oneTimeKeys!).length != 0) { @@ -177,7 +177,7 @@ export class TestClient { * * We check that the query contains each of the users in `response`. * - * @param {Object} response response to the query. + * @param response - response to the query. */ public expectKeyQuery(response: IDownloadKeyResult) { this.httpBackend.when('POST', '/keys/query').respond( @@ -202,7 +202,7 @@ export class TestClient { /** * get the uploaded curve25519 device key * - * @return {string} base64 device key + * @returns base64 device key */ public getDeviceKey(): string { const keyId = 'curve25519:' + this.deviceId; @@ -212,7 +212,7 @@ export class TestClient { /** * get the uploaded ed25519 device key * - * @return {string} base64 device key + * @returns base64 device key */ public getSigningKey(): string { const keyId = 'ed25519:' + this.deviceId; diff --git a/spec/integ/devicelist-integ.spec.ts b/spec/integ/devicelist-integ.spec.ts index 5b980149b..35af27e51 100644 --- a/spec/integ/devicelist-integ.spec.ts +++ b/spec/integ/devicelist-integ.spec.ts @@ -26,9 +26,7 @@ const ROOM_ID = "!room:id"; * get a /sync response which contains a single e2e room (ROOM_ID), with the * members given * - * @param {string[]} roomMembers - * - * @return {object} sync response + * @returns sync response */ function getSyncResponse(roomMembers: string[]) { const stateEvents = [ diff --git a/spec/integ/matrix-client-crypto.spec.ts b/spec/integ/matrix-client-crypto.spec.ts index ae58be1c9..74366a21b 100644 --- a/spec/integ/matrix-client-crypto.spec.ts +++ b/spec/integ/matrix-client-crypto.spec.ts @@ -60,7 +60,7 @@ async function bobUploadsDeviceKeys(): Promise { /** * Set an expectation that querier will query uploader's keys; then flush the http request. * - * @return {promise} resolves once the http request has completed. + * @returns resolves once the http request has completed. */ function expectQueryKeys(querier: TestClient, uploader: TestClient): Promise { // can't query keys before bob has uploaded them @@ -83,7 +83,7 @@ const expectBobQueryKeys = () => expectQueryKeys(bobTestClient, aliTestClient); /** * Set an expectation that ali will claim one of bob's keys; then flush the http request. * - * @return {promise} resolves once the http request has completed. + * @returns resolves once the http request has completed. */ async function expectAliClaimKeys(): Promise { const keys = await bobTestClient.awaitOneTimeKeyUpload(); @@ -151,7 +151,7 @@ const bobEnablesEncryption = () => clientEnablesEncryption(bobTestClient.client) * Ali sends a message, first claiming e2e keys. Set the expectations and * check the results. * - * @return {promise} which resolves to the ciphertext for Bob's device. + * @returns which resolves to the ciphertext for Bob's device. */ async function aliSendsFirstMessage(): Promise { // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -168,7 +168,7 @@ async function aliSendsFirstMessage(): Promise { * Ali sends a message without first claiming e2e keys. Set the expectations * and check the results. * - * @return {promise} which resolves to the ciphertext for Bob's device. + * @returns which resolves to the ciphertext for Bob's device. */ async function aliSendsMessage(): Promise { // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -183,7 +183,7 @@ async function aliSendsMessage(): Promise { * Bob sends a message, first querying (but not claiming) e2e keys. Set the * expectations and check the results. * - * @return {promise} which resolves to the ciphertext for Ali's device. + * @returns which resolves to the ciphertext for Ali's device. */ async function bobSendsReplyMessage(): Promise { // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -198,7 +198,7 @@ async function bobSendsReplyMessage(): Promise { /** * Set an expectation that Ali will send a message, and flush the request * - * @return {promise} which resolves to the ciphertext for Bob's device. + * @returns which resolves to the ciphertext for Bob's device. */ async function expectAliSendMessageRequest(): Promise { const content = await expectSendMessageRequest(aliTestClient.httpBackend); @@ -212,7 +212,7 @@ async function expectAliSendMessageRequest(): Promise { /** * Set an expectation that Bob will send a message, and flush the request * - * @return {promise} which resolves to the ciphertext for Bob's device. + * @returns which resolves to the ciphertext for Bob's device. */ async function expectBobSendMessageRequest(): Promise { const content = await expectSendMessageRequest(bobTestClient.httpBackend); @@ -321,8 +321,7 @@ async function recvMessage( * Send an initial sync response to the client (which just includes the member * list for our test room). * - * @param {TestClient} testClient - * @returns {Promise} which resolves when the sync has been flushed. + * @returns which resolves when the sync has been flushed. */ function firstSync(testClient: TestClient): Promise { // send a sync response including our test room. diff --git a/spec/integ/matrix-client-syncing.spec.ts b/spec/integ/matrix-client-syncing.spec.ts index dbb891449..5ddcb0aa0 100644 --- a/spec/integ/matrix-client-syncing.spec.ts +++ b/spec/integ/matrix-client-syncing.spec.ts @@ -1658,8 +1658,8 @@ describe("MatrixClient syncing", () => { /** * waits for the MatrixClient to emit one or more 'sync' events. * - * @param {Number?} numSyncs number of syncs to wait for - * @returns {Promise} promise which resolves after the sync events have happened + * @param numSyncs - number of syncs to wait for + * @returns promise which resolves after the sync events have happened */ function awaitSyncEvent(numSyncs?: number) { return utils.syncPromise(client!, numSyncs); diff --git a/spec/integ/megolm-integ.spec.ts b/spec/integ/megolm-integ.spec.ts index 89c064266..73a199936 100644 --- a/spec/integ/megolm-integ.spec.ts +++ b/spec/integ/megolm-integ.spec.ts @@ -220,8 +220,8 @@ describe("megolm", () => { * Get the device keys for testOlmAccount in a format suitable for a * response to /keys/query * - * @param {string} userId The user ID to query for - * @returns {IDownloadKeyResult} The fake query response + * @param userId - The user ID to query for + * @returns The fake query response */ function getTestKeysQueryResponse(userId: string): IDownloadKeyResult { const testE2eKeys = JSON.parse(testOlmAccount.identity_keys()); @@ -248,8 +248,8 @@ describe("megolm", () => { * Get a one-time key for testOlmAccount in a format suitable for a * response to /keys/claim - * @param {string} userId The user ID to query for - * @returns {IClaimOTKsResult} The fake key claim response + * @param userId - The user ID to query for + * @returns The fake key claim response */ function getTestKeysClaimResponse(userId: string): IClaimOTKsResult { testOlmAccount.generate_one_time_keys(1); diff --git a/spec/integ/sliding-sync.spec.ts b/spec/integ/sliding-sync.spec.ts index c2a4b8e98..d90c0236a 100644 --- a/spec/integ/sliding-sync.spec.ts +++ b/spec/integ/sliding-sync.spec.ts @@ -1446,11 +1446,11 @@ function timeout(delayMs: number, reason: string): { promise: Promise, ca /** * Listen until a callback returns data. - * @param {EventEmitter} emitter The event emitter - * @param {string} eventName The event to listen for - * @param {function} callback The callback which will be invoked when events fire. Return something truthy from this to resolve the promise. - * @param {number} timeoutMs The number of milliseconds to wait for the callback to return data. Default: 500ms. - * @returns {Promise} A promise which will be resolved when the callback returns data. If the callback throws or the timeout is reached, + * @param emitter - The event emitter + * @param eventName - The event to listen for + * @param callback - The callback which will be invoked when events fire. Return something truthy from this to resolve the promise. + * @param timeoutMs - The number of milliseconds to wait for the callback to return data. Default: 500ms. + * @returns A promise which will be resolved when the callback returns data. If the callback throws or the timeout is reached, * the promise is rejected. */ function listenUntil( diff --git a/spec/test-utils/test-utils.ts b/spec/test-utils/test-utils.ts index 3dd9c0378..814f9b15e 100644 --- a/spec/test-utils/test-utils.ts +++ b/spec/test-utils/test-utils.ts @@ -13,9 +13,9 @@ import { eventMapperFor } from "../../src/event-mapper"; /** * Return a promise that is resolved when the client next emits a * SYNCING event. - * @param {Object} client The client - * @param {Number=} count Number of syncs to wait for (default 1) - * @return {Promise} Resolves once the client has emitted a SYNCING event + * @param client - The client + * @param count - Number of syncs to wait for (default 1) + * @returns Promise which resolves once the client has emitted a SYNCING event */ export function syncPromise(client: MatrixClient, count = 1): Promise { if (count <= 0) { @@ -41,9 +41,9 @@ export function syncPromise(client: MatrixClient, count = 1): Promise { /** * Create a spy for an object and automatically spy its methods. - * @param {*} constr The class constructor (used with 'new') - * @param {string} name The name of the class - * @return {Object} An instantiated object with spied methods/properties. + * @param constr - The class constructor (used with 'new') + * @param name - The name of the class + * @returns An instantiated object with spied methods/properties. */ export function mock(constr: { new(...args: any[]): T }, name: string): T { // Based on http://eclipsesource.com/blogs/2014/03/27/mocks-in-jasmine-tests/ @@ -84,15 +84,15 @@ interface IEventOpts { let testEventIndex = 1; // counter for events, easier for comparison of randomly generated events /** * Create an Event. - * @param {Object} opts Values for the event. - * @param {string} opts.type The event.type - * @param {string} opts.room The event.room_id - * @param {string} opts.sender The event.sender - * @param {string} opts.skey Optional. The state key (auto inserts empty string) - * @param {Object} opts.content The event.content - * @param {boolean} opts.event True to make a MatrixEvent. - * @param {MatrixClient} client If passed along with opts.event=true will be used to set up re-emitters. - * @return {Object} a JSON object representing this event. + * @param opts - Values for the event. + * @param opts.type - The event.type + * @param opts.room - The event.room_id + * @param opts.sender - The event.sender + * @param opts.skey - Optional. The state key (auto inserts empty string) + * @param opts.content - The event.content + * @param opts.event - True to make a MatrixEvent. + * @param client - If passed along with opts.event=true will be used to set up re-emitters. + * @returns a JSON object representing this event. */ export function mkEvent(opts: IEventOpts & { event: true }, client?: MatrixClient): MatrixEvent; export function mkEvent(opts: IEventOpts & { event?: false }, client?: MatrixClient): Partial; @@ -160,8 +160,8 @@ interface IPresenceOpts { /** * Create an m.presence event. - * @param {Object} opts Values for the presence. - * @return {Object|MatrixEvent} The event + * @param opts - Values for the presence. + * @returns The event */ export function mkPresence(opts: IPresenceOpts & { event: true }): MatrixEvent; export function mkPresence(opts: IPresenceOpts & { event?: false }): Partial; @@ -193,16 +193,16 @@ interface IMembershipOpts { /** * Create an m.room.member event. - * @param {Object} opts Values for the membership. - * @param {string} opts.room The room ID for the event. - * @param {string} opts.mship The content.membership for the event. - * @param {string} opts.sender The sender user ID for the event. - * @param {string} opts.skey The target user ID for the event if applicable + * @param opts - Values for the membership. + * @param opts.room - The room ID for the event. + * @param opts.mship - The content.membership for the event. + * @param opts.sender - The sender user ID for the event. + * @param opts.skey - The target user ID for the event if applicable * e.g. for invites/bans. - * @param {string} opts.name The content.displayname for the event. - * @param {string} opts.url The content.avatar_url for the event. - * @param {boolean} opts.event True to make a MatrixEvent. - * @return {Object|MatrixEvent} The event + * @param opts.name - The content.displayname for the event. + * @param opts.url - The content.avatar_url for the event. + * @param opts.event - True to make a MatrixEvent. + * @returns The event */ export function mkMembership(opts: IMembershipOpts & { event: true }): MatrixEvent; export function mkMembership(opts: IMembershipOpts & { event?: false }): Partial; @@ -250,13 +250,13 @@ export interface IMessageOpts { /** * Create an m.room.message event. - * @param {Object} opts Values for the message - * @param {string} opts.room The room ID for the event. - * @param {string} opts.user The user ID for the event. - * @param {string} opts.msg Optional. The content.body for the event. - * @param {boolean} opts.event True to make a MatrixEvent. - * @param {MatrixClient} client If passed along with opts.event=true will be used to set up re-emitters. - * @return {Object|MatrixEvent} The event + * @param opts - Values for the message + * @param opts.room - The room ID for the event. + * @param opts.user - The user ID for the event. + * @param opts.msg - Optional. The content.body for the event. + * @param opts.event - True to make a MatrixEvent. + * @param client - If passed along with opts.event=true will be used to set up re-emitters. + * @returns The event */ export function mkMessage(opts: IMessageOpts & { event: true }, client?: MatrixClient): MatrixEvent; export function mkMessage(opts: IMessageOpts & { event?: false }, client?: MatrixClient): Partial; @@ -290,14 +290,14 @@ interface IReplyMessageOpts extends IMessageOpts { /** * Create a reply message. * - * @param {Object} opts Values for the message - * @param {string} opts.room The room ID for the event. - * @param {string} opts.user The user ID for the event. - * @param {string} opts.msg Optional. The content.body for the event. - * @param {MatrixEvent} opts.replyToMessage The replied message - * @param {boolean} opts.event True to make a MatrixEvent. - * @param {MatrixClient} client If passed along with opts.event=true will be used to set up re-emitters. - * @return {Object|MatrixEvent} The event + * @param opts - Values for the message + * @param opts.room - The room ID for the event. + * @param opts.user - The user ID for the event. + * @param opts.msg - Optional. The content.body for the event. + * @param opts.replyToMessage - The replied message + * @param opts.event - True to make a MatrixEvent. + * @param client - If passed along with opts.event=true will be used to set up re-emitters. + * @returns The event */ export function mkReplyMessage(opts: IReplyMessageOpts & { event: true }, client?: MatrixClient): MatrixEvent; export function mkReplyMessage(opts: IReplyMessageOpts & { event?: false }, client?: MatrixClient): Partial; @@ -329,8 +329,6 @@ export function mkReplyMessage( /** * A mock implementation of webstorage - * - * @constructor */ export class MockStorageApi implements Storage { private data: Record = {}; @@ -363,8 +361,7 @@ export class MockStorageApi implements Storage { /** * If an event is being decrypted, wait for it to finish being decrypted. * - * @param {MatrixEvent} event - * @returns {Promise} promise which resolves (to `event`) when the event has been decrypted + * @returns promise which resolves (to `event`) when the event has been decrypted */ export async function awaitDecryption( event: MatrixEvent, { waitOnDecryptionFailure = false } = {}, diff --git a/spec/unit/room.spec.ts b/spec/unit/room.spec.ts index c820f37a0..ad74a2853 100644 --- a/spec/unit/room.spec.ts +++ b/spec/unit/room.spec.ts @@ -16,7 +16,6 @@ limitations under the License. /** * This is an internal module. See {@link MatrixClient} for the public class. - * @module client */ import { mocked } from "jest-mock"; diff --git a/src/@types/IIdentityServerProvider.ts b/src/@types/IIdentityServerProvider.ts index 7b905e316..05793d53a 100644 --- a/src/@types/IIdentityServerProvider.ts +++ b/src/@types/IIdentityServerProvider.ts @@ -18,7 +18,7 @@ export interface IIdentityServerProvider { /** * Gets an access token for use against the identity server, * for the associated client. - * @returns {Promise} Resolves to the access token. + * @returns Promise which resolves to the access token. */ getAccessToken(): Promise; } diff --git a/src/@types/beacon.ts b/src/@types/beacon.ts index 6da17061e..ea8a9c8eb 100644 --- a/src/@types/beacon.ts +++ b/src/@types/beacon.ts @@ -35,7 +35,8 @@ import { MAssetEvent, MLocationEvent, MTimestampEvent } from "./location"; * To achieve an arbitrary number of only owner-writable state events * we introduce a variable suffix to the event type * - * Eg + * @example + * ``` * { * "type": "m.beacon_info.@matthew:matrix.org.1", * "state_key": "@matthew:matrix.org", @@ -58,6 +59,7 @@ import { MAssetEvent, MLocationEvent, MTimestampEvent } from "./location"; * // more content as described below * } * } + * ``` */ /** @@ -78,20 +80,23 @@ export type MBeaconInfoContent = { /** * m.beacon_info Event example from the spec * https://github.com/matrix-org/matrix-spec-proposals/pull/3672 + * @example + * ``` * { - "type": "m.beacon_info", - "state_key": "@matthew:matrix.org", - "content": { - "m.beacon_info": { - "description": "The Matthew Tracker", // same as an `m.location` description - "timeout": 86400000, // how long from the last event until we consider the beacon inactive in milliseconds - }, - "m.ts": 1436829458432, // creation timestamp of the beacon on the client - "m.asset": { - "type": "m.self" // the type of asset being tracked as per MSC3488 - } - } -} + * "type": "m.beacon_info", + * "state_key": "@matthew:matrix.org", + * "content": { + * "m.beacon_info": { + * "description": "The Matthew Tracker", // same as an `m.location` description + * "timeout": 86400000, // how long from the last event until we consider the beacon inactive in milliseconds + * }, + * "m.ts": 1436829458432, // creation timestamp of the beacon on the client + * "m.asset": { + * "type": "m.self" // the type of asset being tracked as per MSC3488 + * } + * } + * } + * ``` */ /** @@ -107,22 +112,24 @@ export type MBeaconInfoEventContent = & /** * m.beacon event example * https://github.com/matrix-org/matrix-spec-proposals/pull/3672 - * + * @example + * ``` * { - "type": "m.beacon", - "sender": "@matthew:matrix.org", - "content": { - "m.relates_to": { // from MSC2674: https://github.com/matrix-org/matrix-doc/pull/2674 - "rel_type": "m.reference", // from MSC3267: https://github.com/matrix-org/matrix-doc/pull/3267 - "event_id": "$beacon_info" - }, - "m.location": { - "uri": "geo:51.5008,0.1247;u=35", - "description": "Arbitrary beacon information" - }, - "m.ts": 1636829458432, - } -} + * "type": "m.beacon", + * "sender": "@matthew:matrix.org", + * "content": { + * "m.relates_to": { // from MSC2674: https://github.com/matrix-org/matrix-doc/pull/2674 + * "rel_type": "m.reference", // from MSC3267: https://github.com/matrix-org/matrix-doc/pull/3267 + * "event_id": "$beacon_info" + * }, + * "m.location": { + * "uri": "geo:51.5008,0.1247;u=35", + * "description": "Arbitrary beacon information" + * }, + * "m.ts": 1636829458432, + * } + * } + * ``` */ /** diff --git a/src/@types/event.ts b/src/@types/event.ts index ab07c01d7..d8bb4cc30 100644 --- a/src/@types/event.ts +++ b/src/@types/event.ts @@ -171,17 +171,21 @@ export const UNSTABLE_MSC2716_MARKER = new UnstableValue("m.room.marker", "org.m * eventual removal. * * Schema (TypeScript): + * ``` * { * service_members?: string[] * } + * ``` * - * Example: + * @example + * ``` * { * "service_members": [ * "@helperbot:localhost", * "@reminderbot:alice.tdl" * ] * } + * ``` */ export const UNSTABLE_ELEMENT_FUNCTIONAL_USERS = new UnstableValue( "io.element.functional_members", diff --git a/src/@types/requests.ts b/src/@types/requests.ts index 936ace5b4..75296940a 100644 --- a/src/@types/requests.ts +++ b/src/@types/requests.ts @@ -54,17 +54,31 @@ export interface ISendEventResponse { } export interface IPresenceOpts { + // One of "online", "offline" or "unavailable" presence: "online" | "offline" | "unavailable"; + // The status message to attach. status_msg?: string; } export interface IPaginateOpts { + // true to fill backwards, false to go forwards backwards?: boolean; + // number of events to request limit?: number; } export interface IGuestAccessOpts { + /** + * True to allow guests to join this room. This + * implicitly gives guests write access. If false or not given, guests are + * explicitly forbidden from joining the room. + */ allowJoin: boolean; + /** + * True to set history visibility to + * be world_readable. This gives guests read access *from this point forward*. + * If false or not given, history visibility is not modified. + */ allowRead: boolean; } @@ -74,7 +88,9 @@ export interface ISearchOpts { } export interface IEventSearchOpts { + // a JSON filter object to pass in the request filter?: IRoomEventFilter; + // the term to search for term: string; } @@ -92,9 +108,13 @@ export interface ICreateRoomStateEvent { } export interface ICreateRoomOpts { + // The alias localpart to assign to this room. room_alias_name?: string; + // Either 'public' or 'private'. visibility?: Visibility; + // The name to give this room. name?: string; + // The topic to give this room. topic?: string; preset?: Preset; power_level_content_override?: { @@ -111,6 +131,7 @@ export interface ICreateRoomOpts { }; creation_content?: object; initial_state?: ICreateRoomStateEvent[]; + // A list of user IDs to invite to this room. invite?: string[]; invite_3pid?: IInvite3PID[]; is_direct?: boolean; @@ -121,7 +142,10 @@ export interface IRoomDirectoryOptions { server?: string; limit?: number; since?: string; + + // Filter parameters filter?: { + // String to search for generic_search_term?: string; room_types?: Array; }; diff --git a/src/@types/topic.ts b/src/@types/topic.ts index 0d2708b2e..5b66e07c4 100644 --- a/src/@types/topic.ts +++ b/src/@types/topic.ts @@ -21,10 +21,9 @@ import { UnstableValue } from "../NamespacedValue"; /** * Extensible topic event type based on MSC3765 * https://github.com/matrix-org/matrix-spec-proposals/pull/3765 - */ - -/** - * Eg + * + * @example + * ``` * { * "type": "m.room.topic, * "state_key": "", @@ -39,6 +38,7 @@ import { UnstableValue } from "../NamespacedValue"; * }], * } * } + * ``` */ /** diff --git a/src/autodiscovery.ts b/src/autodiscovery.ts index fe2b6e383..35728d1e2 100644 --- a/src/autodiscovery.ts +++ b/src/autodiscovery.ts @@ -15,8 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/** @module auto-discovery */ - import { IClientWellKnown, IWellKnownConfig } from "./client"; import { logger } from './logger'; import { MatrixError, Method, timeoutSignal } from "./http-api"; @@ -87,8 +85,6 @@ export class AutoDiscovery { /** * The auto discovery failed. The client is expected to communicate * the error to the user and refuse logging in. - * @return {string} - * @constructor */ public static readonly FAIL_ERROR = AutoDiscoveryAction.FAIL_ERROR; @@ -98,8 +94,6 @@ export class AutoDiscovery { * action it would for PROMPT while also warning the user about * what went wrong. The client may also treat this the same as * a FAIL_ERROR state. - * @return {string} - * @constructor */ public static readonly FAIL_PROMPT = AutoDiscoveryAction.FAIL_PROMPT; @@ -107,15 +101,11 @@ export class AutoDiscovery { * The auto discovery didn't fail but did not find anything of * interest. The client is expected to prompt the user for more * information, or fail if it prefers. - * @return {string} - * @constructor */ public static readonly PROMPT = AutoDiscoveryAction.PROMPT; /** * The auto discovery was successful. - * @return {string} - * @constructor */ public static readonly SUCCESS = AutoDiscoveryAction.SUCCESS; @@ -125,9 +115,9 @@ export class AutoDiscovery { * and identity server URL the client would want. Additional details * may also be included, and will be transparently brought into the * response object unaltered. - * @param {object} wellknown The configuration object itself, as returned + * @param wellknown - The configuration object itself, as returned * by the .well-known auto-discovery endpoint. - * @return {Promise} Resolves to the verified + * @returns Promise which resolves to the verified * configuration, which may include error states. Rejects on unexpected * failure, not when verification fails. */ @@ -284,9 +274,9 @@ export class AutoDiscovery { * and identity server URL the client would want. Additional details * may also be discovered, and will be transparently included in the * response object unaltered. - * @param {string} domain The homeserver domain to perform discovery + * @param domain - The homeserver domain to perform discovery * on. For example, "matrix.org". - * @return {Promise} Resolves to the discovered + * @returns Promise which resolves to the discovered * configuration, which may include error states. Rejects on unexpected * failure, not when discovery fails. */ @@ -354,8 +344,8 @@ export class AutoDiscovery { * Gets the raw discovery client configuration for the given domain name. * Should only be used if there's no validation to be done on the resulting * object, otherwise use findClientConfig(). - * @param {string} domain The domain to get the client config for. - * @returns {Promise} Resolves to the domain's client config. Can + * @param domain - The domain to get the client config for. + * @returns Promise which resolves to the domain's client config. Can * be an empty object. */ public static async getRawClientConfig(domain?: string): Promise { @@ -374,9 +364,9 @@ export class AutoDiscovery { * Sanitizes a given URL to ensure it is either an HTTP or HTTP URL and * is suitable for the requirements laid out by .well-known auto discovery. * If valid, the URL will also be stripped of any trailing slashes. - * @param {string} url The potentially invalid URL to sanitize. - * @return {string|boolean} The sanitized URL or a falsey value if the URL is invalid. - * @private + * @param url - The potentially invalid URL to sanitize. + * @returns The sanitized URL or a falsey value if the URL is invalid. + * @internal */ private static sanitizeWellKnownUrl(url?: string | null): string | false { if (!url) return false; @@ -430,9 +420,9 @@ export class AutoDiscovery { * action: One of SUCCESS, IGNORE, or FAIL_PROMPT. * reason: Relatively human-readable description of what went wrong. * error: The actual Error, if one exists. - * @param {string} url The URL to fetch a JSON object from. - * @return {Promise} Resolves to the returned state. - * @private + * @param url - The URL to fetch a JSON object from. + * @returns Promise which resolves to the returned state. + * @internal */ private static async fetchWellKnownObject(url: string): Promise { let response: Response; diff --git a/src/client.ts b/src/client.ts index 6fb74ca17..fba259a56 100644 --- a/src/client.ts +++ b/src/client.ts @@ -16,7 +16,6 @@ limitations under the License. /** * This is an internal module. See {@link MatrixClient} for the public class. - * @module client */ import { EmoteEvent, IPartialEvent, MessageEvent, NoticeEvent, Optional } from "matrix-events-sdk"; @@ -258,7 +257,10 @@ export interface ICreateClientOpts { /** * A store to be used for end-to-end crypto session data. If not specified, * end-to-end crypto will be disabled. The `createClient` helper will create - * a default store if needed. + * a default store if needed. Calls the factory supplied to + * {@link setCryptoStoreFactory} if unspecified; or if no factory has been + * specified, uses a default implementation (indexeddb in the browser, + * in-memory otherwise). */ cryptoStore?: CryptoStore; @@ -266,7 +268,7 @@ export interface ICreateClientOpts { * The scheduler to use. If not * specified, this client will not retry requests on failure. This client * will supply its own processing function to - * {@link module:scheduler~MatrixScheduler#setProcessFunction}. + * {@link MatrixScheduler#setProcessFunction}. */ scheduler?: MatrixScheduler; @@ -311,8 +313,8 @@ export interface ICreateClientOpts { /** * Set to true to enable - * improved timeline support ({@link module:client~MatrixClient#getEventTimeline getEventTimeline}). It is - * disabled by default for compatibility with older clients - in particular to + * improved timeline support, see {@link MatrixClient#getEventTimeline}. + * It is disabled by default for compatibility with older clients - in particular to * maintain support for back-paginating the live timeline after a '/sync' * result with a gap. */ @@ -321,7 +323,7 @@ export interface ICreateClientOpts { /** * Extra query parameters to append * to all requests with this client. Useful for application services which require - * ?user_id=. + * `?user_id=`. */ queryParams?: Record; @@ -395,12 +397,12 @@ export enum PendingEventOrdering { export interface IStartClientOpts { /** - * The event limit= to apply to initial sync. Default: 8. + * The event `limit=` to apply to initial sync. Default: 8. */ initialSyncLimit?: number; /** - * True to put archived=true on the /initialSync request. Default: false. + * True to put `archived=true on the /initialSync` request. Default: false. */ includeArchivedRooms?: boolean; @@ -411,8 +413,8 @@ export interface IStartClientOpts { /** * Controls where pending messages appear in a room's timeline. If "chronological", messages will - * appear in the timeline when the call to sendEvent was made. If "detached", - * pending messages will appear in a separate list, accessbile via {@link module:models/room#getPendingEvents}. + * appear in the timeline when the call to `sendEvent` was made. If "detached", + * pending messages will appear in a separate list, accessbile via {@link Room#getPendingEvents}. * Default: "chronological". */ pendingEventOrdering?: PendingEventOrdering; @@ -456,7 +458,14 @@ export interface IStartClientOpts { } export interface IStoredClientOpts extends IStartClientOpts { + // Crypto manager crypto?: Crypto; + /** + * A function which is called + * with a room ID and returns a boolean. It should return 'true' if the SDK can + * SAFELY remove events from this room. It may not be safe to remove events if + * there are other references to the timelines for this room. + */ canResetEntireTimeline: ResetTimelineCallback; } @@ -916,13 +925,184 @@ export type EmittedEvents = ClientEvent | BeaconEvent; export type ClientEventHandlerMap = { + /** + * Fires whenever the SDK's syncing state is updated. The state can be one of: + *
    + * + *
  • PREPARED: The client has synced with the server at least once and is + * ready for methods to be called on it. This will be immediately followed by + * a state of SYNCING. This is the equivalent of "syncComplete" in the + * previous API.
  • + * + *
  • CATCHUP: The client has detected the connection to the server might be + * available again and will now try to do a sync again. As this sync might take + * a long time (depending how long ago was last synced, and general server + * performance) the client is put in this mode so the UI can reflect trying + * to catch up with the server after losing connection.
  • + * + *
  • SYNCING : The client is currently polling for new events from the server. + * This will be called after processing latest events from a sync.
  • + * + *
  • ERROR : The client has had a problem syncing with the server. If this is + * called before PREPARED then there was a problem performing the initial + * sync. If this is called after PREPARED then there was a problem polling + * the server for updates. This may be called multiple times even if the state is + * already ERROR. This is the equivalent of "syncError" in the previous + * API.
  • + * + *
  • RECONNECTING: The sync connection has dropped, but not (yet) in a way that + * should be considered erroneous. + *
  • + * + *
  • STOPPED: The client has stopped syncing with server due to stopClient + * being called. + *
  • + *
+ * State transition diagram: + * ``` + * +---->STOPPED + * | + * +----->PREPARED -------> SYNCING <--+ + * | ^ | ^ | + * | CATCHUP ----------+ | | | + * | ^ V | | + * null ------+ | +------- RECONNECTING | + * | V V | + * +------->ERROR ---------------------+ + * + * NB: 'null' will never be emitted by this event. + * + * ``` + * Transitions: + *
    + * + *
  • `null -> PREPARED` : Occurs when the initial sync is completed + * first time. This involves setting up filters and obtaining push rules. + * + *
  • `null -> ERROR` : Occurs when the initial sync failed first time. + * + *
  • `ERROR -> PREPARED` : Occurs when the initial sync succeeds + * after previously failing. + * + *
  • `PREPARED -> SYNCING` : Occurs immediately after transitioning + * to PREPARED. Starts listening for live updates rather than catching up. + * + *
  • `SYNCING -> RECONNECTING` : Occurs when the live update fails. + * + *
  • `RECONNECTING -> RECONNECTING` : Can occur if the update calls + * continue to fail, but the keepalive calls (to /versions) succeed. + * + *
  • `RECONNECTING -> ERROR` : Occurs when the keepalive call also fails + * + *
  • `ERROR -> SYNCING` : Occurs when the client has performed a + * live update after having previously failed. + * + *
  • `ERROR -> ERROR` : Occurs when the client has failed to keepalive + * for a second time or more.
  • + * + *
  • `SYNCING -> SYNCING` : Occurs when the client has performed a live + * update. This is called after processing.
  • + * + *
  • `* -> STOPPED` : Occurs once the client has stopped syncing or + * trying to sync after stopClient has been called.
  • + *
+ * + * @param state - An enum representing the syncing state. One of "PREPARED", + * "SYNCING", "ERROR", "STOPPED". + * + * @param prevState - An enum representing the previous syncing state. + * One of "PREPARED", "SYNCING", "ERROR", "STOPPED" or null. + * + * @param data - Data about this transition. + * + * @example + * ``` + * matrixClient.on("sync", function(state, prevState, data) { + * switch (state) { + * case "ERROR": + * // update UI to say "Connection Lost" + * break; + * case "SYNCING": + * // update UI to remove any "Connection Lost" message + * break; + * case "PREPARED": + * // the client instance is ready to be queried. + * var rooms = matrixClient.getRooms(); + * break; + * } + * }); + * ``` + */ [ClientEvent.Sync]: (state: SyncState, lastState: SyncState | null, data?: ISyncStateData) => void; + /** + * Fires whenever the SDK receives a new event. + *

+ * This is only fired for live events received via /sync - it is not fired for + * events received over context, search, or pagination APIs. + * + * @param event - The matrix event which caused this event to fire. + * @example + * ``` + * matrixClient.on("event", function(event){ + * var sender = event.getSender(); + * }); + * ``` + */ [ClientEvent.Event]: (event: MatrixEvent) => void; + /** + * Fires whenever the SDK receives a new to-device event. + * @param event - The matrix event which caused this event to fire. + * @example + * ``` + * matrixClient.on("toDeviceEvent", function(event){ + * var sender = event.getSender(); + * }); + * ``` + */ [ClientEvent.ToDeviceEvent]: (event: MatrixEvent) => void; + /** + * Fires whenever new user-scoped account_data is added. + * @param event - The event describing the account_data just added + * @param event - The previous account data, if known. + * @example + * ``` + * matrixClient.on("accountData", function(event, oldEvent){ + * myAccountData[event.type] = event.content; + * }); + * ``` + */ [ClientEvent.AccountData]: (event: MatrixEvent, lastEvent?: MatrixEvent) => void; + /** + * Fires whenever a new Room is added. This will fire when you are invited to a + * room, as well as when you join a room. This event is experimental and + * may change. + * @param room - The newly created, fully populated room. + * @example + * ``` + * matrixClient.on("Room", function(room){ + * var roomId = room.roomId; + * }); + * ``` + */ [ClientEvent.Room]: (room: Room) => void; + /** + * Fires whenever a Room is removed. This will fire when you forget a room. + * This event is experimental and may change. + * @param roomId - The deleted room ID. + * @example + * ``` + * matrixClient.on("deleteRoom", function(roomId){ + * // update UI from getRooms() + * }); + * ``` + */ [ClientEvent.DeleteRoom]: (roomId: string) => void; [ClientEvent.SyncUnexpectedError]: (error: Error) => void; + /** + * Fires when the client .well-known info is fetched. + * + * @param data - The JSON object returned by the server + */ [ClientEvent.ClientWellKnown]: (data: IClientWellKnown) => void; [ClientEvent.ReceivedVoipEvent]: (event: MatrixEvent) => void; [ClientEvent.TurnServers]: (servers: ITurnServer[]) => void; @@ -1185,10 +1365,10 @@ export class MatrixClient extends TypedEventEmitter { if (this.clientRunning) { @@ -1302,9 +1482,9 @@ export class MatrixClient extends TypedEventEmitter} Resolves to undefined if a device could not be dehydrated, or + * @returns Promise which resolves to undefined if a device could not be dehydrated, or * to the new device ID if the dehydration was successful. - * @return {module:http-api.MatrixError} Rejects: with an error response. + * @returns Rejects: with an error response. */ public async rehydrateDevice(): Promise { if (this.crypto) { @@ -1379,7 +1559,7 @@ export class MatrixClient extends TypedEventEmitter { try { @@ -1401,12 +1581,12 @@ export class MatrixClient extends TypedEventEmitter} the device id of the newly created dehydrated device + * @returns the device id of the newly created dehydrated device */ public async createDehydratedDevice( key: Uint8Array, @@ -1458,7 +1638,7 @@ export class MatrixClient extends TypedEventEmitter { if (this.clientRunning) { @@ -1477,7 +1657,7 @@ export class MatrixClient extends TypedEventEmitterThis method is experimental * and may change without warning. - * @param {boolean} guest True if this is a guest account. + * @param guest - True if this is a guest account. */ public setGuest(guest: boolean): void { // EXPERIMENTAL: @@ -1697,7 +1874,7 @@ export class MatrixClient extends TypedEventEmitterexplicitly attempts to retry their lost connection. * Will also retry any outbound to-device messages currently in the queue to be sent * (retries of regular outgoing events are handled separately, per-event). - * @return {boolean} True if this resulted in a request being retried. + * @returns True if this resulted in a request being retried. */ public retryImmediately(): boolean { // don't await for this promise: we just want to kick it off @@ -1719,7 +1896,7 @@ export class MatrixClient extends TypedEventEmitter { const now = new Date().getTime(); @@ -1870,7 +2046,7 @@ export class MatrixClient extends TypedEventEmitterdeviceId->{@link - * module:crypto~DeviceInfo|DeviceInfo}. + * @returns A promise which resolves to a map userId-\>deviceId-\>{@link DeviceInfo} */ public downloadKeys( userIds: string[], @@ -1925,9 +2100,9 @@ export class MatrixClient extends TypedEventEmitter { const prom = this.setDeviceVerification(userId, deviceId, verified, null, null); @@ -1980,16 +2156,17 @@ export class MatrixClient extends TypedEventEmitter { return this.setDeviceVerification(userId, deviceId, null, blocked, null); @@ -1998,16 +2175,17 @@ export class MatrixClient extends TypedEventEmitter { return this.setDeviceVerification(userId, deviceId, null, null, known); @@ -2029,10 +2207,10 @@ export class MatrixClient extends TypedEventEmitter} resolves to a VerificationRequest + * @returns resolves to a VerificationRequest * when the request has been sent to the other party. */ public requestVerificationDM(userId: string, roomId: string): Promise { @@ -2045,9 +2223,9 @@ export class MatrixClient extends TypedEventEmitter} resolves to a VerificationRequest + * @returns resolves to a VerificationRequest * when the request has been sent to the other party. */ public requestVerification(userId: string, devices?: string[]): Promise { @@ -2090,11 +2268,11 @@ export class MatrixClient extends TypedEventEmitter { @@ -2116,7 +2294,7 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2263,9 +2438,9 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2326,15 +2501,6 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2350,7 +2516,7 @@ export class MatrixClient extends TypedEventEmitter} Resolves to the number of sessions requiring backup + * @returns Promise which resolves to the number of sessions requiring backup */ public countSessionsNeedingBackup(): Promise { if (!this.crypto) { @@ -2385,8 +2551,8 @@ export class MatrixClient extends TypedEventEmitter} Object with public key metadata, encoded private + * @returns Object with public key metadata, encoded private * recovery key which should be disposed of after displaying to the user, * and raw private key to avoid round tripping if needed. */ @@ -2427,7 +2593,7 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2449,7 +2615,6 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2463,14 +2628,14 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2504,9 +2669,9 @@ export class MatrixClient extends TypedEventEmitter { @@ -2521,9 +2686,9 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2537,8 +2702,8 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2585,7 +2750,7 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2601,9 +2766,9 @@ export class MatrixClient extends TypedEventEmitter} + * @param event - event to be checked */ public async getEventSenderDeviceInfo(event: MatrixEvent): Promise { if (!this.crypto) { @@ -2629,10 +2792,10 @@ export class MatrixClient extends TypedEventEmitter { const device = await this.getEventSenderDeviceInfo(event); @@ -2644,9 +2807,9 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2671,9 +2834,9 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2685,9 +2848,9 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2698,8 +2861,8 @@ export class MatrixClient extends TypedEventEmitter} Promise which + * @param payload - fields to include in the encrypted payload + * + * @returns Promise which * resolves once the message has been encrypted and sent to the given - * userDeviceMap, and returns the { contentMap, deviceInfoByDeviceId } + * userDeviceMap, and returns the `{ contentMap, deviceInfoByDeviceId }` * of the successfully sent messages. */ public encryptAndSendToDevices( @@ -2750,7 +2912,7 @@ export class MatrixClient extends TypedEventEmitter { @@ -2779,12 +2941,9 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2797,7 +2956,7 @@ export class MatrixClient extends TypedEventEmitter} Information object from API or null + * @returns Information object from API or null */ public async getKeyBackupVersion(): Promise { let res: IKeyBackupInfo; @@ -2832,14 +2991,7 @@ export class MatrixClient extends TypedEventEmitter { if (!this.crypto) { @@ -2849,7 +3001,7 @@ export class MatrixClient extends TypedEventEmitter} Resolves when complete. + * @param info - Backup information object as returned by getKeyBackupVersion + * @returns Promise which resolves when complete. */ public enableKeyBackup(info: IKeyBackupInfo): Promise { if (!this.crypto) { @@ -2890,17 +3042,13 @@ export class MatrixClient extends TypedEventEmitter} Object that can be passed to createKeyBackupVersion and + * @returns Object that can be passed to createKeyBackupVersion and * additionally has a 'recovery_key' member with the user-facing recovery key string. */ - // TODO: Verify types public async prepareKeyBackupVersion( password?: string | Uint8Array | null, opts: IKeyBackupPrepareOpts = { secureSecretStorage: false }, @@ -2929,7 +3077,7 @@ export class MatrixClient extends TypedEventEmitter} map of key name to key info the secret is + * @returns map of key name to key info the secret is * encrypted with, or null if it is not present or not encrypted with a * trusted key */ @@ -2941,8 +3089,8 @@ export class MatrixClient extends TypedEventEmitter} Object with 'version' param indicating the version created + * @param info - Info object from prepareKeyBackupVersion + * @returns Object with 'version' param indicating the version created */ public async createKeyBackupVersion(info: IKeyBackupInfo): Promise { if (!this.crypto) { @@ -3036,11 +3184,11 @@ export class MatrixClient extends TypedEventEmitter} Resolves to the number of sessions requiring a backup. + * @returns Promise which resolves to the number of sessions requiring a backup. */ public flagAllGroupSessionsForBackup(): Promise { if (!this.crypto) { @@ -3118,9 +3266,9 @@ export class MatrixClient extends TypedEventEmitter} key backup key + * @param password - Passphrase + * @param backupInfo - Backup metadata from `checkKeyBackup` + * @returns key backup key */ public keyBackupKeyFromPassword(password: string, backupInfo: IKeyBackupInfo): Promise { return keyFromAuthData(backupInfo.auth_data, password); @@ -3132,8 +3280,8 @@ export class MatrixClient extends TypedEventEmitter} Status of restoration with `total` and `imported` + * @param backupInfo - Backup metadata from `checkKeyBackup` + * @param opts - Optional params such as callbacks + * @returns Status of restoration with `total` and `imported` * key counts. */ public async restoreKeyBackupWithPassword( @@ -3188,13 +3336,13 @@ export class MatrixClient extends TypedEventEmitter} Status of restoration with `total` and `imported` + * @param opts - Optional params such as callbacks + * @returns Status of restoration with `total` and `imported` * key counts. */ public async restoreKeyBackupWithSecretStorage( @@ -3223,15 +3371,15 @@ export class MatrixClient extends TypedEventEmitter} Status of restoration with `total` and `imported` + * @returns Status of restoration with `total` and `imported` * key counts. */ public restoreKeyBackupWithRecoveryKey( @@ -3435,8 +3583,8 @@ export class MatrixClient extends TypedEventEmitter { @@ -3468,7 +3616,7 @@ export class MatrixClient extends TypedEventEmitter { return this.http.authedRequest( @@ -3483,8 +3631,8 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/user/$userId/account_data/$type", { @@ -3570,8 +3718,8 @@ export class MatrixClient extends TypedEventEmitter(eventType: string): Promise { if (this.isInitialSyncComplete()) { @@ -3611,7 +3759,7 @@ export class MatrixClient extends TypedEventEmitter { const content = { ignored_users: {} as Record }; @@ -3635,8 +3783,8 @@ export class MatrixClient extends TypedEventEmitterreturned Room object will have no current state. - * Default: true. - * @param {boolean} opts.inviteSignUrl If the caller has a keypair 3pid invite, the signing URL is passed in this parameter. - * @param {string[]} opts.viaServers The server names to try and join through in addition to those that are automatically chosen. - * @return {Promise} Resolves: Room object. - * @return {module:http-api.MatrixError} Rejects: with an error response. + * @param roomIdOrAlias - The room ID or room alias to join. + * @param opts - Options when joining the room. + * @returns Promise which resolves: Room object. + * @returns Rejects: with an error response. */ public async joinRoom(roomIdOrAlias: string, opts: IJoinRoomOpts = {}): Promise { if (opts.syncRoom === undefined) { @@ -3702,11 +3845,11 @@ export class MatrixClient extends TypedEventEmitter { // also kick the to-device queue to retry @@ -3719,7 +3862,7 @@ export class MatrixClient extends TypedEventEmitter { return this.sendStateEvent(roomId, EventType.RoomName, { name: name }); } /** - * @param {string} roomId - * @param {string} topic - * @param {string} htmlTopic Optional. - * @return {Promise} Resolves: TODO - * @return {module:http-api.MatrixError} Rejects: with an error response. + * @param htmlTopic - Optional. + * @returns Promise which resolves: TODO + * @returns Rejects: with an error response. */ public setRoomTopic( roomId: string, @@ -3768,9 +3907,8 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/user/$userId/rooms/$roomId/tags", { @@ -3781,11 +3919,10 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/user/$userId/rooms/$roomId/tags/$tag", { @@ -3797,10 +3934,9 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/user/$userId/rooms/$roomId/tags/$tag", { @@ -3812,11 +3948,10 @@ export class MatrixClient extends TypedEventEmitter { let cancelled = false; @@ -4161,9 +4276,9 @@ export class MatrixClient extends TypedEventEmitter { @@ -4792,11 +4872,8 @@ export class MatrixClient extends TypedEventEmitter { if (this.isGuest()) { @@ -4822,12 +4899,12 @@ export class MatrixClient extends TypedEventEmitter { return this.membershipChange(roomId, userId, "invite", reason); @@ -4907,10 +4982,10 @@ export class MatrixClient extends TypedEventEmitter { return this.inviteByThreePid(roomId, "email", email); @@ -4918,11 +4993,11 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri( @@ -4957,9 +5032,8 @@ export class MatrixClient extends TypedEventEmitter { return this.membershipChange(roomId, undefined, "leave"); @@ -4970,10 +5044,10 @@ export class MatrixClient extends TypedEventEmitter { return this.membershipChange(roomId, userId, "ban", reason); } /** - * @param {string} roomId - * @param {boolean} deleteRoom True to delete the room from the store on success. + * @param deleteRoom - True to delete the room from the store on success. * Default: true. - * @return {Promise} Resolves: {} an empty object. - * @return {module:http-api.MatrixError} Rejects: with an error response. + * @returns Promise which resolves: `{}` an empty object. + * @returns Rejects: with an error response. */ public forget(roomId: string, deleteRoom = true): Promise<{}> { const promise = this.membershipChange(roomId, undefined, "forget"); @@ -5043,10 +5114,8 @@ export class MatrixClient extends TypedEventEmitter { // unbanning != set their state to leave: this used to be @@ -5064,11 +5133,9 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/rooms/$roomId/kick", { @@ -5102,10 +5169,10 @@ export class MatrixClient extends TypedEventEmitter; @@ -5132,9 +5199,8 @@ export class MatrixClient extends TypedEventEmitter { const prom = await this.setProfileInfo("displayname", { displayname: name }); @@ -5148,9 +5214,8 @@ export class MatrixClient extends TypedEventEmitter { const prom = await this.setProfileInfo("avatar_url", { avatar_url: url }); @@ -5166,15 +5231,15 @@ export class MatrixClient extends TypedEventEmitterThis method is experimental and * may change. - * @param {string} mxcUrl The MXC URL - * @param {Number} width The desired width of the thumbnail. - * @param {Number} height The desired height of the thumbnail. - * @param {string} resizeMethod The thumbnail resize method to use, either + * @param mxcUrl - The MXC URL + * @param width - The desired width of the thumbnail. + * @param height - The desired height of the thumbnail. + * @param resizeMethod - The thumbnail resize method to use, either * "crop" or "scale". - * @param {Boolean} allowDirectLinks If true, return any non-mxc URLs + * @param allowDirectLinks - If true, return any non-mxc URLs * directly. Fetching such URLs will leak information about the user to * anyone they share a room with. If false, will return null for such URLs. - * @return {?string} the avatar URL or null. + * @returns the avatar URL or null. */ public mxcUrlToHttp( mxcUrl: string, @@ -5187,11 +5252,9 @@ export class MatrixClient extends TypedEventEmitter { @@ -5207,9 +5270,9 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/presence/$userId/status", { @@ -5227,13 +5290,13 @@ export class MatrixClient extends TypedEventEmitterRoom.oldState.paginationToken will be - * null. - * @return {module:http-api.MatrixError} Rejects: with an error response. + * @returns Promise which resolves: Room. If you are at the beginning + * of the timeline, `Room.oldState.paginationToken` will be + * `null`. + * @returns Rejects: with an error response. */ public scrollback(room: Room, limit = 30): Promise { let timeToWaitMs = 0; @@ -5302,13 +5365,6 @@ export class MatrixClient extends TypedEventEmitter> { // don't allow any timeline support unless it's been enabled. @@ -5563,10 +5619,10 @@ export class MatrixClient extends TypedEventEmitter> { // don't allow any timeline support unless it's been enabled. @@ -5628,12 +5684,9 @@ export class MatrixClient extends TypedEventEmitter { @@ -5997,9 +6042,9 @@ export class MatrixClient extends TypedEventEmitter { this.peekSync?.stopPeeking(); @@ -6019,16 +6064,10 @@ export class MatrixClient extends TypedEventEmitter { const writePromise = this.sendStateEvent(roomId, EventType.RoomGuestAccess, { @@ -6053,11 +6092,11 @@ export class MatrixClient extends TypedEventEmitter( endpoint: string, @@ -6276,9 +6315,9 @@ export class MatrixClient extends TypedEventEmitter | undefined { let promise: Promise | undefined; @@ -6388,20 +6427,15 @@ export class MatrixClient extends TypedEventEmitter { // TODO: support search groups @@ -6433,9 +6467,9 @@ export class MatrixClient extends TypedEventEmitter(searchResults: T): Promise { // TODO: we should implement a backoff (as per scrollback()) to deal more @@ -6469,10 +6503,8 @@ export class MatrixClient extends TypedEventEmitter(searchResults: T, response: ISearchResponse): T { @@ -6511,9 +6543,9 @@ export class MatrixClient extends TypedEventEmitter { // Guard against multiple calls whilst ongoing and multiple calls post success @@ -6539,9 +6571,9 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/user/$userId/filter", { @@ -6558,12 +6590,12 @@ export class MatrixClient extends TypedEventEmitter { if (allowCached) { @@ -6587,9 +6619,7 @@ export class MatrixClient extends TypedEventEmitter} Filter ID + * @returns Filter ID */ public async getOrCreateFilter(filterName: string, filter: Filter): Promise { const filterId = this.store.getFilterIdByName(filterName); @@ -6642,8 +6672,8 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/user/$userId/openid/request_token", { @@ -6662,8 +6692,8 @@ export class MatrixClient extends TypedEventEmitter { return this.http.authedRequest(Method.Get, "/voip/turnServer"); @@ -6671,7 +6701,7 @@ export class MatrixClient extends TypedEventEmitter} The servers or an empty list. + * @returns The servers or an empty list. */ public getTurnServers(): ITurnServer[] { return this.turnServers || []; @@ -6680,7 +6710,7 @@ export class MatrixClient extends TypedEventEmitterThis function is implementation specific and may change * as a result. - * @return {boolean} true if the user appears to be a Synapse administrator. + * @returns true if the user appears to be a Synapse administrator. */ public isSynapseAdministrator(): Promise { const path = utils.encodeUri( @@ -6780,8 +6809,8 @@ export class MatrixClient extends TypedEventEmitterThis function is implementation specific and may change as a * result. - * @param {string} userId the User ID to look up. - * @return {object} the whois response - see Synapse docs for information. + * @param userId - the User ID to look up. + * @returns the whois response - see Synapse docs for information. */ public whoisSynapseUser(userId: string): Promise { const path = utils.encodeUri( @@ -6794,8 +6823,8 @@ export class MatrixClient extends TypedEventEmitterThis * function is implementation specific and may change as a result. - * @param {string} userId the User ID to deactivate. - * @return {object} the deactivate response - see Synapse docs for information. + * @param userId - the User ID to deactivate. + * @returns the deactivate response - see Synapse docs for information. */ public deactivateSynapseUser(userId: string): Promise { const path = utils.encodeUri( @@ -6828,8 +6857,8 @@ export class MatrixClient extends TypedEventEmitter { // XXX: Intended private, used in code const primTypes = ["boolean", "string", "number"]; @@ -6846,9 +6875,9 @@ export class MatrixClient extends TypedEventEmitter} Resolves to a set of rooms - * @return {module:http-api.MatrixError} Rejects: with an error response. + * @param userId - The userId to check. + * @returns Promise which resolves to a set of rooms + * @returns Rejects: with an error response. */ public async _unstable_getSharedRooms(userId: string): Promise { // eslint-disable-line const sharedRoomsSupport = await this.doesServerSupportUnstableFeature("uk.half-shot.msc2666"); @@ -6873,7 +6902,7 @@ export class MatrixClient extends TypedEventEmitter} The server /versions response + * @returns The server /versions response */ public async getVersions(): Promise { if (this.serverVersionsPromise) { @@ -6906,8 +6935,8 @@ export class MatrixClient extends TypedEventEmitter} Whether it is supported + * @param version - The spec version (such as "r0.5.0") to check for. + * @returns Whether it is supported */ public async isVersionSupported(version: string): Promise { const { versions } = await this.getVersions(); @@ -6916,7 +6945,7 @@ export class MatrixClient extends TypedEventEmitter} true if server supports lazy loading + * @returns true if server supports lazy loading */ public async doesServerSupportLazyLoading(): Promise { const response = await this.getVersions(); @@ -6932,7 +6961,7 @@ export class MatrixClient extends TypedEventEmitter} true if id_server parameter is required + * @returns true if id_server parameter is required */ public async doesServerRequireIdServerParam(): Promise { const response = await this.getVersions(); @@ -6958,7 +6987,7 @@ export class MatrixClient extends TypedEventEmitter} true if id_access_token can be sent + * @returns true if id_access_token can be sent */ public async doesServerAcceptIdentityAccessToken(): Promise { const response = await this.getVersions(); @@ -6974,7 +7003,7 @@ export class MatrixClient extends TypedEventEmitter} true if separate functions are supported + * @returns true if separate functions are supported */ public async doesServerSupportSeparateAddAndBind(): Promise { const response = await this.getVersions(); @@ -6989,8 +7018,8 @@ export class MatrixClient extends TypedEventEmitter} true if the feature is supported + * @param feature - the feature name + * @returns true if the feature is supported */ public async doesServerSupportUnstableFeature(feature: string): Promise { const response = await this.getVersions(); @@ -7002,8 +7031,8 @@ export class MatrixClient extends TypedEventEmitter} true if the server is forcing encryption + * @param presetName - The name of the preset to check. + * @returns true if the server is forcing encryption * for the preset. */ public async doesServerForceEncryptionForPreset(presetName: Preset): Promise { @@ -7062,7 +7091,7 @@ export class MatrixClient extends TypedEventEmitter} true if server supports the `logout_devices` parameter + * @returns true if server supports the `logout_devices` parameter */ public doesServerSupportLogoutDevices(): Promise { return this.isVersionSupported("r0.6.1"); @@ -7070,7 +7099,7 @@ export class MatrixClient extends TypedEventEmitterThis * method is experimental and may change. - * @return {string} A new client secret + * @returns A new client secret */ public generateClientSecret(): string { return randomString(32); @@ -7170,11 +7198,8 @@ export class MatrixClient extends TypedEventEmitter} A decryption promise - * @param {object} options - * @param {boolean} options.isRetry True if this is a retry (enables more logging) - * @param {boolean} options.emit Emits "event.decrypted" if set to true + * @param event - The event to decrypt + * @returns A decryption promise */ public decryptEventIfNeeded(event: MatrixEvent, options?: IDecryptOptions): Promise { if (event.shouldAttemptDecryption() && this.isCryptoEnabled()) { @@ -7201,7 +7226,7 @@ export class MatrixClient extends TypedEventEmitter { return this.http.authedRequest<{ available: true }>( @@ -7280,17 +7305,11 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types - opts = opts || {}; - opts.body = opts.body || {}; - return this.registerRequest(opts.body, "guest"); + public registerGuest({ body }: { body?: any } = {}): Promise { // TODO: Types + return this.registerRequest(body || {}, "guest"); } /** - * @param {Object} data parameters for registration request - * @param {string=} kind type of user to register. may be "guest" - * @return {Promise} Resolves: to the /register response - * @return {module:http-api.MatrixError} Rejects: with an error response. + * @param data - parameters for registration request + * @param kind - type of user to register. may be "guest" + * @returns Promise which resolves: to the /register response + * @returns Rejects: with an error response. */ public registerRequest(data: IRegisterRequestParams, kind?: string): Promise { const params: { kind?: string } = {}; @@ -7396,9 +7412,9 @@ export class MatrixClient extends TypedEventEmitter} Resolves to the new token. - * @return {module:http-api.MatrixError} Rejects with an error response. + * @param refreshToken - The refresh token. + * @returns Promise which resolves to the new token. + * @returns Rejects with an error response. */ public refreshToken(refreshToken: string): Promise { return this.http.authedRequest( @@ -7414,18 +7430,16 @@ export class MatrixClient extends TypedEventEmitter} Resolves to the available login flows - * @return {module:http-api.MatrixError} Rejects: with an error response. + * @returns Promise which resolves to the available login flows + * @returns Rejects: with an error response. */ public loginFlows(): Promise { return this.http.request(Method.Get, "/login"); } /** - * @param {string} loginType - * @param {Object} data - * @return {Promise} Resolves: TODO - * @return {module:http-api.MatrixError} Rejects: with an error response. + * @returns Promise which resolves: TODO + * @returns Rejects: with an error response. */ public login(loginType: string, data: any): Promise { // TODO: Types const loginData = { @@ -7450,10 +7464,8 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types return this.login("m.login.password", { @@ -7463,9 +7475,9 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types return this.login("m.login.saml2", { @@ -7474,22 +7486,22 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types return this.login("m.login.token", { @@ -7527,8 +7539,8 @@ export class MatrixClient extends TypedEventEmitter { if (this.crypto?.backupManager?.getKeyBackupEnabled()) { @@ -7556,11 +7568,11 @@ export class MatrixClient extends TypedEventEmitter { const body: any = {}; @@ -7579,8 +7591,8 @@ export class MatrixClient extends TypedEventEmitter>} Resolves: On success, the token response + * @param auth - Optional. Auth data to supply for User-Interactive auth. + * @returns Promise which resolves: On success, the token response * or UIA auth data. */ public requestLoginToken(auth?: IAuthData): Promise> { @@ -7597,10 +7609,10 @@ export class MatrixClient extends TypedEventEmitter{room_id: {string}} - * @return {module:http-api.MatrixError} Rejects: with an error response. + * @param options - a list of options to pass to the /createRoom API. + * @returns Promise which resolves: `{room_id: {string}}` + * @returns Rejects: with an error response. */ public async createRoom(options: ICreateRoomOpts): Promise<{ room_id: string }> { // eslint-disable-line camelcase // some valid options include: room_alias_name, visibility, invite @@ -7648,12 +7654,12 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/rooms/$roomId/state", { $roomId: roomId }); @@ -7706,11 +7711,9 @@ export class MatrixClient extends TypedEventEmitter> { const path = utils.encodeUri( @@ -7723,12 +7726,11 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/rooms/$roomId/initialSync", @@ -7841,14 +7833,14 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/joined_rooms", {}); @@ -7886,10 +7878,10 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/rooms/$roomId/joined_members", { @@ -7899,16 +7891,14 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/directory/room/$alias", { @@ -7941,9 +7931,9 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/directory/room/$alias", { @@ -7955,9 +7945,9 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/rooms/$roomId/aliases", { $roomId: roomId }); @@ -7967,9 +7957,9 @@ export class MatrixClient extends TypedEventEmitter { @@ -7995,9 +7984,8 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/directory/list/room/$roomId", { @@ -8008,12 +7996,11 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/directory/list/room/$roomId", { @@ -8025,14 +8012,13 @@ export class MatrixClient extends TypedEventEmitter { + public searchUserDirectory({ term, limit }: { term: string, limit?: number }): Promise { const body: any = { - search_term: opts.term, + search_term: term, }; - if (opts.limit !== undefined) { - body.limit = opts.limit; + if (limit !== undefined) { + body.limit = limit; } return this.http.authedRequest(Method.Post, "/user_directory/search", undefined, body); @@ -8069,27 +8054,13 @@ export class MatrixClient extends TypedEventEmitterfile.name. - * - * @param {boolean=} opts.includeFilename if false will not send the filename, - * e.g for encrypted file uploads where filename leaks are undesirable. - * Defaults to true. - * - * @param {string=} opts.type Content-type for the upload. Defaults to - * file.type, or applicaton/octet-stream. - * - * @param {Function=} opts.progressHandler Optional. Called when a chunk of - * data has been uploaded, with an object containing the fields `loaded` - * (number of bytes transferred) and `total` (total size, if known). - * - * @return {Promise} Resolves to response object, as + * @returns Promise which resolves to response object, as * determined by this.opts.onlyData, opts.rawResponse, and * opts.onlyContentUri. Rejects with an error (usually a MatrixError). */ @@ -8099,8 +8070,8 @@ export class MatrixClient extends TypedEventEmitter): boolean { return this.http.cancelUpload(upload); @@ -8108,7 +8079,7 @@ export class MatrixClient extends TypedEventEmitter { return this.http.authedRequest(Method.Get, "/account/3pid"); @@ -8153,10 +8123,8 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types const path = "/account/3pid"; @@ -8174,10 +8142,10 @@ export class MatrixClient extends TypedEventEmitter/requestToken` on the homeserver. - * @return {Promise} Resolves: to an empty object {} - * @return {module:http-api.MatrixError} Rejects: with an error response. + * @returns Promise which resolves: to an empty object `{}` + * @returns Rejects: with an error response. */ public async addThreePidOnly(data: IAddThreePidOnlyBody): Promise<{}> { const path = "/account/3pid/add"; @@ -8193,11 +8161,11 @@ export class MatrixClient extends TypedEventEmitter/requestToken` on the identity server. It should also * contain `id_server` and `id_access_token` fields as well. - * @return {Promise} Resolves: to an empty object {} - * @return {module:http-api.MatrixError} Rejects: with an error response. + * @returns Promise which resolves: to an empty object `{}` + * @returns Rejects: with an error response. */ public async bindThreePid(data: IBindThreePidBody): Promise<{}> { const path = "/account/3pid/bind"; @@ -8210,11 +8178,11 @@ export class MatrixClient extends TypedEventEmitter { return this.http.authedRequest(Method.Get, "/devices"); @@ -8282,9 +8249,9 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/devices/$device_id", { @@ -8296,10 +8263,10 @@ export class MatrixClient extends TypedEventEmitter { @@ -8313,10 +8280,10 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/devices/$device_id", { @@ -8335,10 +8302,10 @@ export class MatrixClient extends TypedEventEmitter { const body: any = { devices }; @@ -8354,8 +8321,8 @@ export class MatrixClient extends TypedEventEmitter { const response = await this.http.authedRequest<{ pushers: IPusher[] }>(Method.Get, "/pushers"); @@ -8377,9 +8344,9 @@ export class MatrixClient extends TypedEventEmitter { const path = "/pushers/set"; @@ -8388,10 +8355,8 @@ export class MatrixClient extends TypedEventEmitter { return this.http.authedRequest(Method.Get, "/pushrules/").then((rules: IPushRules) => { @@ -8413,12 +8378,8 @@ export class MatrixClient extends TypedEventEmitter { const queryParams: any = {}; - if (opts.next_batch) { - queryParams.next_batch = opts.next_batch; + if (nextBatch) { + queryParams.next_batch = nextBatch; } - return this.http.authedRequest(Method.Post, "/search", queryParams, opts.body, { abortSignal }); + return this.http.authedRequest(Method.Post, "/search", queryParams, body, { abortSignal }); } /** * Upload keys * - * @param {Object} content body of upload request + * @param content - body of upload request * - * @param {Object=} opts this method no longer takes any opts, + * @param opts - this method no longer takes any opts, * used to take opts.device_id but this was not removed from the spec as a redundant parameter * - * @return {Promise} Resolves: result object. Rejects: with - * an error response ({@link module:http-api.MatrixError}). + * @returns Promise which resolves: result object. Rejects: with + * an error response ({@link MatrixError}). */ public uploadKeysRequest( content: IUploadKeysRequest, @@ -8548,22 +8497,20 @@ export class MatrixClient extends TypedEventEmitter { + public downloadKeysForUsers(userIds: string[], { token }: { token?: string } = {}): Promise { const content: IQueryKeysRequest = { device_keys: {}, }; - if ('token' in opts) { - content.token = opts.token; + if (token !== undefined) { + content.token = token; } userIds.forEach((u) => { content.device_keys[u] = []; @@ -8575,15 +8522,15 @@ export class MatrixClient extends TypedEventEmitter { const qps = { @@ -8641,15 +8586,14 @@ export class MatrixClient extends TypedEventEmitter} The hashing information for the identity server. + * @param identityAccessToken - The access token for the identity server. + * @returns The hashing information for the identity server. */ public getIdentityHashDetails(identityAccessToken: string): Promise { // TODO: Types return this.http.idServerRequest( @@ -8842,11 +8786,11 @@ export class MatrixClient extends TypedEventEmitter>} addressPairs An array of 2 element arrays. + * @param addressPairs - An array of 2 element arrays. * The first element of each pair is the address, the second is the 3PID medium. - * Eg: ["email@example.org", "email"] - * @param {string} identityAccessToken The access token for the identity server. - * @returns {Promise>} A collection of address mappings to + * Eg: `["email@example.org", "email"]` + * @param identityAccessToken - The access token for the identity server. + * @returns A collection of address mappings to * found MXIDs. Results where no user could be found will not be listed. */ public async identityHashedLookup( @@ -8925,15 +8869,15 @@ export class MatrixClient extends TypedEventEmitter>} query Array of arrays containing + * @param query - Array of arrays containing * [medium, address] - * @param {string} identityAccessToken The `access_token` field of the Identity + * @param identityAccessToken - The `access_token` field of the Identity * Server `/account/register` response (see {@link registerWithIdentityServer}). * - * @return {Promise} Resolves: Lookup results from IS. - * @return {module:http-api.MatrixError} Rejects: with an error response. + * @returns Promise which resolves: Lookup results from IS. + * @returns Rejects: with an error response. */ public async bulkLookupThreePids(query: [string, string][], identityAccessToken: string): Promise { // TODO: Types // Note: we're using the V2 API by calling this function, but our @@ -9006,11 +8950,11 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types return this.http.idServerRequest( @@ -9025,12 +8969,11 @@ export class MatrixClient extends TypedEventEmitter>} contentMap + * @param eventType - type of event to send * content to send. Map from user_id to device_id to content object. - * @param {string=} txnId transaction id. One will be made up if not + * @param txnId - transaction id. One will be made up if not * supplied. - * @return {Promise} Resolves: to an empty object {} + * @returns Promise which resolves: to an empty object `{}` */ public sendToDevice( eventType: string, @@ -9060,7 +9003,7 @@ export class MatrixClient extends TypedEventEmitter { return this.toDeviceMessageQueue.queueBatch(batch); @@ -9069,7 +9012,7 @@ export class MatrixClient extends TypedEventEmitter { return this.http.authedRequest>( @@ -9086,10 +9029,10 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types const path = utils.encodeUri("/thirdparty/user/$protocol", { @@ -9140,11 +9083,11 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/rooms/$roomId/report/$eventId", { @@ -9158,12 +9101,12 @@ export class MatrixClient extends TypedEventEmitter} Resolves to the created space. + * @param name - The name of the tree space. + * @returns Promise which resolves to the created space. */ public async unstableCreateFileTree(name: string): Promise { const { room_id: roomId } = await this.createRoom({ @@ -9244,8 +9187,8 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/rooms/$roomid/summary", { $roomid: roomIdOrAlias }); @@ -9355,7 +9298,7 @@ export class MatrixClient extends TypedEventEmitter - * This is only fired for live events received via /sync - it is not fired for - * events received over context, search, or pagination APIs. - * - * @event module:client~MatrixClient#"event" - * @param {MatrixEvent} event The matrix event which caused this event to fire. - * @example - * matrixClient.on("event", function(event){ - * var sender = event.getSender(); - * }); - */ - -/** - * Fires whenever the SDK receives a new to-device event. - * @event module:client~MatrixClient#"toDeviceEvent" - * @param {MatrixEvent} event The matrix event which caused this event to fire. - * @example - * matrixClient.on("toDeviceEvent", function(event){ - * var sender = event.getSender(); - * }); - */ - -/** - * Fires whenever the SDK's syncing state is updated. The state can be one of: - *

    - * - *
  • PREPARED: The client has synced with the server at least once and is - * ready for methods to be called on it. This will be immediately followed by - * a state of SYNCING. This is the equivalent of "syncComplete" in the - * previous API.
  • - * - *
  • CATCHUP: The client has detected the connection to the server might be - * available again and will now try to do a sync again. As this sync might take - * a long time (depending how long ago was last synced, and general server - * performance) the client is put in this mode so the UI can reflect trying - * to catch up with the server after losing connection.
  • - * - *
  • SYNCING : The client is currently polling for new events from the server. - * This will be called after processing latest events from a sync.
  • - * - *
  • ERROR : The client has had a problem syncing with the server. If this is - * called before PREPARED then there was a problem performing the initial - * sync. If this is called after PREPARED then there was a problem polling - * the server for updates. This may be called multiple times even if the state is - * already ERROR. This is the equivalent of "syncError" in the previous - * API.
  • - * - *
  • RECONNECTING: The sync connection has dropped, but not (yet) in a way that - * should be considered erroneous. - *
  • - * - *
  • STOPPED: The client has stopped syncing with server due to stopClient - * being called. - *
  • - *
- * State transition diagram: - *
- *                                          +---->STOPPED
- *                                          |
- *              +----->PREPARED -------> SYNCING <--+
- *              |                        ^  |  ^    |
- *              |      CATCHUP ----------+  |  |    |
- *              |        ^                  V  |    |
- *   null ------+        |  +------- RECONNECTING   |
- *              |        V  V                       |
- *              +------->ERROR ---------------------+
- *
- * NB: 'null' will never be emitted by this event.
- *
- * 
- * Transitions: - *
    - * - *
  • null -> PREPARED : Occurs when the initial sync is completed - * first time. This involves setting up filters and obtaining push rules. - * - *
  • null -> ERROR : Occurs when the initial sync failed first time. - * - *
  • ERROR -> PREPARED : Occurs when the initial sync succeeds - * after previously failing. - * - *
  • PREPARED -> SYNCING : Occurs immediately after transitioning - * to PREPARED. Starts listening for live updates rather than catching up. - * - *
  • SYNCING -> RECONNECTING : Occurs when the live update fails. - * - *
  • RECONNECTING -> RECONNECTING : Can occur if the update calls - * continue to fail, but the keepalive calls (to /versions) succeed. - * - *
  • RECONNECTING -> ERROR : Occurs when the keepalive call also fails - * - *
  • ERROR -> SYNCING : Occurs when the client has performed a - * live update after having previously failed. - * - *
  • ERROR -> ERROR : Occurs when the client has failed to keepalive - * for a second time or more.
  • - * - *
  • SYNCING -> SYNCING : Occurs when the client has performed a live - * update. This is called after processing.
  • - * - *
  • * -> STOPPED : Occurs once the client has stopped syncing or - * trying to sync after stopClient has been called.
  • - *
- * - * @event module:client~MatrixClient#"sync" - * - * @param {string} state An enum representing the syncing state. One of "PREPARED", - * "SYNCING", "ERROR", "STOPPED". - * - * @param {?string} prevState An enum representing the previous syncing state. - * One of "PREPARED", "SYNCING", "ERROR", "STOPPED" or null. - * - * @param {?Object} data Data about this transition. - * - * @param {MatrixError} data.error The matrix error if state=ERROR. - * - * @param {String} data.oldSyncToken The 'since' token passed to /sync. - * null for the first successful sync since this client was - * started. Only present if state=PREPARED or - * state=SYNCING. - * - * @param {String} data.nextSyncToken The 'next_batch' result from /sync, which - * will become the 'since' token for the next call to /sync. Only present if - * state=PREPARED or state=SYNCING. - * - * @param {boolean} data.catchingUp True if we are working our way through a - * backlog of events after connecting. Only present if state=SYNCING. - * - * @example - * matrixClient.on("sync", function(state, prevState, data) { - * switch (state) { - * case "ERROR": - * // update UI to say "Connection Lost" - * break; - * case "SYNCING": - * // update UI to remove any "Connection Lost" message - * break; - * case "PREPARED": - * // the client instance is ready to be queried. - * var rooms = matrixClient.getRooms(); - * break; - * } - * }); - */ - -/** - * Fires whenever a new Room is added. This will fire when you are invited to a - * room, as well as when you join a room. This event is experimental and - * may change. - * @event module:client~MatrixClient#"Room" - * @param {Room} room The newly created, fully populated room. - * @example - * matrixClient.on("Room", function(room){ - * var roomId = room.roomId; - * }); - */ - -/** - * Fires whenever a Room is removed. This will fire when you forget a room. - * This event is experimental and may change. - * @event module:client~MatrixClient#"deleteRoom" - * @param {string} roomId The deleted room ID. - * @example - * matrixClient.on("deleteRoom", function(roomId){ - * // update UI from getRooms() - * }); - */ - -/** - * Fires whenever an incoming call arrives. - * @event module:client~MatrixClient#"Call.incoming" - * @param {module:webrtc/call~MatrixCall} call The incoming call. - * @example - * matrixClient.on("Call.incoming", function(call){ - * call.answer(); // auto-answer - * }); - */ - -/** - * Fires whenever the login session the JS SDK is using is no - * longer valid and the user must log in again. - * NB. This only fires when action is required from the user, not - * when then login session can be renewed by using a refresh token. - * @event module:client~MatrixClient#"Session.logged_out" - * @example - * matrixClient.on("Session.logged_out", function(errorObj){ - * // show the login screen - * }); - */ - -/** - * Fires when the JS SDK receives a M_CONSENT_NOT_GIVEN error in response - * to a HTTP request. - * @event module:client~MatrixClient#"no_consent" - * @example - * matrixClient.on("no_consent", function(message, contentUri) { - * console.info(message + ' Go to ' + contentUri); - * }); - */ - -/** - * Fires when a device is marked as verified/unverified/blocked/unblocked by - * {@link module:client~MatrixClient#setDeviceVerified|MatrixClient.setDeviceVerified} or - * {@link module:client~MatrixClient#setDeviceBlocked|MatrixClient.setDeviceBlocked}. - * - * @event module:client~MatrixClient#"deviceVerificationChanged" - * @param {string} userId the owner of the verified device - * @param {string} deviceId the id of the verified device - * @param {module:crypto/deviceinfo} deviceInfo updated device information - */ - -/** - * Fires when the trust status of a user changes - * If userId is the userId of the logged in user, this indicated a change - * in the trust status of the cross-signing data on the account. - * - * The cross-signing API is currently UNSTABLE and may change without notice. - * - * @event module:client~MatrixClient#"userTrustStatusChanged" - * @param {string} userId the userId of the user in question - * @param {UserTrustLevel} trustLevel The new trust level of the user - */ - -/** - * Fires when the user's cross-signing keys have changed or cross-signing - * has been enabled/disabled. The client can use getStoredCrossSigningForUser - * with the user ID of the logged in user to check if cross-signing is - * enabled on the account. If enabled, it can test whether the current key - * is trusted using with checkUserTrust with the user ID of the logged - * in user. The checkOwnCrossSigningTrust function may be used to reconcile - * the trust in the account key. - * - * The cross-signing API is currently UNSTABLE and may change without notice. - * - * @event module:client~MatrixClient#"crossSigning.keysChanged" - */ - -/** - * Fires whenever new user-scoped account_data is added. - * @event module:client~MatrixClient#"accountData" - * @param {MatrixEvent} event The event describing the account_data just added - * @param {MatrixEvent} event The previous account data, if known. - * @example - * matrixClient.on("accountData", function(event, oldEvent){ - * myAccountData[event.type] = event.content; - * }); - */ - -/** - * Fires whenever the stored devices for a user have changed - * @event module:client~MatrixClient#"crypto.devicesUpdated" - * @param {String[]} users A list of user IDs that were updated - * @param {boolean} initialFetch If true, the store was empty (apart - * from our own device) and has been seeded. - */ - -/** - * Fires whenever the stored devices for a user will be updated - * @event module:client~MatrixClient#"crypto.willUpdateDevices" - * @param {String[]} users A list of user IDs that will be updated - * @param {boolean} initialFetch If true, the store is empty (apart - * from our own device) and is being seeded. - */ - -/** - * Fires whenever the status of e2e key backup changes, as returned by getKeyBackupEnabled() - * @event module:client~MatrixClient#"crypto.keyBackupStatus" - * @param {boolean} enabled true if key backup has been enabled, otherwise false - * @example - * matrixClient.on("crypto.keyBackupStatus", function(enabled){ - * if (enabled) { - * [...] - * } - * }); - */ - -/** - * Fires when we want to suggest to the user that they restore their megolm keys - * from backup or by cross-signing the device. - * - * @event module:client~MatrixClient#"crypto.suggestKeyRestore" - */ - -/** - * Fires when a key verification is requested. - * @event module:client~MatrixClient#"crypto.verification.request" - * @param {object} data - * @param {MatrixEvent} data.event the original verification request message - * @param {Array} data.methods the verification methods that can be used - * @param {Number} data.timeout the amount of milliseconds that should be waited - * before cancelling the request automatically. - * @param {Function} data.beginKeyVerification a function to call if a key - * verification should be performed. The function takes one argument: the - * name of the key verification method (taken from data.methods) to use. - * @param {Function} data.cancel a function to call if the key verification is - * rejected. - */ - -/** - * Fires when a key verification is requested with an unknown method. - * @event module:client~MatrixClient#"crypto.verification.request.unknown" - * @param {string} userId the user ID who requested the key verification - * @param {Function} cancel a function that will send a cancellation message to - * reject the key verification. - */ - -/** - * Fires when a secret request has been cancelled. If the client is prompting - * the user to ask whether they want to share a secret, the prompt can be - * dismissed. - * - * The Secure Secret Storage API is currently UNSTABLE and may change without notice. - * - * @event module:client~MatrixClient#"crypto.secrets.requestCancelled" - * @param {object} data - * @param {string} data.user_id The user ID of the client that had requested the secret. - * @param {string} data.device_id The device ID of the client that had requested the - * secret. - * @param {string} data.request_id The ID of the original request. - */ - -/** - * Fires when the client .well-known info is fetched. - * - * @event module:client~MatrixClient#"WellKnown.client" - * @param {object} data The JSON object returned by the server - */ diff --git a/src/content-helpers.ts b/src/content-helpers.ts index 6fa4b684b..b66f0d102 100644 --- a/src/content-helpers.ts +++ b/src/content-helpers.ts @@ -14,8 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/** @module ContentHelpers */ - import { isProvided, REFERENCE_RELATION } from "matrix-events-sdk"; import { MBeaconEventContent, MBeaconInfoContent, MBeaconInfoEventContent } from "./@types/beacon"; @@ -37,9 +35,9 @@ import { IContent } from "./models/event"; /** * Generates the content for a HTML Message event - * @param {string} body the plaintext body of the message - * @param {string} htmlBody the HTML representation of the message - * @returns {{msgtype: string, format: string, body: string, formatted_body: string}} + * @param body - the plaintext body of the message + * @param htmlBody - the HTML representation of the message + * @returns */ export function makeHtmlMessage(body: string, htmlBody: string): IContent { return { @@ -52,9 +50,9 @@ export function makeHtmlMessage(body: string, htmlBody: string): IContent { /** * Generates the content for a HTML Notice event - * @param {string} body the plaintext body of the notice - * @param {string} htmlBody the HTML representation of the notice - * @returns {{msgtype: string, format: string, body: string, formatted_body: string}} + * @param body - the plaintext body of the notice + * @param htmlBody - the HTML representation of the notice + * @returns */ export function makeHtmlNotice(body: string, htmlBody: string): IContent { return { @@ -67,9 +65,9 @@ export function makeHtmlNotice(body: string, htmlBody: string): IContent { /** * Generates the content for a HTML Emote event - * @param {string} body the plaintext body of the emote - * @param {string} htmlBody the HTML representation of the emote - * @returns {{msgtype: string, format: string, body: string, formatted_body: string}} + * @param body - the plaintext body of the emote + * @param htmlBody - the HTML representation of the emote + * @returns */ export function makeHtmlEmote(body: string, htmlBody: string): IContent { return { @@ -82,8 +80,8 @@ export function makeHtmlEmote(body: string, htmlBody: string): IContent { /** * Generates the content for a Plaintext Message event - * @param {string} body the plaintext body of the emote - * @returns {{msgtype: string, body: string}} + * @param body - the plaintext body of the emote + * @returns */ export function makeTextMessage(body: string): IContent { return { @@ -94,8 +92,8 @@ export function makeTextMessage(body: string): IContent { /** * Generates the content for a Plaintext Notice event - * @param {string} body the plaintext body of the notice - * @returns {{msgtype: string, body: string}} + * @param body - the plaintext body of the notice + * @returns */ export function makeNotice(body: string): IContent { return { @@ -106,8 +104,8 @@ export function makeNotice(body: string): IContent { /** * Generates the content for a Plaintext Emote event - * @param {string} body the plaintext body of the emote - * @returns {{msgtype: string, body: string}} + * @param body - the plaintext body of the emote + * @returns */ export function makeEmoteMessage(body: string): IContent { return { @@ -139,11 +137,11 @@ export const getTextForLocationEvent = ( /** * Generates the content for a Location event - * @param uri a geo:// uri for the location - * @param timestamp the timestamp when the location was correct (milliseconds since the UNIX epoch) - * @param description the (optional) label for this location on the map - * @param assetType the (optional) asset type of this location e.g. "m.self" - * @param text optional. A text for the location + * @param uri - a geo:// uri for the location + * @param timestamp - the timestamp when the location was correct (milliseconds since the UNIX epoch) + * @param description - the (optional) label for this location on the map + * @param assetType - the (optional) asset type of this location e.g. "m.self" + * @param text - optional. A text for the location */ export const makeLocationContent = ( // this is first but optional diff --git a/src/content-repo.ts b/src/content-repo.ts index d6cf81f2e..9b6f6d372 100644 --- a/src/content-repo.ts +++ b/src/content-repo.ts @@ -13,25 +13,22 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -/** - * @module content-repo - */ import * as utils from "./utils"; /** * Get the HTTP URL for an MXC URI. - * @param {string} baseUrl The base homeserver url which has a content repo. - * @param {string} mxc The mxc:// URI. - * @param {Number} width The desired width of the thumbnail. - * @param {Number} height The desired height of the thumbnail. - * @param {string} resizeMethod The thumbnail resize method to use, either + * @param baseUrl - The base homeserver url which has a content repo. + * @param mxc - The mxc:// URI. + * @param width - The desired width of the thumbnail. + * @param height - The desired height of the thumbnail. + * @param resizeMethod - The thumbnail resize method to use, either * "crop" or "scale". - * @param {Boolean} allowDirectLinks If true, return any non-mxc URLs + * @param allowDirectLinks - If true, return any non-mxc URLs * directly. Fetching such URLs will leak information about the user to * anyone they share a room with. If false, will return the emptry string * for such URLs. - * @return {string} The complete URL to the content. + * @returns The complete URL to the content. */ export function getHttpUriForMxc( baseUrl: string, diff --git a/src/crypto/CrossSigning.ts b/src/crypto/CrossSigning.ts index 4035db04c..1ac9e2144 100644 --- a/src/crypto/CrossSigning.ts +++ b/src/crypto/CrossSigning.ts @@ -16,7 +16,6 @@ limitations under the License. /** * Cross signing methods - * @module crypto/CrossSigning */ import { PkSigning } from "@matrix-org/olm"; @@ -67,12 +66,10 @@ export class CrossSigningInfo { /** * Information about a user's cross-signing keys * - * @class - * - * @param {string} userId the user that the information is about - * @param {object} callbacks Callbacks used to interact with the app + * @param userId - the user that the information is about + * @param callbacks - Callbacks used to interact with the app * Requires getCrossSigningKey and saveCrossSigningKeys - * @param {object} cacheCallbacks Callbacks used to interact with the cache + * @param cacheCallbacks - Callbacks used to interact with the cache */ public constructor( public readonly userId: string, @@ -102,10 +99,10 @@ export class CrossSigningInfo { /** * Calls the app callback to ask for a private key * - * @param {string} type The key type ("master", "self_signing", or "user_signing") - * @param {string} expectedPubkey The matching public key or undefined to use + * @param type - The key type ("master", "self_signing", or "user_signing") + * @param expectedPubkey - The matching public key or undefined to use * the stored public key for the given key type. - * @returns {Array} An array with [ public key, Olm.PkSigning ] + * @returns An array with [ public key, Olm.PkSigning ] */ public async getCrossSigningKey(type: string, expectedPubkey?: string): Promise<[string, PkSigning]> { const shouldCache = ["master", "self_signing", "user_signing"].indexOf(type) >= 0; @@ -165,8 +162,8 @@ export class CrossSigningInfo { * XXX: This could be static, be we often seem to have an instance when we * want to know this anyway... * - * @param {SecretStorage} secretStorage The secret store using account data - * @returns {object} map of key name to key info the secret is encrypted + * @param secretStorage - The secret store using account data + * @returns map of key name to key info the secret is encrypted * with, or null if it is not present or not encrypted with a trusted * key */ @@ -194,8 +191,8 @@ export class CrossSigningInfo { * typically called in conjunction with the creation of new cross-signing * keys. * - * @param {Map} keys The keys to store - * @param {SecretStorage} secretStorage The secret store using account data + * @param keys - The keys to store + * @param secretStorage - The secret store using account data */ public static async storeInSecretStorage( keys: Map, @@ -211,10 +208,10 @@ export class CrossSigningInfo { * Get private keys from secret storage created by some other device. This * also passes the private keys to the app-specific callback. * - * @param {string} type The type of key to get. One of "master", + * @param type - The type of key to get. One of "master", * "self_signing", or "user_signing". - * @param {SecretStorage} secretStorage The secret store using account data - * @return {Uint8Array} The private key + * @param secretStorage - The secret store using account data + * @returns The private key */ public static async getFromSecretStorage(type: string, secretStorage: SecretStorage): Promise { const encodedKey = await secretStorage.get(`m.cross_signing.${type}`); @@ -227,9 +224,9 @@ export class CrossSigningInfo { /** * Check whether the private keys exist in the local key cache. * - * @param {string} [type] The type of key to get. One of "master", + * @param type - The type of key to get. One of "master", * "self_signing", or "user_signing". Optional, will check all by default. - * @returns {boolean} True if all keys are stored in the local cache. + * @returns True if all keys are stored in the local cache. */ public async isStoredInKeyCache(type?: string): Promise { const cacheCallbacks = this.cacheCallbacks; @@ -246,7 +243,7 @@ export class CrossSigningInfo { /** * Get cross-signing private keys from the local cache. * - * @returns {Map} A map from key type (string) to private key (Uint8Array) + * @returns A map from key type (string) to private key (Uint8Array) */ public async getCrossSigningKeysFromCache(): Promise> { const keys = new Map(); @@ -266,10 +263,10 @@ export class CrossSigningInfo { * Get the ID used to identify the user. This can also be used to test for * the existence of a given key type. * - * @param {string} type The type of key to get the ID of. One of "master", + * @param type - The type of key to get the ID of. One of "master", * "self_signing", or "user_signing". Defaults to "master". * - * @return {string} the ID + * @returns the ID */ public getId(type = "master"): string | null { if (!this.keys[type]) return null; @@ -282,7 +279,7 @@ export class CrossSigningInfo { * will be held in this class, while the private keys are passed off to the * `saveCrossSigningKeys` application callback. * - * @param {CrossSigningLevel} level The key types to reset + * @param level - The key types to reset */ public async resetKeys(level?: CrossSigningLevel): Promise { if (!this.callbacks.saveCrossSigningKeys) { @@ -502,9 +499,9 @@ export class CrossSigningInfo { /** * Check whether a given user is trusted. * - * @param {CrossSigningInfo} userCrossSigning Cross signing info for user + * @param userCrossSigning - Cross signing info for user * - * @returns {UserTrustLevel} + * @returns */ public checkUserTrust(userCrossSigning: CrossSigningInfo): UserTrustLevel { // if we're checking our own key, then it's trusted if the master key @@ -542,12 +539,12 @@ export class CrossSigningInfo { /** * Check whether a given device is trusted. * - * @param {CrossSigningInfo} userCrossSigning Cross signing info for user - * @param {module:crypto/deviceinfo} device The device to check - * @param {boolean} localTrust Whether the device is trusted locally - * @param {boolean} trustCrossSignedDevices Whether we trust cross signed devices + * @param userCrossSigning - Cross signing info for user + * @param device - The device to check + * @param localTrust - Whether the device is trusted locally + * @param trustCrossSignedDevices - Whether we trust cross signed devices * - * @returns {DeviceTrustLevel} + * @returns */ public checkDeviceTrust( userCrossSigning: CrossSigningInfo, @@ -580,7 +577,7 @@ export class CrossSigningInfo { } /** - * @returns {object} Cache callbacks + * @returns Cache callbacks */ public getCacheCallbacks(): ICacheCallbacks { return this.cacheCallbacks; @@ -621,21 +618,21 @@ export class UserTrustLevel { ) {} /** - * @returns {boolean} true if this user is verified via any means + * @returns true if this user is verified via any means */ public isVerified(): boolean { return this.isCrossSigningVerified(); } /** - * @returns {boolean} true if this user is verified via cross signing + * @returns true if this user is verified via cross signing */ public isCrossSigningVerified(): boolean { return this.crossSigningVerified; } /** - * @returns {boolean} true if we ever verified this user before (at least for + * @returns true if we ever verified this user before (at least for * the history of verifications observed by this device). */ public wasCrossSigningVerified(): boolean { @@ -643,7 +640,7 @@ export class UserTrustLevel { } /** - * @returns {boolean} true if this user's key is trusted on first use + * @returns true if this user's key is trusted on first use */ public isTofu(): boolean { return this.tofu; @@ -675,7 +672,7 @@ export class DeviceTrustLevel { } /** - * @returns {boolean} true if this device is verified via any means + * @returns true if this device is verified via any means */ public isVerified(): boolean { return Boolean(this.isLocallyVerified() || ( @@ -684,21 +681,21 @@ export class DeviceTrustLevel { } /** - * @returns {boolean} true if this device is verified via cross signing + * @returns true if this device is verified via cross signing */ public isCrossSigningVerified(): boolean { return this.crossSigningVerified; } /** - * @returns {boolean} true if this device is verified locally + * @returns true if this device is verified locally */ public isLocallyVerified(): boolean { return this.localVerified; } /** - * @returns {boolean} true if this device is trusted from a user's key + * @returns true if this device is trusted from a user's key * that is trusted on first use */ public isTofu(): boolean { @@ -757,9 +754,9 @@ export type KeysDuringVerification = [[string, PkSigning], [string, PkSigning], /** * Request cross-signing keys from another device during verification. * - * @param {MatrixClient} baseApis base Matrix API interface - * @param {string} userId The user ID being verified - * @param {string} deviceId The device ID being verified + * @param baseApis - base Matrix API interface + * @param userId - The user ID being verified + * @param deviceId - The device ID being verified */ export async function requestKeysDuringVerification( baseApis: MatrixClient, diff --git a/src/crypto/DeviceList.ts b/src/crypto/DeviceList.ts index da40a03f2..81dc5e18e 100644 --- a/src/crypto/DeviceList.ts +++ b/src/crypto/DeviceList.ts @@ -15,8 +15,6 @@ limitations under the License. */ /** - * @module crypto/DeviceList - * * Manages the list of other users' devices */ @@ -64,9 +62,6 @@ export type DeviceInfoMap = Record>; type EmittedEvents = CryptoEvent.WillUpdateDevices | CryptoEvent.DevicesUpdated | CryptoEvent.UserCrossSigningUpdated; -/** - * @alias module:crypto/DeviceList - */ export class DeviceList extends TypedEventEmitter { private devices: { [userId: string]: { [deviceId: string]: IDevice } } = {}; @@ -163,11 +158,11 @@ export class DeviceList extends TypedEventEmitter} true if the data was saved, false if + * @returns true if the data was saved, false if * it was not (eg. because no changes were pending). The promise * will only resolve once the data is saved, so may take some time * to resolve. @@ -236,7 +231,7 @@ export class DeviceList extends TypedEventEmitterdeviceId->{@link - * module:crypto/deviceinfo|DeviceInfo}. + * @returns A promise which resolves to a map userId-\>deviceId-\>{@link DeviceInfo}. */ public downloadKeys(userIds: string[], forceDownload: boolean): Promise { const usersToDownload: string[] = []; @@ -303,9 +297,9 @@ export class DeviceList extends TypedEventEmitterdeviceId->{@link module:crypto/deviceinfo|DeviceInfo}. + * @returns userId-\>deviceId-\>{@link DeviceInfo}. */ private getDevicesFromStore(userIds: string[]): DeviceInfoMap { const stored: DeviceInfoMap = {}; @@ -322,7 +316,7 @@ export class DeviceList extends TypedEventEmitter{object} devices, or undefined if + * @returns `deviceId->{object}` devices, or undefined if * there is no data for this user. */ public getRawStoredDevicesForUser(userId: string): Record { @@ -376,10 +370,8 @@ export class DeviceList extends TypedEventEmitter): void { this.setRawStoredDevicesForUser(userId, devices); @@ -468,7 +458,6 @@ export class DeviceList extends TypedEventEmitter { @@ -569,9 +556,9 @@ export class DeviceList extends TypedEventEmitter{object} the new devices + * @param devices - `deviceId->{object}` the new devices */ public setRawStoredDevicesForUser(userId: string, devices: Record): void { // remove old devices from userByIdentityKey @@ -602,9 +589,9 @@ export class DeviceList extends TypedEventEmitter} accountData pre-existing account data, will only be read, not written. - * @param {CryptoCallbacks} delegateCryptoCallbacks crypto callbacks to delegate to if the key isn't in cache yet + * @param accountData - pre-existing account data, will only be read, not written. + * @param delegateCryptoCallbacks - crypto callbacks to delegate to if the key isn't in cache yet */ public constructor(accountData: Record, delegateCryptoCallbacks?: ICryptoCallbacks) { this.accountDataClientAdapter = new AccountDataClientAdapter(accountData); @@ -70,13 +70,13 @@ export class EncryptionSetupBuilder { /** * Adds new cross-signing public keys * - * @param {function} authUpload Function called to await an interactive auth + * @param authUpload - Function called to await an interactive auth * flow when uploading device signing keys. * Args: - * {function} A function that makes the request requiring auth. Receives + * A function that makes the request requiring auth. Receives * the auth data as an object. Can be called multiple times, first with * an empty authDict, to obtain the flows. - * @param {Object} keys the new keys + * @param keys - the new keys */ public addCrossSigningKeys(authUpload: ICrossSigningKeys["authUpload"], keys: ICrossSigningKeys["keys"]): void { this.crossSigningKeys = { authUpload, keys }; @@ -88,7 +88,7 @@ export class EncryptionSetupBuilder { * Used either to create a new key backup, or add signatures * from the new MSK. * - * @param {Object} keyBackupInfo as received from/sent to the server + * @param keyBackupInfo - as received from/sent to the server */ public addSessionBackup(keyBackupInfo: IKeyBackupInfo): void { this.keyBackupInfo = keyBackupInfo; @@ -99,7 +99,6 @@ export class EncryptionSetupBuilder { * * Used after fixing the format of the key * - * @param {Uint8Array} privateKey */ public addSessionBackupPrivateKeyToCache(privateKey: Uint8Array): void { this.sessionBackupPrivateKey = privateKey; @@ -109,9 +108,6 @@ export class EncryptionSetupBuilder { * Add signatures from a given user and device/x-sign key * Used to sign the new cross-signing key with the device key * - * @param {String} userId - * @param {String} deviceId - * @param {Object} signature */ public addKeySignature(userId: string, deviceId: string, signature: ISignedKey): void { if (!this.keySignatures) { @@ -122,18 +118,12 @@ export class EncryptionSetupBuilder { userSignatures[deviceId] = signature; } - /** - * @param {String} type - * @param {Object} content - * @return {Promise} - */ public async setAccountData(type: string, content: object): Promise { await this.accountDataClientAdapter.setAccountData(type, content); } /** * builds the operation containing all the parts that have been added to the builder - * @return {EncryptionSetupOperation} */ public buildOperation(): EncryptionSetupOperation { const accountData = this.accountDataClientAdapter.values; @@ -150,9 +140,6 @@ export class EncryptionSetupBuilder { * * This does not yet store the operation in a way that it can be restored, * but that is the idea in the future. - * - * @param {Crypto} crypto - * @return {Promise} */ public async persist(crypto: Crypto): Promise { // store private keys in cache @@ -187,10 +174,6 @@ export class EncryptionSetupBuilder { */ export class EncryptionSetupOperation { /** - * @param {Map} accountData - * @param {Object} crossSigningKeys - * @param {Object} keyBackupInfo - * @param {Object} keySignatures */ public constructor( private readonly accountData: Map, @@ -201,7 +184,6 @@ export class EncryptionSetupOperation { /** * Runs the (remaining part of, in the future) operation by sending requests to the server. - * @param {Crypto} crypto */ public async apply(crypto: Crypto): Promise { const baseApis = crypto.baseApis; @@ -270,23 +252,21 @@ class AccountDataClientAdapter public readonly values = new Map(); /** - * @param {Object.} existingValues existing account data + * @param existingValues - existing account data */ public constructor(private readonly existingValues: Record) { super(); } /** - * @param {String} type - * @return {Promise} the content of the account data + * @returns the content of the account data */ public getAccountDataFromServer(type: string): Promise { return Promise.resolve(this.getAccountData(type) as T); } /** - * @param {String} type - * @return {Object} the content of the account data + * @returns the content of the account data */ public getAccountData(type: string): IContent | null { const modifiedValue = this.values.get(type); @@ -300,11 +280,6 @@ class AccountDataClientAdapter return null; } - /** - * @param {String} type - * @param {Object} content - * @return {Promise} - */ public setAccountData(type: string, content: any): Promise<{}> { const lastEvent = this.values.get(type); this.values.set(type, content); diff --git a/src/crypto/OlmDevice.ts b/src/crypto/OlmDevice.ts index 13463ef11..d7d62099d 100644 --- a/src/crypto/OlmDevice.ts +++ b/src/crypto/OlmDevice.ts @@ -53,43 +53,22 @@ function checkPayloadLength(payloadString: string): void { } } -/** - * The type of object we use for importing and exporting megolm session data. - * - * @typedef {Object} module:crypto/OlmDevice.MegolmSessionData - * @property {String} sender_key Sender's Curve25519 device key - * @property {String[]} forwarding_curve25519_key_chain Devices which forwarded - * this session to us (normally empty). - * @property {Object} sender_claimed_keys Other keys the sender claims. - * @property {String} room_id Room this session is used in - * @property {String} session_id Unique id for the session - * @property {String} session_key Base64'ed key data - */ - interface IInitOpts { fromExportedDevice?: IExportedDevice; pickleKey?: string; } -/** - * data stored in the session store about an inbound group session - * - * @typedef {Object} InboundGroupSessionData - * @property {string} room_id - * @property {string} session pickled Olm.InboundGroupSession - * @property {Object} keysClaimed - * @property {Array} forwardingCurve25519KeyChain Devices involved in forwarding - * this session to us (normally empty). - * @property {boolean=} untrusted whether this session is untrusted. - * @property {boolean=} sharedHistory whether this session exists during the room being set to shared history. - */ - +/** data stored in the session store about an inbound group session */ export interface InboundGroupSessionData { room_id: string; // eslint-disable-line camelcase + /** pickled Olm.InboundGroupSession */ session: string; keysClaimed: Record; + /** Devices involved in forwarding this session to us (normally empty). */ forwardingCurve25519KeyChain: string[]; + /** whether this session is untrusted. */ untrusted?: boolean; + /** whether this session exists during the room being set to shared history. */ sharedHistory?: boolean; } @@ -134,20 +113,13 @@ type OneTimeKeys = { curve25519: { [keyId: string]: string } }; * OlmAccount and a number of OlmSessions. * * Accounts and sessions are kept pickled in the cryptoStore. - * - * @constructor - * @alias module:crypto/OlmDevice - * - * @param {Object} cryptoStore A store for crypto data - * - * @property {string} deviceCurve25519Key Curve25519 key for the account - * @property {string} deviceEd25519Key Ed25519 key for the account */ export class OlmDevice { public pickleKey = "DEFAULT_KEY"; // set by consumers - // don't know these until we load the account from storage in init() + /** Curve25519 key for the account, unknown until we load the account from storage in init() */ public deviceCurve25519Key: string | null = null; + /** Ed25519 key for the account, unknown until we load the account from storage in init() */ public deviceEd25519Key: string | null = null; private maxOneTimeKeys: number | null = null; @@ -184,7 +156,7 @@ export class OlmDevice { } /** - * @return {array} The version of Olm. + * @returns The version of Olm. */ public static getOlmVersion(): [number, number, number] { return global.Olm.get_library_version(); @@ -202,12 +174,11 @@ export class OlmDevice { * * Reads the device keys from the OlmAccount object. * - * @param {object} opts - * @param {object} opts.fromExportedDevice (Optional) data from exported device + * @param fromExportedDevice - (Optional) data from exported device * that must be re-created. * If present, opts.pickleKey is ignored * (exported data already provides a pickle key) - * @param {object} opts.pickleKey (Optional) pickle key to set instead of default one + * @param pickleKey - (Optional) pickle key to set instead of default one */ public async init({ pickleKey, fromExportedDevice }: IInitOpts = {}): Promise { let e2eKeys; @@ -245,9 +216,9 @@ export class OlmDevice { * Note that for now only the “account” and “sessions” stores are populated; * Other stores will be as with a new device. * - * @param {IExportedDevice} exportedData Data exported from another device + * @param exportedData - Data exported from another device * through the “export” method. - * @param {Olm.Account} account an olm account to initialize + * @param account - an olm account to initialize */ private async initialiseFromExportedDevice(exportedData: IExportedDevice, account: Account): Promise { await this.cryptoStore.doTxn( @@ -305,9 +276,8 @@ export class OlmDevice { * This function requires a live transaction object from cryptoStore.doTxn() * and therefore may only be called in a doTxn() callback. * - * @param {*} txn Opaque transaction object from cryptoStore.doTxn() - * @param {function} func - * @private + * @param txn - Opaque transaction object from cryptoStore.doTxn() + * @internal */ private getAccount(txn: unknown, func: (account: Account) => void): void { this.cryptoStore.getAccount(txn, (pickledAccount: string | null) => { @@ -326,9 +296,9 @@ export class OlmDevice { * This function requires a live transaction object from cryptoStore.doTxn() * and therefore may only be called in a doTxn() callback. * - * @param {*} txn Opaque transaction object from cryptoStore.doTxn() - * @param {object} Olm.Account object - * @private + * @param txn - Opaque transaction object from cryptoStore.doTxn() + * @param Olm.Account object + * @internal */ private storeAccount(txn: unknown, account: Account): void { this.cryptoStore.storeAccount(txn, account.pickle(this.pickleKey)); @@ -338,7 +308,7 @@ export class OlmDevice { * Export data for re-creating the Olm device later. * TODO export data other than just account and (P2P) sessions. * - * @return {Promise} The exported data + * @returns The exported data */ public async export(): Promise { const result: Partial = { @@ -373,11 +343,8 @@ export class OlmDevice { * function and will be freed as soon the callback returns. It is *not* * usable for the rest of the lifetime of the transaction. * - * @param {string} deviceKey - * @param {string} sessionId - * @param {*} txn Opaque transaction object from cryptoStore.doTxn() - * @param {function} func - * @private + * @param txn - Opaque transaction object from cryptoStore.doTxn() + * @internal */ private getSession( deviceKey: string, @@ -397,9 +364,7 @@ export class OlmDevice { * function with it. The session object is destroyed once the function * returns. * - * @param {object} sessionInfo - * @param {function} func - * @private + * @internal */ private unpickleSession( sessionInfo: ISessionInfo, @@ -419,10 +384,9 @@ export class OlmDevice { /** * store our OlmSession in the session store * - * @param {string} deviceKey - * @param {object} sessionInfo {session: OlmSession, lastReceivedMessageTs: int} - * @param {*} txn Opaque transaction object from cryptoStore.doTxn() - * @private + * @param sessionInfo - `{session: OlmSession, lastReceivedMessageTs: int}` + * @param txn - Opaque transaction object from cryptoStore.doTxn() + * @internal */ private saveSession(deviceKey: string, sessionInfo: IUnpickledSessionInfo, txn: unknown): void { const sessionId = sessionInfo.session.session_id(); @@ -435,9 +399,8 @@ export class OlmDevice { /** * get an OlmUtility and call the given function * - * @param {function} func - * @return {object} result of func - * @private + * @returns result of func + * @internal */ private getUtility(func: (utility: Utility) => T): T { const utility = new global.Olm.Utility(); @@ -451,8 +414,8 @@ export class OlmDevice { /** * Signs a message with the ed25519 key for this account. * - * @param {string} message message to be signed - * @return {Promise} base64-encoded signature + * @param message - message to be signed + * @returns base64-encoded signature */ public async sign(message: string): Promise { let result: string; @@ -469,7 +432,7 @@ export class OlmDevice { /** * Get the current (unused, unpublished) one-time keys for this account. * - * @return {object} one time keys; an object with the single property + * @returns one time keys; an object with the single property * curve25519, which is itself an object mapping key id to Curve25519 * key. */ @@ -490,7 +453,7 @@ export class OlmDevice { /** * Get the maximum number of one-time keys we can store. * - * @return {number} number of keys + * @returns number of keys */ public maxNumberOfOneTimeKeys(): number { return this.maxOneTimeKeys ?? -1; @@ -514,8 +477,8 @@ export class OlmDevice { /** * Generate some new one-time keys * - * @param {number} numKeys number of keys to generate - * @return {Promise} Resolved once the account is saved back having generated the keys + * @param numKeys - number of keys to generate + * @returns Resolved once the account is saved back having generated the keys */ public generateOneTimeKeys(numKeys: number): Promise { return this.cryptoStore.doTxn( @@ -532,7 +495,7 @@ export class OlmDevice { /** * Generate a new fallback keys * - * @return {Promise} Resolved once the account is saved back having generated the key + * @returns Resolved once the account is saved back having generated the key */ public async generateFallbackKey(): Promise { await this.cryptoStore.doTxn( @@ -576,9 +539,9 @@ export class OlmDevice { * * The new session will be stored in the cryptoStore. * - * @param {string} theirIdentityKey remote user's Curve25519 identity key - * @param {string} theirOneTimeKey remote user's one-time Curve25519 key - * @return {string} sessionId for the outbound session. + * @param theirIdentityKey - remote user's Curve25519 identity key + * @param theirOneTimeKey - remote user's one-time Curve25519 key + * @returns sessionId for the outbound session. */ public async createOutboundSession(theirIdentityKey: string, theirOneTimeKey: string): Promise { let newSessionId: string; @@ -615,15 +578,14 @@ export class OlmDevice { /** * Generate a new inbound session, given an incoming message * - * @param {string} theirDeviceIdentityKey remote user's Curve25519 identity key - * @param {number} messageType messageType field from the received message (must be 0) - * @param {string} ciphertext base64-encoded body from the received message + * @param theirDeviceIdentityKey - remote user's Curve25519 identity key + * @param messageType - messageType field from the received message (must be 0) + * @param ciphertext - base64-encoded body from the received message * - * @return {{payload: string, session_id: string}} decrypted payload, and + * @returns decrypted payload, and * session id of new session * - * @raises {Error} if the received message was not valid (for instance, it - * didn't use a valid one-time key). + * @throws Error if the received message was not valid (for instance, it didn't use a valid one-time key). */ public async createInboundSession( theirDeviceIdentityKey: string, @@ -676,9 +638,9 @@ export class OlmDevice { /** * Get a list of known session IDs for the given device * - * @param {string} theirDeviceIdentityKey Curve25519 identity key for the + * @param theirDeviceIdentityKey - Curve25519 identity key for the * remote device - * @return {Promise} a list of known session ids for the device + * @returns a list of known session ids for the device */ public async getSessionIdsForDevice(theirDeviceIdentityKey: string): Promise { const log = logger.withPrefix("[getSessionIdsForDevice]"); @@ -711,13 +673,13 @@ export class OlmDevice { /** * Get the right olm session id for encrypting messages to the given identity key * - * @param {string} theirDeviceIdentityKey Curve25519 identity key for the + * @param theirDeviceIdentityKey - Curve25519 identity key for the * remote device - * @param {boolean} nowait Don't wait for an in-progress session to complete. + * @param nowait - Don't wait for an in-progress session to complete. * This should only be set to true of the calling function is the function * that marked the session as being in-progress. - * @param {PrefixedLogger} [log] A possibly customised log - * @return {Promise} session id, or null if no established session + * @param log - A possibly customised log + * @returns session id, or null if no established session */ public async getSessionIdForDevice( theirDeviceIdentityKey: string, @@ -759,12 +721,11 @@ export class OlmDevice { * the keys 'hasReceivedMessage' (true if the session has received an incoming * message and is therefore past the pre-key stage), and 'sessionId'. * - * @param {string} deviceIdentityKey Curve25519 identity key for the device - * @param {boolean} nowait Don't wait for an in-progress session to complete. + * @param deviceIdentityKey - Curve25519 identity key for the device + * @param nowait - Don't wait for an in-progress session to complete. * This should only be set to true of the calling function is the function * that marked the session as being in-progress. - * @param {Logger} [log] A possibly customised log - * @return {Array.<{sessionId: string, hasReceivedMessage: boolean}>} + * @param log - A possibly customised log */ public async getSessionInfoForDevice( deviceIdentityKey: string, @@ -813,12 +774,12 @@ export class OlmDevice { /** * Encrypt an outgoing message using an existing session * - * @param {string} theirDeviceIdentityKey Curve25519 identity key for the + * @param theirDeviceIdentityKey - Curve25519 identity key for the * remote device - * @param {string} sessionId the id of the active session - * @param {string} payloadString payload to be encrypted and sent + * @param sessionId - the id of the active session + * @param payloadString - payload to be encrypted and sent * - * @return {Promise} ciphertext + * @returns ciphertext */ public async encryptMessage( theirDeviceIdentityKey: string, @@ -849,13 +810,13 @@ export class OlmDevice { /** * Decrypt an incoming message using an existing session * - * @param {string} theirDeviceIdentityKey Curve25519 identity key for the + * @param theirDeviceIdentityKey - Curve25519 identity key for the * remote device - * @param {string} sessionId the id of the active session - * @param {number} messageType messageType field from the received message - * @param {string} ciphertext base64-encoded body from the received message + * @param sessionId - the id of the active session + * @param messageType - messageType field from the received message + * @param ciphertext - base64-encoded body from the received message * - * @return {Promise} decrypted payload. + * @returns decrypted payload. */ public async decryptMessage( theirDeviceIdentityKey: string, @@ -886,13 +847,13 @@ export class OlmDevice { /** * Determine if an incoming messages is a prekey message matching an existing session * - * @param {string} theirDeviceIdentityKey Curve25519 identity key for the + * @param theirDeviceIdentityKey - Curve25519 identity key for the * remote device - * @param {string} sessionId the id of the active session - * @param {number} messageType messageType field from the received message - * @param {string} ciphertext base64-encoded body from the received message + * @param sessionId - the id of the active session + * @param messageType - messageType field from the received message + * @param ciphertext - base64-encoded body from the received message * - * @return {Promise} true if the received message is a prekey message which matches + * @returns true if the received message is a prekey message which matches * the given session. */ public async matchesSession( @@ -937,8 +898,7 @@ export class OlmDevice { /** * store an OutboundGroupSession in outboundGroupSessionStore * - * @param {Olm.OutboundGroupSession} session - * @private + * @internal */ private saveOutboundGroupSession(session: OutboundGroupSession): void { this.outboundGroupSessionStore[session.session_id()] = session.pickle(this.pickleKey); @@ -948,10 +908,8 @@ export class OlmDevice { * extract an OutboundGroupSession from outboundGroupSessionStore and call the * given function * - * @param {string} sessionId - * @param {function} func - * @return {object} result of func - * @private + * @returns result of func + * @internal */ private getOutboundGroupSession(sessionId: string, func: (session: OutboundGroupSession) => T): T { const pickled = this.outboundGroupSessionStore[sessionId]; @@ -971,7 +929,7 @@ export class OlmDevice { /** * Generate a new outbound group session * - * @return {string} sessionId for the outbound session. + * @returns sessionId for the outbound session. */ public createOutboundGroupSession(): string { const session = new global.Olm.OutboundGroupSession(); @@ -987,10 +945,10 @@ export class OlmDevice { /** * Encrypt an outgoing message with an outbound group session * - * @param {string} sessionId the id of the outboundgroupsession - * @param {string} payloadString payload to be encrypted and sent + * @param sessionId - the id of the outboundgroupsession + * @param payloadString - payload to be encrypted and sent * - * @return {string} ciphertext + * @returns ciphertext */ public encryptGroupMessage(sessionId: string, payloadString: string): string { logger.log(`encrypting msg with megolm session ${sessionId}`); @@ -1007,9 +965,9 @@ export class OlmDevice { /** * Get the session keys for an outbound group session * - * @param {string} sessionId the id of the outbound group session + * @param sessionId - the id of the outbound group session * - * @return {{chain_index: number, key: string}} current chain index, and + * @returns current chain index, and * base64-encoded secret key. */ public getOutboundGroupSessionKey(sessionId: string): IOutboundGroupSessionKey { @@ -1028,9 +986,9 @@ export class OlmDevice { * Unpickle a session from a sessionData object and invoke the given function. * The session is valid only until func returns. * - * @param {Object} sessionData Object describing the session. - * @param {function(Olm.InboundGroupSession)} func Invoked with the unpickled session - * @return {*} result of func + * @param sessionData - Object describing the session. + * @param func - Invoked with the unpickled session + * @returns result of func */ private unpickleInboundGroupSession( sessionData: InboundGroupSessionData, @@ -1048,15 +1006,12 @@ export class OlmDevice { /** * extract an InboundGroupSession from the crypto store and call the given function * - * @param {string} roomId The room ID to extract the session for, or null to fetch + * @param roomId - The room ID to extract the session for, or null to fetch * sessions for any room. - * @param {string} senderKey - * @param {string} sessionId - * @param {*} txn Opaque transaction object from cryptoStore.doTxn() - * @param {function(Olm.InboundGroupSession, InboundGroupSessionData)} func - * function to call. + * @param txn - Opaque transaction object from cryptoStore.doTxn() + * @param func - function to call. * - * @private + * @internal */ private getInboundGroupSession( roomId: string, @@ -1095,16 +1050,16 @@ export class OlmDevice { /** * Add an inbound group session to the session store * - * @param {string} roomId room in which this session will be used - * @param {string} senderKey base64-encoded curve25519 key of the sender - * @param {Array} forwardingCurve25519KeyChain Devices involved in forwarding + * @param roomId - room in which this session will be used + * @param senderKey - base64-encoded curve25519 key of the sender + * @param forwardingCurve25519KeyChain - Devices involved in forwarding * this session to us. - * @param {string} sessionId session identifier - * @param {string} sessionKey base64-encoded secret key - * @param {Object} keysClaimed Other keys the sender claims. - * @param {boolean} exportFormat true if the megolm keys are in export format + * @param sessionId - session identifier + * @param sessionKey - base64-encoded secret key + * @param keysClaimed - Other keys the sender claims. + * @param exportFormat - true if the megolm keys are in export format * (ie, they lack an ed25519 signature) - * @param {Object} [extraSessionData={}] any other data to be include with the session + * @param extraSessionData - any other data to be include with the session */ public async addInboundGroupSession( roomId: string, @@ -1216,11 +1171,11 @@ export class OlmDevice { /** * Record in the data store why an inbound group session was withheld. * - * @param {string} roomId room that the session belongs to - * @param {string} senderKey base64-encoded curve25519 key of the sender - * @param {string} sessionId session identifier - * @param {string} code reason code - * @param {string} reason human-readable version of `code` + * @param roomId - room that the session belongs to + * @param senderKey - base64-encoded curve25519 key of the sender + * @param sessionId - session identifier + * @param code - reason code + * @param reason - human-readable version of `code` */ public async addInboundGroupSessionWithheld( roomId: string, @@ -1248,18 +1203,14 @@ export class OlmDevice { /** * Decrypt a received message with an inbound group session * - * @param {string} roomId room in which the message was received - * @param {string} senderKey base64-encoded curve25519 key of the sender - * @param {string} sessionId session identifier - * @param {string} body base64-encoded body of the encrypted message - * @param {string} eventId ID of the event being decrypted - * @param {Number} timestamp timestamp of the event being decrypted + * @param roomId - room in which the message was received + * @param senderKey - base64-encoded curve25519 key of the sender + * @param sessionId - session identifier + * @param body - base64-encoded body of the encrypted message + * @param eventId - ID of the event being decrypted + * @param timestamp - timestamp of the event being decrypted * - * @return {null} the sessionId is unknown - * - * @return {Promise<{result: string, senderKey: string, - * forwardingCurve25519KeyChain: Array, - * keysClaimed: Object}>} + * @returns null if the sessionId is unknown */ public async decryptGroupMessage( roomId: string, @@ -1375,11 +1326,11 @@ export class OlmDevice { /** * Determine if we have the keys for a given megolm session * - * @param {string} roomId room in which the message was received - * @param {string} senderKey base64-encoded curve25519 key of the sender - * @param {string} sessionId session identifier + * @param roomId - room in which the message was received + * @param senderKey - base64-encoded curve25519 key of the sender + * @param sessionId - session identifier * - * @returns {Promise} true if we have the keys to this session + * @returns true if we have the keys to this session */ public async hasInboundSessionKeys(roomId: string, senderKey: string, sessionId: string): Promise { let result: boolean; @@ -1418,16 +1369,13 @@ export class OlmDevice { /** * Extract the keys to a given megolm session, for sharing * - * @param {string} roomId room in which the message was received - * @param {string} senderKey base64-encoded curve25519 key of the sender - * @param {string} sessionId session identifier - * @param {number} chainIndex The chain index at which to export the session. + * @param roomId - room in which the message was received + * @param senderKey - base64-encoded curve25519 key of the sender + * @param sessionId - session identifier + * @param chainIndex - The chain index at which to export the session. * If omitted, export at the first index we know about. * - * @returns {Promise<{chain_index: number, key: string, - * forwarding_curve25519_key_chain: Array, - * sender_claimed_ed25519_key: string - * }>} + * @returns * details of the session key. The key is a base64-encoded megolm key in * export format. * @@ -1492,10 +1440,10 @@ export class OlmDevice { /** * Export an inbound group session * - * @param {string} senderKey base64-encoded curve25519 key of the sender - * @param {string} sessionId session identifier - * @param {ISessionInfo} sessionData The session object from the store - * @return {module:crypto/OlmDevice.MegolmSessionData} exported session data + * @param senderKey - base64-encoded curve25519 key of the sender + * @param sessionId - session identifier + * @param sessionData - The session object from the store + * @returns exported session data */ public exportInboundGroupSession( senderKey: string, @@ -1539,11 +1487,11 @@ export class OlmDevice { /** * Verify an ed25519 signature. * - * @param {string} key ed25519 key - * @param {string} message message which was signed - * @param {string} signature base64-encoded signature to be checked + * @param key - ed25519 key + * @param message - message which was signed + * @param signature - base64-encoded signature to be checked * - * @raises {Error} if there is a problem with the verification. If the key was + * @throws Error if there is a problem with the verification. If the key was * too small then the message will be "OLM.INVALID_BASE64". If the signature * was invalid then the message will be "OLM.BAD_MESSAGE_MAC". */ @@ -1568,11 +1516,11 @@ export const WITHHELD_MESSAGES: Record = { /** * Calculate the message to use for the exception when a session key is withheld. * - * @param {object} withheld An object that describes why the key was withheld. + * @param withheld - An object that describes why the key was withheld. * - * @return {string} the message + * @returns the message * - * @private + * @internal */ function calculateWithheldMessage(withheld: IWithheld): string { if (withheld.code && withheld.code in WITHHELD_MESSAGES) { diff --git a/src/crypto/OutgoingRoomKeyRequestManager.ts b/src/crypto/OutgoingRoomKeyRequestManager.ts index cb93851b9..833592a4c 100644 --- a/src/crypto/OutgoingRoomKeyRequestManager.ts +++ b/src/crypto/OutgoingRoomKeyRequestManager.ts @@ -27,17 +27,17 @@ import { EventType, ToDeviceMessageId } from "../@types/event"; * * See https://docs.google.com/document/d/1m4gQkcnJkxNuBmb5NoFCIadIY-DyqqNAS3lloE73BlQ * for draft documentation on what we're supposed to be implementing here. - * - * @module */ // delay between deciding we want some keys, and sending out the request, to // allow for (a) it turning up anyway, (b) grouping requests together const SEND_KEY_REQUESTS_DELAY_MS = 500; -/** possible states for a room key request +/** + * possible states for a room key request * * The state machine looks like: + * ``` * * | (cancellation sent) * | .-------------------------------------------------. @@ -60,8 +60,7 @@ const SEND_KEY_REQUESTS_DELAY_MS = 500; * | (cancellation sent) | * V | * (deleted) <---------------------------+ - * - * @enum {number} + * ``` */ export enum RoomKeyRequestState { /** request not yet sent */ @@ -134,12 +133,10 @@ export class OutgoingRoomKeyRequestManager { * Otherwise, a request is added to the pending list, and a job is started * in the background to send it. * - * @param {module:crypto~RoomKeyRequestBody} requestBody - * @param {Array<{userId: string, deviceId: string}>} recipients - * @param {boolean} resend whether to resend the key request if there is + * @param resend - whether to resend the key request if there is * already one * - * @returns {Promise} resolves when the request has been added to the + * @returns resolves when the request has been added to the * pending list (or we have established that a similar request already * exists) */ @@ -239,9 +236,8 @@ export class OutgoingRoomKeyRequestManager { /** * Cancel room key requests, if any match the given requestBody * - * @param {module:crypto~RoomKeyRequestBody} requestBody * - * @returns {Promise} resolves when the request has been updated in our + * @returns resolves when the request has been updated in our * pending list. */ public cancelRoomKeyRequest(requestBody: IRoomKeyRequestBody): Promise { @@ -324,11 +320,10 @@ export class OutgoingRoomKeyRequestManager { /** * Look for room key requests by target device and state * - * @param {string} userId Target user ID - * @param {string} deviceId Target device ID + * @param userId - Target user ID + * @param deviceId - Target device ID * - * @return {Promise} resolves to a list of all the - * {@link module:crypto/store/base~OutgoingRoomKeyRequest} + * @returns resolves to a list of all the {@link OutgoingRoomKeyRequest} */ public getOutgoingSentRoomKeyRequest(userId: string, deviceId: string): Promise { return this.cryptoStore.getOutgoingRoomKeyRequestsByTarget(userId, deviceId, [RoomKeyRequestState.Sent]); @@ -339,7 +334,7 @@ export class OutgoingRoomKeyRequestManager { * This is intended for situations where something substantial has changed, and we * don't really expect the other end to even care about the cancellation. * For example, after initialization or self-verification. - * @return {Promise} An array of `queueRoomKeyRequest` outputs. + * @returns An array of `queueRoomKeyRequest` outputs. */ public async cancelAndResendAllOutgoingRequests(): Promise { const outgoings = await this.cryptoStore.getAllOutgoingRoomKeyRequestsByState(RoomKeyRequestState.Sent); diff --git a/src/crypto/RoomList.ts b/src/crypto/RoomList.ts index 672ef473c..2f5233bd2 100644 --- a/src/crypto/RoomList.ts +++ b/src/crypto/RoomList.ts @@ -15,8 +15,6 @@ limitations under the License. */ /** - * @module crypto/RoomList - * * Manages the list of encrypted rooms */ @@ -31,9 +29,6 @@ export interface IRoomEncryption { } /* eslint-enable camelcase */ -/** - * @alias module:crypto/RoomList - */ export class RoomList { // Object of roomId -> room e2e info object (body of the m.room.encryption event) private roomEncryption: Record = {}; diff --git a/src/crypto/SecretStorage.ts b/src/crypto/SecretStorage.ts index 54702034f..921207c4a 100644 --- a/src/crypto/SecretStorage.ts +++ b/src/crypto/SecretStorage.ts @@ -66,7 +66,6 @@ interface ISecretInfo { /** * Implements Secure Secret Storage and Sharing (MSC1946) - * @module crypto/SecretStorage */ export class SecretStorage { private requests = new Map(); @@ -119,15 +118,15 @@ export class SecretStorage { /** * Add a key for encrypting secrets. * - * @param {string} algorithm the algorithm used by the key. - * @param {object} opts the options for the algorithm. The properties used + * @param algorithm - the algorithm used by the key. + * @param opts - the options for the algorithm. The properties used * depend on the algorithm given. - * @param {string} [keyId] the ID of the key. If not given, a random + * @param keyId - the ID of the key. If not given, a random * ID will be generated. * - * @return {object} An object with: - * keyId: {string} the ID of the key - * keyInfo: {object} details about the key (iv, mac, passphrase) + * @returns An object with: + * keyId: the ID of the key + * keyInfo: details about the key (iv, mac, passphrase) */ public async addKey( algorithm: string, @@ -176,9 +175,9 @@ export class SecretStorage { /** * Get the key information for a given ID. * - * @param {string} [keyId = default key's ID] The ID of the key to check + * @param keyId - The ID of the key to check * for. Defaults to the default key ID if not provided. - * @returns {Array?} If the key was found, the return value is an array of + * @returns If the key was found, the return value is an array of * the form [keyId, keyInfo]. Otherwise, null is returned. * XXX: why is this an array when addKey returns an object? */ @@ -199,9 +198,9 @@ export class SecretStorage { /** * Check whether we have a key with a given ID. * - * @param {string} [keyId = default key's ID] The ID of the key to check + * @param keyId - The ID of the key to check * for. Defaults to the default key ID if not provided. - * @return {boolean} Whether we have the key. + * @returns Whether we have the key. */ public async hasKey(keyId?: string): Promise { return Boolean(await this.getKey(keyId)); @@ -210,10 +209,10 @@ export class SecretStorage { /** * Check whether a key matches what we expect based on the key info * - * @param {Uint8Array} key the key to check - * @param {object} info the key info + * @param key - the key to check + * @param info - the key info * - * @return {boolean} whether or not the key matches + * @returns whether or not the key matches */ public async checkKey(key: Uint8Array, info: ISecretStorageKeyInfo): Promise { if (info.algorithm === SECRET_STORAGE_ALGORITHM_V1_AES) { @@ -232,9 +231,9 @@ export class SecretStorage { /** * Store an encrypted secret on the server * - * @param {string} name The name of the secret - * @param {string} secret The secret contents. - * @param {Array} keys The IDs of the keys to use to encrypt the secret + * @param name - The name of the secret + * @param secret - The secret contents. + * @param keys - The IDs of the keys to use to encrypt the secret * or null/undefined to use the default key. */ public async store(name: string, secret: string, keys?: string[] | null): Promise { @@ -280,9 +279,9 @@ export class SecretStorage { /** * Get a secret from storage. * - * @param {string} name the name of the secret + * @param name - the name of the secret * - * @return {string} the contents of the secret + * @returns the contents of the secret */ public async get(name: string): Promise { const secretInfo = await this.accountDataAdapter.getAccountDataFromServer(name); @@ -326,9 +325,9 @@ export class SecretStorage { /** * Check if a secret is stored on the server. * - * @param {string} name the name of the secret + * @param name - the name of the secret * - * @return {object?} map of key name to key info the secret is encrypted + * @returns map of key name to key info the secret is encrypted * with, or null if it is not present or not encrypted with a trusted * key */ @@ -361,8 +360,8 @@ export class SecretStorage { /** * Request a secret from another device * - * @param {string} name the name of the secret to request - * @param {string[]} devices the devices to request the secret from + * @param name - the name of the secret to request + * @param devices - the devices to request the secret from */ public request(this: SecretStorage, name: string, devices: string[]): ISecretRequest { const requestId = this.baseApis.makeTxnId(); diff --git a/src/crypto/aes.ts b/src/crypto/aes.ts index 33971e634..da5464834 100644 --- a/src/crypto/aes.ts +++ b/src/crypto/aes.ts @@ -22,18 +22,21 @@ const zeroSalt = new Uint8Array(8); export interface IEncryptedPayload { [key: string]: any; // extensible + /** the initialization vector in base64 */ iv: string; + /** the ciphertext in base64 */ ciphertext: string; + /** the HMAC in base64 */ mac: string; } /** * encrypt a string * - * @param {string} data the plaintext to encrypt - * @param {Uint8Array} key the encryption key to use - * @param {string} name the name of the secret - * @param {string} ivStr the initialization vector to use + * @param data - the plaintext to encrypt + * @param key - the encryption key to use + * @param name - the name of the secret + * @param ivStr - the initialization vector to use */ export async function encryptAES( data: string, @@ -83,12 +86,9 @@ export async function encryptAES( /** * decrypt a string * - * @param {object} data the encrypted data - * @param {string} data.ciphertext the ciphertext in base64 - * @param {string} data.iv the initialization vector in base64 - * @param {string} data.mac the HMAC in base64 - * @param {Uint8Array} key the encryption key to use - * @param {string} name the name of the secret + * @param data - the encrypted data + * @param key - the encryption key to use + * @param name - the name of the secret */ export async function decryptAES(data: IEncryptedPayload, key: Uint8Array, name: string): Promise { const [aesKey, hmacKey] = await deriveKeys(key, name); @@ -168,10 +168,10 @@ const ZERO_STR = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 /** Calculate the MAC for checking the key. * - * @param {Uint8Array} key the key to use - * @param {string} [iv] The initialization vector as a base64-encoded string. + * @param key - the key to use + * @param iv - The initialization vector as a base64-encoded string. * If omitted, a random initialization vector will be created. - * @return {Promise} An object that contains, `mac` and `iv` properties. + * @returns An object that contains, `mac` and `iv` properties. */ export function calculateKeyCheck(key: Uint8Array, iv?: string): Promise { return encryptAES(ZERO_STR, key, "", iv); diff --git a/src/crypto/algorithms/base.ts b/src/crypto/algorithms/base.ts index 32b9ab73b..3229ad39b 100644 --- a/src/crypto/algorithms/base.ts +++ b/src/crypto/algorithms/base.ts @@ -16,8 +16,6 @@ limitations under the License. /** * Internal module. Defines the base classes of the encryption implementations - * - * @module */ import { MatrixClient } from "../../client"; @@ -35,46 +33,36 @@ import { DeviceInfo } from "../deviceinfo"; import { IRoomEncryption } from "../RoomList"; /** - * map of registered encryption algorithm classes. A map from string to {@link - * module:crypto/algorithms/base.EncryptionAlgorithm|EncryptionAlgorithm} class - * - * @type {Object.} + * Map of registered encryption algorithm classes. A map from string to {@link EncryptionAlgorithm} class */ export const ENCRYPTION_CLASSES = new Map EncryptionAlgorithm>(); export type DecryptionClassParams

= Omit; /** - * map of registered encryption algorithm classes. Map from string to {@link - * module:crypto/algorithms/base.DecryptionAlgorithm|DecryptionAlgorithm} class - * - * @type {Object.} + * map of registered encryption algorithm classes. Map from string to {@link DecryptionAlgorithm} class */ export const DECRYPTION_CLASSES = new Map DecryptionAlgorithm>(); export interface IParams { + /** The UserID for the local user */ userId: string; + /** The identifier for this device. */ deviceId: string; + /** crypto core */ crypto: Crypto; + /** olm.js wrapper */ olmDevice: OlmDevice; + /** base matrix api interface */ baseApis: MatrixClient; + /** The ID of the room we will be sending to */ roomId?: string; + /** The body of the m.room.encryption event */ config: IRoomEncryption & object; } /** * base type for encryption implementations - * - * @alias module:crypto/algorithms/base.EncryptionAlgorithm - * - * @param {object} params parameters - * @param {string} params.userId The UserID for the local user - * @param {string} params.deviceId The identifier for this device. - * @param {module:crypto} params.crypto crypto core - * @param {module:crypto/OlmDevice} params.olmDevice olm.js wrapper - * @param {MatrixClient} baseApis base matrix api interface - * @param {string} params.roomId The ID of the room we will be sending to - * @param {object} params.config The body of the m.room.encryption event */ export abstract class EncryptionAlgorithm { protected readonly userId: string; @@ -84,6 +72,9 @@ export abstract class EncryptionAlgorithm { protected readonly baseApis: MatrixClient; protected readonly roomId?: string; + /** + * @param params - parameters + */ public constructor(params: IParams) { this.userId = params.userId; this.deviceId = params.deviceId; @@ -97,33 +88,28 @@ export abstract class EncryptionAlgorithm { * Perform any background tasks that can be done before a message is ready to * send, in order to speed up sending of the message. * - * @param {module:models/room} room the room the event is in + * @param room - the room the event is in */ public prepareToEncrypt(room: Room): void {} /** * Encrypt a message event * - * @method module:crypto/algorithms/base.EncryptionAlgorithm.encryptMessage * @public - * @abstract * - * @param {module:models/room} room - * @param {string} eventType - * @param {object} content event content + * @param content - event content * - * @return {Promise} Promise which resolves to the new event body + * @returns Promise which resolves to the new event body */ public abstract encryptMessage(room: Room, eventType: string, content: IContent): Promise; /** * Called when the membership of a member of the room changes. * - * @param {module:models/event.MatrixEvent} event event causing the change - * @param {module:models/room-member} member user whose membership changed - * @param {string=} oldMembership previous membership + * @param event - event causing the change + * @param member - user whose membership changed + * @param oldMembership - previous membership * @public - * @abstract */ public onRoomMembership(event: MatrixEvent, member: RoomMember, oldMembership?: string): void {} @@ -139,15 +125,6 @@ export abstract class EncryptionAlgorithm { /** * base type for decryption implementations - * - * @alias module:crypto/algorithms/base.DecryptionAlgorithm - * @param {object} params parameters - * @param {string} params.userId The UserID for the local user - * @param {module:crypto} params.crypto crypto core - * @param {module:crypto/OlmDevice} params.olmDevice olm.js wrapper - * @param {MatrixClient} baseApis base matrix api interface - * @param {string=} params.roomId The ID of the room we will be receiving - * from. Null for to-device events. */ export abstract class DecryptionAlgorithm { protected readonly userId: string; @@ -167,12 +144,9 @@ export abstract class DecryptionAlgorithm { /** * Decrypt an event * - * @method module:crypto/algorithms/base.DecryptionAlgorithm#decryptEvent - * @abstract + * @param event - undecrypted event * - * @param {MatrixEvent} event undecrypted event - * - * @return {Promise} promise which + * @returns promise which * resolves once we have finished decrypting. Rejects with an * `algorithms.DecryptionError` if there is a problem decrypting the event. */ @@ -181,9 +155,7 @@ export abstract class DecryptionAlgorithm { /** * Handle a key event * - * @method module:crypto/algorithms/base.DecryptionAlgorithm#onRoomKeyEvent - * - * @param {module:models/event.MatrixEvent} params event key event + * @param params - event key event */ public async onRoomKeyEvent(params: MatrixEvent): Promise { // ignore by default @@ -192,8 +164,7 @@ export abstract class DecryptionAlgorithm { /** * Import a room key * - * @param {module:crypto/OlmDevice.MegolmSessionData} session - * @param {object} opts object + * @param opts - object */ public async importRoomKey(session: IMegolmSessionData, opts: object): Promise { // ignore by default @@ -202,8 +173,7 @@ export abstract class DecryptionAlgorithm { /** * Determine if we have the keys necessary to respond to a room key request * - * @param {module:crypto~IncomingRoomKeyRequest} keyRequest - * @return {Promise} true if we have the keys and could (theoretically) share + * @returns true if we have the keys and could (theoretically) share * them; else false. */ public hasKeysForKeyRequest(keyRequest: IncomingRoomKeyRequest): Promise { @@ -213,7 +183,6 @@ export abstract class DecryptionAlgorithm { /** * Send the response to a room key request * - * @param {module:crypto~IncomingRoomKeyRequest} keyRequest */ public shareKeysWithDevice(keyRequest: IncomingRoomKeyRequest): void { throw new Error("shareKeysWithDevice not supported for this DecryptionAlgorithm"); @@ -223,7 +192,7 @@ export abstract class DecryptionAlgorithm { * Retry decrypting all the events from a sender that haven't been * decrypted yet. * - * @param {string} senderKey the sender's key + * @param senderKey - the sender's key */ public async retryDecryptionFromSender(senderKey: string): Promise { // ignore by default @@ -237,13 +206,10 @@ export abstract class DecryptionAlgorithm { /** * Exception thrown when decryption fails * - * @alias module:crypto/algorithms/base.DecryptionError - * @param {string} msg user-visible message describing the problem + * @param msg - user-visible message describing the problem * - * @param {Object=} details key/value pairs reported in the logs but not shown + * @param details - key/value pairs reported in the logs but not shown * to the user. - * - * @extends Error */ export class DecryptionError extends Error { public readonly detailedString: string; @@ -268,16 +234,14 @@ function detailedStringForDecryptionError(err: DecryptionError, details?: Record return result; } -/** - * Exception thrown specifically when we want to warn the user to consider - * the security of their conversation before continuing - * - * @param {string} msg message describing the problem - * @param {Object} devices userId -> {deviceId -> object} - * set of unknown devices per user we're warning about - * @extends Error - */ export class UnknownDeviceError extends Error { + /** + * Exception thrown specifically when we want to warn the user to consider + * the security of their conversation before continuing + * + * @param msg - message describing the problem + * @param devices - set of unknown devices per user we're warning about + */ public constructor( msg: string, public readonly devices: Record>, @@ -292,15 +256,11 @@ export class UnknownDeviceError extends Error { /** * Registers an encryption/decryption class for a particular algorithm * - * @param {string} algorithm algorithm tag to register for + * @param algorithm - algorithm tag to register for * - * @param {class} encryptor {@link - * module:crypto/algorithms/base.EncryptionAlgorithm|EncryptionAlgorithm} - * implementation + * @param encryptor - {@link EncryptionAlgorithm} implementation * - * @param {class} decryptor {@link - * module:crypto/algorithms/base.DecryptionAlgorithm|DecryptionAlgorithm} - * implementation + * @param decryptor - {@link DecryptionAlgorithm} implementation */ export function registerAlgorithm

( algorithm: string, diff --git a/src/crypto/algorithms/index.ts b/src/crypto/algorithms/index.ts index 3dd1158a0..b3c5b0ede 100644 --- a/src/crypto/algorithms/index.ts +++ b/src/crypto/algorithms/index.ts @@ -14,10 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/** - * @module crypto/algorithms - */ - import "./olm"; import "./megolm"; diff --git a/src/crypto/algorithms/megolm.ts b/src/crypto/algorithms/megolm.ts index b099ef40a..d995623d4 100644 --- a/src/crypto/algorithms/megolm.ts +++ b/src/crypto/algorithms/megolm.ts @@ -16,8 +16,6 @@ limitations under the License. /** * Defines m.olm encryption/decryption - * - * @module crypto/algorithms/megolm */ import { v4 as uuidv4 } from "uuid"; @@ -123,37 +121,27 @@ interface SharedWithData { } /** - * @private - * @constructor - * - * @param {string} sessionId - * @param {boolean} sharedHistory whether the session can be freely shared with - * other group members, according to the room history visibility settings - * - * @property {string} sessionId - * @property {Number} useCount number of times this session has been used - * @property {Number} creationTime when the session was created (ms since the epoch) - * - * @property {object} sharedWithDevices - * devices with which we have shared the session key - * userId -> {deviceId -> SharedWithData} + * @internal */ class OutboundSessionInfo { + /** number of times this session has been used */ public useCount = 0; + /** when the session was created (ms since the epoch) */ public creationTime: number; + /** devices with which we have shared the session key `userId -> {deviceId -> SharedWithData}` */ public sharedWithDevices: Record> = {}; public blockedDevicesNotified: Record> = {}; + /** + * @param sharedHistory - whether the session can be freely shared with + * other group members, according to the room history visibility settings + */ public constructor(public readonly sessionId: string, public readonly sharedHistory = false) { this.creationTime = new Date().getTime(); } /** * Check if it's time to rotate the session - * - * @param {Number} rotationPeriodMsgs - * @param {Number} rotationPeriodMs - * @return {Boolean} */ public needsRotation(rotationPeriodMsgs: number, rotationPeriodMs: number): boolean { const sessionLifetime = new Date().getTime() - this.creationTime; @@ -189,10 +177,10 @@ class OutboundSessionInfo { * Determine if this session has been shared with devices which it shouldn't * have been. * - * @param {Object} devicesInRoom userId -> {deviceId -> object} + * @param devicesInRoom - `userId -> {deviceId -> object}` * devices we should shared the session with. * - * @return {Boolean} true if we have shared the session with devices which aren't + * @returns true if we have shared the session with devices which aren't * in devicesInRoom. */ public sharedWithTooManyDevices(devicesInRoom: Record>): boolean { @@ -228,11 +216,7 @@ class OutboundSessionInfo { /** * Megolm encryption implementation * - * @constructor - * @extends {module:crypto/algorithms/EncryptionAlgorithm} - * - * @param {object} params parameters, as per - * {@link module:crypto/algorithms/EncryptionAlgorithm} + * @param params - parameters, as per {@link EncryptionAlgorithm} */ export class MegolmEncryption extends EncryptionAlgorithm { // the most recent attempt to set up a session. This is used to serialise @@ -265,15 +249,14 @@ export class MegolmEncryption extends EncryptionAlgorithm { } /** - * @private + * @internal * - * @param {module:models/room} room - * @param {Object} devicesInRoom The devices in this room, indexed by user ID - * @param {Object} blocked The devices that are blocked, indexed by user ID - * @param {boolean} [singleOlmCreationPhase] Only perform one round of olm + * @param devicesInRoom - The devices in this room, indexed by user ID + * @param blocked - The devices that are blocked, indexed by user ID + * @param singleOlmCreationPhase - Only perform one round of olm * session creation * - * @return {Promise} Promise which resolves to the + * @returns Promise which resolves to the * OutboundSessionInfo when setup is complete. */ private async ensureOutboundSession( @@ -488,11 +471,10 @@ export class MegolmEncryption extends EncryptionAlgorithm { } /** - * @private + * @internal * - * @param {boolean} sharedHistory * - * @return {module:crypto/algorithms/megolm.OutboundSessionInfo} session + * @returns session */ private async prepareNewSession(sharedHistory: boolean): Promise { const sessionId = this.olmDevice.createOutboundGroupSession(); @@ -514,15 +496,15 @@ export class MegolmEncryption extends EncryptionAlgorithm { * Determines what devices in devicesByUser don't have an olm session as given * in devicemap. * - * @private + * @internal * - * @param {object} devicemap the devices that have olm sessions, as returned by + * @param devicemap - the devices that have olm sessions, as returned by * olmlib.ensureOlmSessionsForDevices. - * @param {object} devicesByUser a map of user IDs to array of deviceInfo - * @param {array} [noOlmDevices] an array to fill with devices that don't have + * @param devicesByUser - a map of user IDs to array of deviceInfo + * @param noOlmDevices - an array to fill with devices that don't have * olm sessions * - * @return {array} an array of devices that don't have olm sessions. If + * @returns an array of devices that don't have olm sessions. If * noOlmDevices is specified, then noOlmDevices will be returned. */ private getDevicesWithoutSessions( @@ -558,11 +540,11 @@ export class MegolmEncryption extends EncryptionAlgorithm { * Splits the user device map into multiple chunks to reduce the number of * devices we encrypt to per API call. * - * @private + * @internal * - * @param {object} devicesByUser map from userid to list of devices + * @param devicesByUser - map from userid to list of devices * - * @return {array>} the blocked devices, split into chunks + * @returns the blocked devices, split into chunks */ private splitDevices( devicesByUser: Record>, @@ -599,18 +581,16 @@ export class MegolmEncryption extends EncryptionAlgorithm { } /** - * @private + * @internal * - * @param {module:crypto/algorithms/megolm.OutboundSessionInfo} session * - * @param {number} chainIndex current chain index + * @param chainIndex - current chain index * - * @param {object} userDeviceMap - * mapping from userId to deviceInfo + * @param userDeviceMap - mapping from userId to deviceInfo * - * @param {object} payload fields to include in the encrypted payload + * @param payload - fields to include in the encrypted payload * - * @return {Promise} Promise which resolves once the key sharing + * @returns Promise which resolves once the key sharing * for the given userDeviceMap is generated and has been sent. */ private encryptAndSendKeysToDevices( @@ -639,15 +619,14 @@ export class MegolmEncryption extends EncryptionAlgorithm { } /** - * @private + * @internal * - * @param {module:crypto/algorithms/megolm.OutboundSessionInfo} session * - * @param {array} userDeviceMap list of blocked devices to notify + * @param userDeviceMap - list of blocked devices to notify * - * @param {object} payload fields to include in the notification payload + * @param payload - fields to include in the notification payload * - * @return {Promise} Promise which resolves once the notifications + * @returns Promise which resolves once the notifications * for the given userDeviceMap is generated and has been sent. */ private async sendBlockedNotificationsToDevices( @@ -695,10 +674,10 @@ export class MegolmEncryption extends EncryptionAlgorithm { * Re-shares a megolm session key with devices if the key has already been * sent to them. * - * @param {string} senderKey The key of the originating device for the session - * @param {string} sessionId ID of the outbound session to share - * @param {string} userId ID of the user who owns the target device - * @param {module:crypto/deviceinfo} device The target device + * @param senderKey - The key of the originating device for the session + * @param sessionId - ID of the outbound session to share + * @param userId - ID of the user who owns the target device + * @param device - The target device */ public async reshareKeyWithDevice( senderKey: string, @@ -792,26 +771,23 @@ export class MegolmEncryption extends EncryptionAlgorithm { } /** - * @private + * @internal * - * @param {module:crypto/algorithms/megolm.OutboundSessionInfo} session * - * @param {object} key the session key as returned by + * @param key - the session key as returned by * OlmDevice.getOutboundGroupSessionKey * - * @param {object} payload the base to-device message payload for sharing keys + * @param payload - the base to-device message payload for sharing keys * - * @param {object} devicesByUser - * map from userid to list of devices + * @param devicesByUser - map from userid to list of devices * - * @param {array} errorDevices - * array that will be populated with the devices that we can't get an + * @param errorDevices - array that will be populated with the devices that we can't get an * olm session for * - * @param {Number} [otkTimeout] The timeout in milliseconds when requesting + * @param otkTimeout - The timeout in milliseconds when requesting * one-time keys for establishing new olm sessions. * - * @param {Array} [failedServers] An array to fill with remote servers that + * @param failedServers - An array to fill with remote servers that * failed to respond to one-time-key requests. */ private async shareKeyWithDevices( @@ -866,11 +842,9 @@ export class MegolmEncryption extends EncryptionAlgorithm { /** * Notify devices that we weren't able to create olm sessions. * - * @param {module:crypto/algorithms/megolm.OutboundSessionInfo} session * - * @param {object} key * - * @param {Array} failedDevices the devices that we were unable to + * @param failedDevices - the devices that we were unable to * create olm sessions for, as returned by shareKeyWithDevices */ private async notifyFailedOlmDevices( @@ -927,10 +901,8 @@ export class MegolmEncryption extends EncryptionAlgorithm { /** * Notify blocked devices that they have been blocked. * - * @param {module:crypto/algorithms/megolm.OutboundSessionInfo} session * - * @param {object} devicesByUser - * map from userid to device ID to blocked data + * @param devicesByUser - map from userid to device ID to blocked data */ private async notifyBlockedDevices( session: OutboundSessionInfo, @@ -963,7 +935,7 @@ export class MegolmEncryption extends EncryptionAlgorithm { * Perform any background tasks that can be done before a message is ready to * send, in order to speed up sending of the message. * - * @param {module:models/room} room the room the event is in + * @param room - the room the event is in */ public prepareToEncrypt(room: Room): void { if (this.encryptionPreparation != null) { @@ -1008,13 +980,9 @@ export class MegolmEncryption extends EncryptionAlgorithm { } /** - * @inheritdoc + * @param content - plaintext event content * - * @param {module:models/room} room - * @param {string} eventType - * @param {object} content plaintext event content - * - * @return {Promise} Promise which resolves to the new event body + * @returns Promise which resolves to the new event body */ public async encryptMessage(room: Room, eventType: string, content: IContent): Promise { logger.log(`Starting to encrypt event for ${this.roomId}`); @@ -1103,7 +1071,7 @@ export class MegolmEncryption extends EncryptionAlgorithm { * unknown to the user. If so, warn the user, and mark them as known to * give the user a chance to go verify them before re-sending this message. * - * @param {Object} devicesInRoom userId -> {deviceId -> object} + * @param devicesInRoom - `userId -> {deviceId -> object}` * devices we should shared the session with. */ private checkForUnknownDevices(devicesInRoom: DeviceInfoMap): void { @@ -1133,7 +1101,7 @@ export class MegolmEncryption extends EncryptionAlgorithm { * Remove unknown devices from a set of devices. The devicesInRoom parameter * will be modified. * - * @param {Object} devicesInRoom userId -> {deviceId -> object} + * @param devicesInRoom - `userId -> {deviceId -> object}` * devices we should shared the session with. */ private removeUnknownDevices(devicesInRoom: DeviceInfoMap): void { @@ -1153,11 +1121,10 @@ export class MegolmEncryption extends EncryptionAlgorithm { /** * Get the list of unblocked devices for all users in the room * - * @param {module:models/room} room - * @param forceDistributeToUnverified if set to true will include the unverified devices + * @param forceDistributeToUnverified - if set to true will include the unverified devices * even if setting is set to block them (useful for verification) * - * @return {Promise} Promise which resolves to an array whose + * @returns Promise which resolves to an array whose * first element is a map from userId to deviceId to deviceInfo indicating * the devices that messages should be encrypted to, and whose second * element is a map from userId to deviceId to data indicating the devices @@ -1225,11 +1192,7 @@ export class MegolmEncryption extends EncryptionAlgorithm { /** * Megolm decryption implementation * - * @constructor - * @extends {module:crypto/algorithms/DecryptionAlgorithm} - * - * @param {object} params parameters, as per - * {@link module:crypto/algorithms/DecryptionAlgorithm} + * @param params - parameters, as per {@link DecryptionAlgorithm} */ export class MegolmDecryption extends DecryptionAlgorithm { // events which we couldn't decrypt due to unknown sessions / @@ -1248,12 +1211,8 @@ export class MegolmDecryption extends DecryptionAlgorithm { } /** - * @inheritdoc - * - * @param {MatrixEvent} event - * * returns a promise which resolves to a - * {@link module:crypto~EventDecryptionResult} once we have finished + * {@link EventDecryptionResult} once we have finished * decrypting, or rejects with an `algorithms.DecryptionError` if there is a * problem decrypting the event. */ @@ -1394,9 +1353,8 @@ export class MegolmDecryption extends DecryptionAlgorithm { /** * Add an event to the list of those awaiting their session keys. * - * @private + * @internal * - * @param {module:models/event.MatrixEvent} event */ private addEventToPendingList(event: MatrixEvent): void { const content = event.getWireContent(); @@ -1415,9 +1373,8 @@ export class MegolmDecryption extends DecryptionAlgorithm { /** * Remove an event from the list of those awaiting their session keys. * - * @private + * @internal * - * @param {module:models/event.MatrixEvent} event */ private removeEventFromPendingList(event: MatrixEvent): void { const content = event.getWireContent(); @@ -1438,11 +1395,6 @@ export class MegolmDecryption extends DecryptionAlgorithm { } } - /** - * @inheritdoc - * - * @param {module:models/event.MatrixEvent} event key event - */ public async onRoomKeyEvent(event: MatrixEvent): Promise { const content = event.getContent>(); let senderKey = event.getSenderKey()!; @@ -1619,9 +1571,7 @@ export class MegolmDecryption extends DecryptionAlgorithm { } /** - * @inheritdoc - * - * @param {module:models/event.MatrixEvent} event key event + * @param event - key event */ public async onRoomKeyWithheldEvent(event: MatrixEvent): Promise { const content = event.getContent(); @@ -1706,9 +1656,6 @@ export class MegolmDecryption extends DecryptionAlgorithm { } } - /** - * @inheritdoc - */ public hasKeysForKeyRequest(keyRequest: IncomingRoomKeyRequest): Promise { const body = keyRequest.requestBody; @@ -1720,9 +1667,6 @@ export class MegolmDecryption extends DecryptionAlgorithm { ); } - /** - * @inheritdoc - */ public shareKeysWithDevice(keyRequest: IncomingRoomKeyRequest): void { const userId = keyRequest.userId; const deviceId = keyRequest.deviceId; @@ -1808,19 +1752,15 @@ export class MegolmDecryption extends DecryptionAlgorithm { } /** - * @inheritdoc - * - * @param {module:crypto/OlmDevice.MegolmSessionData} session - * @param {object} [opts={}] options for the import - * @param {boolean} [opts.untrusted] whether the key should be considered as untrusted - * @param {string} [opts.source] where the key came from + * @param untrusted - whether the key should be considered as untrusted + * @param source - where the key came from */ public importRoomKey( session: IMegolmSessionData, - opts: { untrusted?: boolean, source?: string } = {}, + { untrusted, source }: { untrusted?: boolean, source?: string } = {}, ): Promise { const extraSessionData: OlmGroupSessionExtraData = {}; - if (opts.untrusted || session.untrusted) { + if (untrusted || session.untrusted) { extraSessionData.untrusted = true; } if (session["org.matrix.msc3061.shared_history"]) { @@ -1836,7 +1776,7 @@ export class MegolmDecryption extends DecryptionAlgorithm { true, extraSessionData, ).then(() => { - if (opts.source !== "backup") { + if (source !== "backup") { // don't wait for it to complete this.crypto.backupManager.backupGroupSession( session.sender_key, session.session_id, @@ -1855,13 +1795,11 @@ export class MegolmDecryption extends DecryptionAlgorithm { * Have another go at decrypting events after we receive a key. Resolves once * decryption has been re-attempted on all events. * - * @private - * @param {String} senderKey - * @param {String} sessionId - * @param {Boolean} forceRedecryptIfUntrusted whether messages that were already + * @internal + * @param forceRedecryptIfUntrusted - whether messages that were already * successfully decrypted using untrusted keys should be re-decrypted * - * @return {Boolean} whether all messages were successfully + * @returns whether all messages were successfully * decrypted with trusted keys */ private async retryDecryption( diff --git a/src/crypto/algorithms/olm.ts b/src/crypto/algorithms/olm.ts index 114368319..1feee6ba6 100644 --- a/src/crypto/algorithms/olm.ts +++ b/src/crypto/algorithms/olm.ts @@ -16,8 +16,6 @@ limitations under the License. /** * Defines m.olm encryption/decryption - * - * @module crypto/algorithms/olm */ import { logger } from '../../logger'; @@ -44,21 +42,17 @@ export interface IMessage { /** * Olm encryption implementation * - * @constructor - * @extends {module:crypto/algorithms/EncryptionAlgorithm} - * - * @param {object} params parameters, as per - * {@link module:crypto/algorithms/EncryptionAlgorithm} + * @param params - parameters, as per {@link EncryptionAlgorithm} */ class OlmEncryption extends EncryptionAlgorithm { private sessionPrepared = false; private prepPromise: Promise | null = null; /** - * @private + * @internal - * @param {string[]} roomMembers list of currently-joined users in the room - * @return {Promise} Promise which resolves when setup is complete + * @param roomMembers - list of currently-joined users in the room + * @returns Promise which resolves when setup is complete */ private ensureSession(roomMembers: string[]): Promise { if (this.prepPromise) { @@ -83,13 +77,9 @@ class OlmEncryption extends EncryptionAlgorithm { } /** - * @inheritdoc + * @param content - plaintext event content * - * @param {module:models/room} room - * @param {string} eventType - * @param {object} content plaintext event content - * - * @return {Promise} Promise which resolves to the new event body + * @returns Promise which resolves to the new event body */ public async encryptMessage(room: Room, eventType: string, content: IContent): Promise { // pick the list of recipients based on the membership list. @@ -150,19 +140,12 @@ class OlmEncryption extends EncryptionAlgorithm { /** * Olm decryption implementation * - * @constructor - * @extends {module:crypto/algorithms/DecryptionAlgorithm} - * @param {object} params parameters, as per - * {@link module:crypto/algorithms/DecryptionAlgorithm} + * @param params - parameters, as per {@link DecryptionAlgorithm} */ class OlmDecryption extends DecryptionAlgorithm { /** - * @inheritdoc - * - * @param {MatrixEvent} event - * * returns a promise which resolves to a - * {@link module:crypto~EventDecryptionResult} once we have finished + * {@link EventDecryptionResult} once we have finished * decrypting. Rejects with an `algorithms.DecryptionError` if there is a * problem decrypting the event. */ @@ -275,10 +258,10 @@ class OlmDecryption extends DecryptionAlgorithm { /** * Attempt to decrypt an Olm message * - * @param {string} theirDeviceIdentityKey Curve25519 identity key of the sender - * @param {object} message message object, with 'type' and 'body' fields + * @param theirDeviceIdentityKey - Curve25519 identity key of the sender + * @param message - message object, with 'type' and 'body' fields * - * @return {string} payload, if decrypted successfully. + * @returns payload, if decrypted successfully. */ private decryptMessage(theirDeviceIdentityKey: string, message: IMessage): Promise { // This is a wrapper that serialises decryptions of prekey messages, because diff --git a/src/crypto/api.ts b/src/crypto/api.ts index f6487ca91..468cc9933 100644 --- a/src/crypto/api.ts +++ b/src/crypto/api.ts @@ -66,8 +66,7 @@ export interface IRecoveryKey { export interface ICreateSecretStorageOpts { /** * Function called to await a secret storage key creation flow. - * Returns: - * {Promise} Object with public key metadata, encoded private + * @returns Promise resolving to an object with public key metadata, encoded private * recovery key which should be disposed of after displaying to the user, * and raw private key to avoid round tripping if needed. */ @@ -131,6 +130,7 @@ export interface IImportOpts { } export interface IImportRoomKeysOpts { + /** called with an object that has a "stage" param */ progressCallback?: (stage: IImportOpts) => void; untrusted?: boolean; source?: string; // TODO: Enum diff --git a/src/crypto/backup.ts b/src/crypto/backup.ts index 519128936..fa90c6b78 100644 --- a/src/crypto/backup.ts +++ b/src/crypto/backup.ts @@ -15,8 +15,6 @@ limitations under the License. */ /** - * @module crypto/backup - * * Classes for dealing with key backup. */ @@ -134,7 +132,7 @@ export class BackupManager { * * Throws an error if a problem is detected. * - * @param {IKeyBackupInfo} info the key backup info + * @param info - the key backup info */ public static checkBackupVersion(info: IKeyBackupInfo): void { const Algorithm = algorithmsByName[info.algorithm]; @@ -276,7 +274,7 @@ export class BackupManager { * Forces a re-check of the key backup and enables/disables it * as appropriate. * - * @return {Object} Object with backup info (as returned by + * @returns Object with backup info (as returned by * getKeyBackupVersion) in backupInfo and * trust information (as returned by isKeyBackupTrusted) * in trustInfo. @@ -309,15 +307,7 @@ export class BackupManager { /** * Check if the given backup info is trusted. * - * @param {IKeyBackupInfo} backupInfo key backup info dict from /room_keys/version - * @return {object} { - * usable: [bool], // is the backup trusted, true iff there is a sig that is valid & from a trusted device - * sigs: [ - * valid: [bool || null], // true: valid, false: invalid, null: cannot attempt validation - * deviceId: [string], - * device: [DeviceInfo || null], - * ] - * } + * @param backupInfo - key backup info dict from /room_keys/version */ public async isKeyBackupTrusted(backupInfo?: IKeyBackupInfo): Promise { const ret = { @@ -432,7 +422,7 @@ export class BackupManager { * Schedules sending all keys waiting to be sent to the backup, if not already * scheduled. Retries if necessary. * - * @param maxDelay Maximum delay to wait in ms. 0 means no delay. + * @param maxDelay - Maximum delay to wait in ms. 0 means no delay. */ public async scheduleKeyBackupSend(maxDelay = 10000): Promise { if (this.sendingBackups) return; @@ -490,8 +480,8 @@ export class BackupManager { * Take some e2e keys waiting to be backed up and send them * to the backup. * - * @param {number} limit Maximum number of keys to back up - * @returns {number} Number of sessions backed up + * @param limit - Maximum number of keys to back up + * @returns Number of sessions backed up */ public async backupPendingKeys(limit: number): Promise { const sessions = await this.baseApis.crypto!.cryptoStore.getSessionsNeedingBackup(limit); @@ -573,7 +563,7 @@ export class BackupManager { /** * Marks all group sessions as needing to be backed up without scheduling * them to upload in the background. - * @returns {Promise} Resolves to the number of sessions now requiring a backup + * @returns Promise which resolves to the number of sessions now requiring a backup * (which will be equal to the number of sessions in the store). */ public async flagAllGroupSessionsForBackup(): Promise { @@ -599,7 +589,7 @@ export class BackupManager { /** * Counts the number of end to end session keys that are waiting to be backed up - * @returns {Promise} Resolves to the number of sessions requiring backup + * @returns Promise which resolves to the number of sessions requiring backup */ public countSessionsNeedingBackup(): Promise { return this.baseApis.crypto!.cryptoStore.countSessionsNeedingBackup(); diff --git a/src/crypto/deviceinfo.ts b/src/crypto/deviceinfo.ts index a8fd9f008..1fbbd2800 100644 --- a/src/crypto/deviceinfo.ts +++ b/src/crypto/deviceinfo.ts @@ -16,10 +16,6 @@ limitations under the License. import { ISignatures } from "../@types/signed"; -/** - * @module crypto/deviceinfo - */ - export interface IDevice { keys: Record; algorithms: string[]; @@ -37,36 +33,15 @@ enum DeviceVerification { /** * Information about a user's device - * - * @constructor - * @alias module:crypto/deviceinfo - * - * @property {string} deviceId the ID of this device - * - * @property {string[]} algorithms list of algorithms supported by this device - * - * @property {Object.} keys a map from - * <key type>:<id> -> <base64-encoded key>> - * - * @property {module:crypto/deviceinfo.DeviceVerification} verified - * whether the device has been verified/blocked by the user - * - * @property {boolean} known - * whether the user knows of this device's existence (useful when warning - * the user that a user has added new devices) - * - * @property {Object} unsigned additional data from the homeserver - * - * @param {string} deviceId id of the device */ export class DeviceInfo { /** * rehydrate a DeviceInfo from the session store * - * @param {object} obj raw object from session store - * @param {string} deviceId id of the device + * @param obj - raw object from session store + * @param deviceId - id of the device * - * @return {module:crypto~DeviceInfo} new DeviceInfo + * @returns new DeviceInfo */ public static fromStorage(obj: Partial, deviceId: string): DeviceInfo { const res = new DeviceInfo(deviceId); @@ -79,28 +54,36 @@ export class DeviceInfo { return res; } - /** - * @enum - */ public static DeviceVerification = { VERIFIED: DeviceVerification.Verified, UNVERIFIED: DeviceVerification.Unverified, BLOCKED: DeviceVerification.Blocked, }; + /** list of algorithms supported by this device */ public algorithms: string[] = []; + /** a map from `: -> ` */ public keys: Record = {}; + /** whether the device has been verified/blocked by the user */ public verified = DeviceVerification.Unverified; + /** + * whether the user knows of this device's existence + * (useful when warning the user that a user has added new devices) + */ public known = false; + /** additional data from the homeserver */ public unsigned: Record = {}; public signatures: ISignatures = {}; + /** + * @param deviceId - id of the device + */ public constructor(public readonly deviceId: string) {} /** * Prepare a DeviceInfo for JSON serialisation in the session store * - * @return {object} deviceinfo with non-serialised members removed + * @returns deviceinfo with non-serialised members removed */ public toStorage(): IDevice { return { @@ -116,7 +99,7 @@ export class DeviceInfo { /** * Get the fingerprint for this device (ie, the Ed25519 key) * - * @return {string} base64-encoded fingerprint of this device + * @returns base64-encoded fingerprint of this device */ public getFingerprint(): string { return this.keys["ed25519:" + this.deviceId]; @@ -125,7 +108,7 @@ export class DeviceInfo { /** * Get the identity key for this device (ie, the Curve25519 key) * - * @return {string} base64-encoded identity key of this device + * @returns base64-encoded identity key of this device */ public getIdentityKey(): string { return this.keys["curve25519:" + this.deviceId]; @@ -134,7 +117,7 @@ export class DeviceInfo { /** * Get the configured display name for this device, if any * - * @return {string?} displayname + * @returns displayname */ public getDisplayName(): string | null { return this.unsigned.device_display_name || null; @@ -143,7 +126,7 @@ export class DeviceInfo { /** * Returns true if this device is blocked * - * @return {Boolean} true if blocked + * @returns true if blocked */ public isBlocked(): boolean { return this.verified == DeviceVerification.Blocked; @@ -152,7 +135,7 @@ export class DeviceInfo { /** * Returns true if this device is verified * - * @return {Boolean} true if verified + * @returns true if verified */ public isVerified(): boolean { return this.verified == DeviceVerification.Verified; @@ -161,7 +144,7 @@ export class DeviceInfo { /** * Returns true if this device is unverified * - * @return {Boolean} true if unverified + * @returns true if unverified */ public isUnverified(): boolean { return this.verified == DeviceVerification.Unverified; @@ -170,7 +153,7 @@ export class DeviceInfo { /** * Returns true if the user knows about this device's existence * - * @return {Boolean} true if known + * @returns true if known */ public isKnown(): boolean { return this.known === true; diff --git a/src/crypto/index.ts b/src/crypto/index.ts index 9163ace4f..65b43a635 100644 --- a/src/crypto/index.ts +++ b/src/crypto/index.ts @@ -17,10 +17,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/** - * @module crypto - */ - import anotherjson from "another-json"; import { v4 as uuidv4 } from "uuid"; @@ -128,7 +124,12 @@ interface IInitOpts { } export interface IBootstrapCrossSigningOpts { + /** Optional. Reset even if keys already exist. */ setupNewCrossSigning?: boolean; + /** + * A function that makes the request requiring auth. Receives the auth data as an object. + * Can be called multiple times, first with an empty authDict, to obtain the flows. + */ authUploadDeviceSigningKeys?(makeRequest: (authData: any) => Promise<{}>): Promise; } @@ -161,18 +162,32 @@ interface IRoomKey { algorithm: string; } +/** + * The parameters of a room key request. The details of the request may + * vary with the crypto algorithm, but the management and storage layers for + * outgoing requests expect it to have 'room_id' and 'session_id' properties. + */ export interface IRoomKeyRequestBody extends IRoomKey { session_id: string; sender_key: string; } -export interface IMegolmSessionData { - [key: string]: any; // extensible +interface Extensible { + [key: string]: any; +} + +export interface IMegolmSessionData extends Extensible { + // Sender's Curve25519 device key sender_key: string; + // Devices which forwarded this session to us (normally empty). forwarding_curve25519_key_chain: string[]; + // Other keys the sender claims. sender_claimed_keys: Record; + // Room this session is used in room_id: string; + // Unique id for the session session_id: string; + // Base64'ed key data session_key: string; algorithm?: string; untrusted?: boolean; @@ -188,13 +203,6 @@ export interface ICheckOwnCrossSigningTrustOpts { allowPrivateKeyRequests?: boolean; } -/** - * @typedef {Object} module:crypto~OlmSessionResult - * @property {module:crypto/deviceinfo} device device info - * @property {string?} sessionId base64 olm session id; null if no session - * could be established - */ - interface IUserOlmSession { deviceIdKey: string; sessions: { @@ -213,10 +221,26 @@ interface ISignableObject { unsigned?: object; } +/** + * The result of a (successful) call to decryptEvent. + */ export interface IEventDecryptionResult { + /** + * The plaintext payload for the event (typically containing type and content fields). + */ clearEvent: IClearEvent; + /** + * List of curve25519 keys involved in telling us about the senderCurve25519Key and claimedEd25519Key. + * See {@link MatrixEvent#getForwardingCurve25519KeyChain}. + */ forwardingCurve25519KeyChain?: string[]; + /** + * Key owned by the sender of this event. See {@link MatrixEvent#getSenderKey}. + */ senderCurve25519Key?: string; + /** + * ed25519 key claimed by the sender of this event. See {@link MatrixEvent#getClaimedEd25519Key}. + */ claimedEd25519Key?: string; untrusted?: boolean; } @@ -266,10 +290,50 @@ export enum CryptoEvent { } export type CryptoEventHandlerMap = { + /** + * Fires when a device is marked as verified/unverified/blocked/unblocked by + * {@link MatrixClient#setDeviceVerified|MatrixClient.setDeviceVerified} or + * {@link MatrixClient#setDeviceBlocked|MatrixClient.setDeviceBlocked}. + * + * @param userId - the owner of the verified device + * @param deviceId - the id of the verified device + * @param deviceInfo - updated device information + */ [CryptoEvent.DeviceVerificationChanged]: (userId: string, deviceId: string, device: DeviceInfo) => void; + /** + * Fires when the trust status of a user changes + * If userId is the userId of the logged-in user, this indicated a change + * in the trust status of the cross-signing data on the account. + * + * The cross-signing API is currently UNSTABLE and may change without notice. + * @experimental + * + * @param userId - the userId of the user in question + * @param trustLevel - The new trust level of the user + */ [CryptoEvent.UserTrustStatusChanged]: (userId: string, trustLevel: UserTrustLevel) => void; + /** + * Fires when we receive a room key request + * + * @param req - request details + */ [CryptoEvent.RoomKeyRequest]: (request: IncomingRoomKeyRequest) => void; + /** + * Fires when we receive a room key request cancellation + */ [CryptoEvent.RoomKeyRequestCancellation]: (request: IncomingRoomKeyRequestCancellation) => void; + /** + * Fires whenever the status of e2e key backup changes, as returned by getKeyBackupEnabled() + * @param enabled - true if key backup has been enabled, otherwise false + * @example + * ``` + * matrixClient.on("crypto.keyBackupStatus", function(enabled){ + * if (enabled) { + * [...] + * } + * }); + * ``` + */ [CryptoEvent.KeyBackupStatus]: (enabled: boolean) => void; [CryptoEvent.KeyBackupFailed]: (errcode: string) => void; [CryptoEvent.KeyBackupSessionsRemaining]: (remaining: number) => void; @@ -277,18 +341,50 @@ export type CryptoEventHandlerMap = { failures: IUploadKeySignaturesResponse["failures"], source: "checkOwnCrossSigningTrust" | "afterCrossSigningLocalKeyChange" | "setDeviceVerification", upload: (opts: { shouldEmit: boolean }) => Promise - ) => void; + ) => void;/** + * Fires when a key verification is requested. + */ [CryptoEvent.VerificationRequest]: (request: VerificationRequest) => void; + /** + * Fires when the app may wish to warn the user about something related + * the end-to-end crypto. + * + * @param type - One of the strings listed above + */ [CryptoEvent.Warning]: (type: string) => void; + /** + * Fires when the user's cross-signing keys have changed or cross-signing + * has been enabled/disabled. The client can use getStoredCrossSigningForUser + * with the user ID of the logged in user to check if cross-signing is + * enabled on the account. If enabled, it can test whether the current key + * is trusted using with checkUserTrust with the user ID of the logged + * in user. The checkOwnCrossSigningTrust function may be used to reconcile + * the trust in the account key. + * + * The cross-signing API is currently UNSTABLE and may change without notice. + * @experimental + */ [CryptoEvent.KeysChanged]: (data: {}) => void; + /** + * Fires whenever the stored devices for a user will be updated + * @param users - A list of user IDs that will be updated + * @param initialFetch - If true, the store is empty (apart + * from our own device) and is being seeded. + */ [CryptoEvent.WillUpdateDevices]: (users: string[], initialFetch: boolean) => void; + /** + * Fires whenever the stored devices for a user have changed + * @param users - A list of user IDs that were updated + * @param initialFetch - If true, the store was empty (apart + * from our own device) and has been seeded. + */ [CryptoEvent.DevicesUpdated]: (users: string[], initialFetch: boolean) => void; [CryptoEvent.UserCrossSigningUpdated]: (userId: string) => void; }; export class Crypto extends TypedEventEmitter { /** - * @return {string} The version of Olm. + * @returns The version of Olm. */ public static getOlmVersion(): [number, number, number] { return OlmDevice.getOlmVersion(); @@ -362,25 +458,21 @@ export class Crypto extends TypedEventEmitter { @@ -556,7 +647,7 @@ export class Crypto extends TypedEventEmitter} Object with public key metadata, encoded private + * @returns Object with public key metadata, encoded private * recovery key which should be disposed of after displaying to the user, * and raw private key to avoid round tripping if needed. */ @@ -639,7 +730,7 @@ export class Crypto extends TypedEventEmitter { const publicKeysOnDevice = this.crossSigningInfo.getId(); @@ -664,7 +755,7 @@ export class Crypto extends TypedEventEmitter { const secretStorageKeyInAccount = await this.secretStorage.hasKey(); @@ -694,12 +785,12 @@ export class Crypto extends TypedEventEmitter} Object with public key metadata, encoded private + * Returns a Promise which resolves to an object with public key metadata, encoded private * recovery key which should be disposed of after displaying to the user, * and raw private key to avoid round tripping if needed. - * @param {object} [opts.keyBackupInfo] The current key backup object. If passed, + * @param keyBackupInfo - The current key backup object. If passed, * the passphrase and recovery key from this backup will be used. - * @param {boolean} [opts.setupNewKeyBackup] If true, a new key backup version will be + * @param setupNewKeyBackup - If true, a new key backup version will be * created and the private key stored in the new SSSS store. Ignored if keyBackupInfo * is supplied. - * @param {boolean} [opts.setupNewSecretStorage] Optional. Reset even if keys already exist. - * @param {func} [opts.getKeyBackupPassphrase] Optional. Function called to get the user's + * @param setupNewSecretStorage - Optional. Reset even if keys already exist. + * @param getKeyBackupPassphrase - Optional. Function called to get the user's * current key backup passphrase. Should return a promise that resolves with a Buffer * containing the key, or rejects if the key cannot be obtained. * Returns: - * {Promise} A promise which resolves to key creation data for + * A promise which resolves to key creation data for * SecretStorage#addKey: an object with `passphrase` etc fields. */ // TODO this does not resolve with what it says it does @@ -1150,9 +1240,9 @@ export class Crypto extends TypedEventEmitter { let key = await new Promise((resolve) => { // TODO types @@ -1200,8 +1290,8 @@ export class Crypto extends TypedEventEmitter): Promise { if (!(key instanceof Uint8Array)) { @@ -1223,9 +1313,9 @@ export class Crypto extends TypedEventEmitter | null): Promise { if (keys) { @@ -1732,7 +1822,7 @@ export class Crypto extends TypedEventEmitter { const shouldUpgradeCb = ( @@ -1774,7 +1864,7 @@ export class Crypto extends TypedEventEmitter { const deviceKeys = { @@ -1866,7 +1956,7 @@ export class Crypto extends TypedEventEmitterdeviceId->{@link - * module:crypto/deviceinfo|DeviceInfo}. + * @returns A promise which resolves to a map `userId->deviceId->{@link DeviceInfo}`. */ public downloadKeys(userIds: string[], forceDownload?: boolean): Promise { return this.deviceList.downloadKeys(userIds, !!forceDownload); @@ -2069,9 +2158,9 @@ export class Crypto extends TypedEventEmitter | null { @@ -2081,10 +2170,8 @@ export class Crypto extends TypedEventEmitter} true if the data was saved, false if + * @returns true if the data was saved, false if * it was not (eg. because no changes were pending). The promise * will only resolve once the data is saved, so may take some time * to resolve. @@ -2110,24 +2197,24 @@ export class Crypto extends TypedEventEmitter} keys The list of keys that was present + * @param keys - The list of keys that was present * during the device verification. This will be double checked with the list * of keys the given device has currently. * - * @return {Promise} updated DeviceInfo + * @returns updated DeviceInfo */ public async setDeviceVerification( userId: string, @@ -2392,13 +2479,11 @@ export class Crypto extends TypedEventEmitter * This method is provided for debugging purposes. * - * @param {string} userId id of user to inspect - * - * @return {Promise>} + * @param userId - id of user to inspect */ public async getOlmSessionsForUser(userId: string): Promise> { const devices = this.getStoredDevicesForUser(userId) || []; @@ -2418,9 +2503,7 @@ export class Crypto extends TypedEventEmitternot initiate a device list query for the room. That is normally * done once we finish processing the sync, in onSyncCompleted. * - * @param room The room to enable encryption in. - * @param config The encryption config for the room. + * @param room - The room to enable encryption in. + * @param config - The encryption config for the room. */ private async setRoomEncryptionImpl( room: Room, @@ -2682,8 +2765,8 @@ export class Crypto extends TypedEventEmitter { const room = this.clientStore.getRoom(roomId); @@ -2701,7 +2784,7 @@ export class Crypto extends TypedEventEmitter { const roomId = room.roomId; @@ -2732,12 +2815,12 @@ export class Crypto extends TypedEventEmitter { const exportedSessions: IMegolmSessionData[] = []; @@ -2793,10 +2876,8 @@ export class Crypto extends TypedEventEmitter { let successes = 0; @@ -2830,7 +2911,7 @@ export class Crypto extends TypedEventEmitter} Resolves to the number of sessions requiring backup + * @returns Promise which resolves to the number of sessions requiring backup */ public countSessionsNeedingBackup(): Promise { return this.backupManager.countSessionsNeedingBackup(); @@ -2840,7 +2921,7 @@ export class Crypto extends TypedEventEmitter { @@ -2917,9 +2998,8 @@ export class Crypto extends TypedEventEmitter} resolves once we have + * @returns resolves once we have * finished decrypting. Rejects with an `algorithms.DecryptionError` if there * is a problem decrypting the event. */ @@ -2952,8 +3032,8 @@ export class Crypto extends TypedEventEmitter} recipients - * @param {boolean} resend whether to resend the key request if there is + * @param resend - whether to resend the key request if there is * already one * - * @return {Promise} a promise that resolves when the key request is queued + * @returns a promise that resolves when the key request is queued */ public requestRoomKey( requestBody: IRoomKeyRequestBody, @@ -3007,8 +3085,7 @@ export class Crypto extends TypedEventEmitter { await this.outgoingRoomKeyRequestManager.cancelAndResendAllOutgoingRequests(); @@ -3028,8 +3105,8 @@ export class Crypto extends TypedEventEmitter { const content = event.getContent(); @@ -3039,7 +3116,7 @@ export class Crypto extends TypedEventEmitter { if (!syncData.oldSyncToken) { @@ -3063,7 +3140,7 @@ export class Crypto extends TypedEventEmitter { this.deviceList.setSyncToken(syncData.nextSyncToken ?? null); @@ -3096,7 +3173,7 @@ export class Crypto extends TypedEventEmitter["device_lists"]): Promise { @@ -3124,7 +3201,7 @@ export class Crypto extends TypedEventEmitter { const e2eUserIds: string[] = []; @@ -3141,7 +3218,7 @@ export class Crypto extends TypedEventEmitter { @@ -3163,11 +3240,11 @@ export class Crypto extends TypedEventEmitter} Promise which + * @param userDeviceInfoArr - the devices to send to + * @param payload - fields to include in the encrypted payload + * @returns Promise which * resolves once the message has been encrypted and sent to the given - * userDeviceMap, and returns the { contentMap, deviceInfoByDeviceId } + * userDeviceMap, and returns the `{ contentMap, deviceInfoByDeviceId }` * of the successfully sent messages. */ public async encryptAndSendToDevices( @@ -3281,8 +3358,8 @@ export class Crypto extends TypedEventEmitter { const content = event.getWireContent(); @@ -3565,10 +3642,10 @@ export class Crypto extends TypedEventEmitter { if (this.processingRoomKeyRequests) { @@ -3669,7 +3746,6 @@ export class Crypto extends TypedEventEmitter { const userId = req.userId; @@ -3759,7 +3835,6 @@ export class Crypto extends TypedEventEmitter | undefined; @@ -3834,9 +3906,9 @@ export class Crypto extends TypedEventEmitter(obj: T): Promise { const sigs = obj.signatures || {}; @@ -3874,8 +3946,8 @@ export class Crypto extends TypedEventEmitter void; public constructor(event: MatrixEvent) { @@ -3928,14 +3992,13 @@ export class IncomingRoomKeyRequest { /** * Represents a received m.room_key_request cancellation - * - * @property {string} userId user requesting the cancellation - * @property {string} deviceId device requesting the cancellation - * @property {string} requestId unique id for the request to be cancelled */ class IncomingRoomKeyRequestCancellation { + /** user requesting the cancellation */ public readonly userId: string; + /** device requesting the cancellation */ public readonly deviceId: string; + /** unique id for the request to be cancelled */ public readonly requestId: string; public constructor(event: MatrixEvent) { @@ -3946,46 +4009,3 @@ class IncomingRoomKeyRequestCancellation { this.requestId = content.request_id; } } - -/** - * The result of a (successful) call to decryptEvent. - * - * @typedef {Object} EventDecryptionResult - * - * @property {Object} clearEvent The plaintext payload for the event - * (typically containing type and content fields). - * - * @property {?string} senderCurve25519Key Key owned by the sender of this - * event. See {@link module:models/event.MatrixEvent#getSenderKey}. - * - * @property {?string} claimedEd25519Key ed25519 key claimed by the sender of - * this event. See - * {@link module:models/event.MatrixEvent#getClaimedEd25519Key}. - * - * @property {?Array} forwardingCurve25519KeyChain list of curve25519 - * keys involved in telling us about the senderCurve25519Key and - * claimedEd25519Key. See - * {@link module:models/event.MatrixEvent#getForwardingCurve25519KeyChain}. - */ - -/** - * Fires when we receive a room key request - * - * @event module:client~MatrixClient#"crypto.roomKeyRequest" - * @param {module:crypto~IncomingRoomKeyRequest} req request details - */ - -/** - * Fires when we receive a room key request cancellation - * - * @event module:client~MatrixClient#"crypto.roomKeyRequestCancellation" - * @param {module:crypto~IncomingRoomKeyRequestCancellation} req - */ - -/** - * Fires when the app may wish to warn the user about something related - * the end-to-end crypto. - * - * @event module:client~MatrixClient#"crypto.warning" - * @param {string} type One of the strings listed above - */ diff --git a/src/crypto/keybackup.ts b/src/crypto/keybackup.ts index 919266a3e..67e213c4a 100644 --- a/src/crypto/keybackup.ts +++ b/src/crypto/keybackup.ts @@ -59,6 +59,10 @@ export interface IKeyBackupInfo { /* eslint-enable camelcase */ export interface IKeyBackupPrepareOpts { + /** + * Whether to use Secure Secret Storage to store the key encrypting key backups. + * Optional, defaults to false. + */ secureSecretStorage: boolean; } diff --git a/src/crypto/olmlib.ts b/src/crypto/olmlib.ts index 862691353..4a228e281 100644 --- a/src/crypto/olmlib.ts +++ b/src/crypto/olmlib.ts @@ -15,8 +15,6 @@ limitations under the License. */ /** - * @module olmlib - * * Utilities common to olm encryption algorithms */ @@ -55,22 +53,20 @@ export const MEGOLM_ALGORITHM = Algorithm.Megolm; export const MEGOLM_BACKUP_ALGORITHM = Algorithm.MegolmBackup; export interface IOlmSessionResult { + /** device info */ device: DeviceInfo; + /** base64 olm session id; null if no session could be established */ sessionId: string | null; } /** * Encrypt an event payload for an Olm device * - * @param {Object} resultsObject The `ciphertext` property + * @param resultsObject - The `ciphertext` property * of the m.room.encrypted event to which to add our result * - * @param {string} ourUserId - * @param {string} ourDeviceId - * @param {module:crypto/OlmDevice} olmDevice olm.js wrapper - * @param {string} recipientUserId - * @param {module:crypto/deviceinfo} recipientDevice - * @param {object} payloadFields fields to include in the encrypted payload + * @param olmDevice - olm.js wrapper + * @param payloadFields - fields to include in the encrypted payload * * Returns a promise which resolves (to undefined) when the payload * has been encrypted into `resultsObject` @@ -145,17 +141,14 @@ interface IExistingOlmSession { * Get the existing olm sessions for the given devices, and the devices that * don't have olm sessions. * - * @param {module:crypto/OlmDevice} olmDevice * - * @param {MatrixClient} baseApis * - * @param {object} devicesByUser - * map from userid to list of devices to ensure sessions for + * @param devicesByUser - map from userid to list of devices to ensure sessions for * - * @return {Promise} resolves to an array. The first element of the array is a + * @returns resolves to an array. The first element of the array is a * a map of user IDs to arrays of deviceInfo, representing the devices that * don't have established olm sessions. The second element of the array is - * a map from userId to deviceId to {@link module:crypto~OlmSessionResult} + * a map from userId to deviceId to {@link OlmSessionResult} */ export async function getExistingOlmSessions( olmDevice: OlmDevice, @@ -197,27 +190,22 @@ export async function getExistingOlmSessions( /** * Try to make sure we have established olm sessions for the given devices. * - * @param {module:crypto/OlmDevice} olmDevice + * @param devicesByUser - map from userid to list of devices to ensure sessions for * - * @param {MatrixClient} baseApis - * - * @param {object} devicesByUser - * map from userid to list of devices to ensure sessions for - * - * @param {boolean} [force=false] If true, establish a new session even if one + * @param force - If true, establish a new session even if one * already exists. * - * @param {Number} [otkTimeout] The timeout in milliseconds when requesting + * @param otkTimeout - The timeout in milliseconds when requesting * one-time keys for establishing new olm sessions. * - * @param {Array} [failedServers] An array to fill with remote servers that + * @param failedServers - An array to fill with remote servers that * failed to respond to one-time-key requests. * - * @param {Logger} [log] A possibly customised log + * @param log - A possibly customised log * - * @return {Promise} resolves once the sessions are complete, to + * @returns resolves once the sessions are complete, to * an Object mapping from userId to deviceId to - * {@link module:crypto~OlmSessionResult} + * {@link OlmSessionResult} */ export async function ensureOlmSessionsForDevices( olmDevice: OlmDevice, @@ -442,15 +430,15 @@ export interface IObject { /** * Verify the signature on an object * - * @param {module:crypto/OlmDevice} olmDevice olm wrapper to use for verify op + * @param olmDevice - olm wrapper to use for verify op * - * @param {Object} obj object to check signature on. + * @param obj - object to check signature on. * - * @param {string} signingUserId ID of the user whose signature should be checked + * @param signingUserId - ID of the user whose signature should be checked * - * @param {string} signingDeviceId ID of the device whose signature should be checked + * @param signingDeviceId - ID of the device whose signature should be checked * - * @param {string} signingKey base64-ed ed25519 public key + * @param signingKey - base64-ed ed25519 public key * * Returns a promise which resolves (to undefined) if the the signature is good, * or rejects with an Error if it is bad. @@ -485,13 +473,13 @@ export async function verifySignature( /** * Sign a JSON object using public key cryptography - * @param {Object} obj Object to sign. The object will be modified to include + * @param obj - Object to sign. The object will be modified to include * the new signature - * @param {Olm.PkSigning|Uint8Array} key the signing object or the private key + * @param key - the signing object or the private key * seed - * @param {string} userId The user ID who owns the signing key - * @param {string} pubKey The public key (ignored if key is a seed) - * @returns {string} the signature for the object + * @param userId - The user ID who owns the signing key + * @param pubKey - The public key (ignored if key is a seed) + * @returns the signature for the object */ export function pkSign(obj: object & IObject, key: Uint8Array | PkSigning, userId: string, pubKey: string): string { let createdKey = false; @@ -521,9 +509,9 @@ export function pkSign(obj: object & IObject, key: Uint8Array | PkSigning, userI /** * Verify a signed JSON object - * @param {Object} obj Object to verify - * @param {string} pubKey The public key to use to verify - * @param {string} userId The user ID who signed the object + * @param obj - Object to verify + * @param pubKey - The public key to use to verify + * @param userId - The user ID who signed the object */ export function pkVerify(obj: IObject, pubKey: string, userId: string): void { const keyId = "ed25519:" + pubKey; @@ -563,8 +551,8 @@ export function isOlmEncrypted(event: MatrixEvent): boolean { /** * Encode a typed array of uint8 as base64. - * @param {Uint8Array} uint8Array The data to encode. - * @return {string} The base64. + * @param uint8Array - The data to encode. + * @returns The base64. */ export function encodeBase64(uint8Array: ArrayBuffer | Uint8Array): string { return Buffer.from(uint8Array).toString("base64"); @@ -572,8 +560,8 @@ export function encodeBase64(uint8Array: ArrayBuffer | Uint8Array): string { /** * Encode a typed array of uint8 as unpadded base64. - * @param {Uint8Array} uint8Array The data to encode. - * @return {string} The unpadded base64. + * @param uint8Array - The data to encode. + * @returns The unpadded base64. */ export function encodeUnpaddedBase64(uint8Array: ArrayBuffer | Uint8Array): string { return encodeBase64(uint8Array).replace(/=+$/g, ''); @@ -581,8 +569,8 @@ export function encodeUnpaddedBase64(uint8Array: ArrayBuffer | Uint8Array): stri /** * Decode a base64 string to a typed array of uint8. - * @param {string} base64 The base64 to decode. - * @return {Uint8Array} The decoded data. + * @param base64 - The base64 to decode. + * @returns The decoded data. */ export function decodeBase64(base64: string): Uint8Array { return Buffer.from(base64, "base64"); diff --git a/src/crypto/store/base.ts b/src/crypto/store/base.ts index 72b02e0a1..31ece3b06 100644 --- a/src/crypto/store/base.ts +++ b/src/crypto/store/base.ts @@ -30,8 +30,6 @@ import { IEncryptedPayload } from "../aes"; /** * Internal module. Definitions for storage for the crypto module - * - * @module */ export interface SecretStorePrivateKeys { @@ -46,8 +44,6 @@ export interface SecretStorePrivateKeys { /** * Abstraction of things that can store data required for end-to-end encryption - * - * @interface CryptoStore */ export interface CryptoStore { startup(): Promise; @@ -197,32 +193,29 @@ export interface IWithheld { /** * Represents an outgoing room key request - * - * @typedef {Object} OutgoingRoomKeyRequest - * - * @property {string} requestId unique id for this request. Used for both - * an id within the request for later pairing with a cancellation, and for - * the transaction id when sending the to_device messages to our local - * server. - * - * @property {string?} cancellationTxnId - * transaction id for the cancellation, if any - * - * @property {Array<{userId: string, deviceId: string}>} recipients - * list of recipients for the request - * - * @property {module:crypto~RoomKeyRequestBody} requestBody - * parameters for the request. - * - * @property {Number} state current state of this request (states are defined - * in {@link module:crypto/OutgoingRoomKeyRequestManager~ROOM_KEY_REQUEST_STATES}) */ export interface OutgoingRoomKeyRequest { + /** + * Unique id for this request. Used for both an id within the request for later pairing with a cancellation, + * and for the transaction id when sending the to_device messages to our local server. + */ requestId: string; requestTxnId?: string; + /** + * Transaction id for the cancellation, if any + */ cancellationTxnId?: string; + /** + * List of recipients for the request + */ recipients: IRoomKeyRequestRecipient[]; + /** + * Parameters for the request + */ requestBody: IRoomKeyRequestBody; + /** + * current state of this request (states are defined in {@link OutgoingRoomKeyRequestManager}) + */ state: RoomKeyRequestState; } diff --git a/src/crypto/store/indexeddb-crypto-store-backend.ts b/src/crypto/store/indexeddb-crypto-store-backend.ts index cdf35e787..3a0c7711a 100644 --- a/src/crypto/store/indexeddb-crypto-store-backend.ts +++ b/src/crypto/store/indexeddb-crypto-store-backend.ts @@ -39,14 +39,11 @@ const PROFILE_TRANSACTIONS = false; * Implementation of a CryptoStore which is backed by an existing * IndexedDB connection. Generally you want IndexedDBCryptoStore * which connects to the database and defers to one of these. - * - * @implements {module:crypto/store/base~CryptoStore} */ export class Backend implements CryptoStore { private nextTxnId = 0; /** - * @param {IDBDatabase} db */ public constructor(private db: IDBDatabase) { // make sure we close the db on `onversionchange` - otherwise @@ -71,10 +68,9 @@ export class Backend implements CryptoStore { * Look for an existing outgoing room key request, and if none is found, * add a new one * - * @param {module:crypto/store/base~OutgoingRoomKeyRequest} request * - * @returns {Promise} resolves to - * {@link module:crypto/store/base~OutgoingRoomKeyRequest}: either the + * @returns resolves to + * {@link OutgoingRoomKeyRequest}: either the * same instance as passed in, or the existing one. */ public getOrAddOutgoingRoomKeyRequest(request: OutgoingRoomKeyRequest): Promise { @@ -113,11 +109,10 @@ export class Backend implements CryptoStore { /** * Look for an existing room key request * - * @param {module:crypto~RoomKeyRequestBody} requestBody - * existing request to look for + * @param requestBody - existing request to look for * - * @return {Promise} resolves to the matching - * {@link module:crypto/store/base~OutgoingRoomKeyRequest}, or null if + * @returns resolves to the matching + * {@link OutgoingRoomKeyRequest}, or null if * not found */ public getOutgoingRoomKeyRequest(requestBody: IRoomKeyRequestBody): Promise { @@ -134,13 +129,12 @@ export class Backend implements CryptoStore { /** * look for an existing room key request in the db * - * @private - * @param {IDBTransaction} txn database transaction - * @param {module:crypto~RoomKeyRequestBody} requestBody - * existing request to look for - * @param {Function} callback function to call with the results of the + * @internal + * @param txn - database transaction + * @param requestBody - existing request to look for + * @param callback - function to call with the results of the * search. Either passed a matching - * {@link module:crypto/store/base~OutgoingRoomKeyRequest}, or null if + * {@link OutgoingRoomKeyRequest}, or null if * not found. */ // eslint-disable-next-line @typescript-eslint/naming-convention @@ -181,10 +175,10 @@ export class Backend implements CryptoStore { /** * Look for room key requests by state * - * @param {Array} wantedStates list of acceptable states + * @param wantedStates - list of acceptable states * - * @return {Promise} resolves to the a - * {@link module:crypto/store/base~OutgoingRoomKeyRequest}, or null if + * @returns resolves to the a + * {@link OutgoingRoomKeyRequest}, or null if * there are no pending requests in those states. If there are multiple * requests in those states, an arbitrary one is chosen. */ @@ -233,8 +227,7 @@ export class Backend implements CryptoStore { /** * - * @param {Number} wantedState - * @return {Promise>} All elements in a given state + * @returns All elements in a given state */ public getAllOutgoingRoomKeyRequestsByState(wantedState: number): Promise { return new Promise((resolve, reject) => { @@ -294,12 +287,12 @@ export class Backend implements CryptoStore { * Look for an existing room key request by id and state, and update it if * found * - * @param {string} requestId ID of request to update - * @param {number} expectedState state we expect to find the request in - * @param {Object} updates name/value map of updates to apply + * @param requestId - ID of request to update + * @param expectedState - state we expect to find the request in + * @param updates - name/value map of updates to apply * - * @returns {Promise} resolves to - * {@link module:crypto/store/base~OutgoingRoomKeyRequest} + * @returns resolves to + * {@link OutgoingRoomKeyRequest} * updated request, or null if no matching row was found */ public updateOutgoingRoomKeyRequest( @@ -337,10 +330,10 @@ export class Backend implements CryptoStore { * Look for an existing room key request by id and state, and delete it if * found * - * @param {string} requestId ID of request to update - * @param {number} expectedState state we expect to find the request in + * @param requestId - ID of request to update + * @param expectedState - state we expect to find the request in * - * @returns {Promise} resolves once the operation is completed + * @returns resolves once the operation is completed */ public deleteOutgoingRoomKeyRequest( requestId: string, diff --git a/src/crypto/store/indexeddb-crypto-store.ts b/src/crypto/store/indexeddb-crypto-store.ts index d743a95de..ac2964d12 100644 --- a/src/crypto/store/indexeddb-crypto-store.ts +++ b/src/crypto/store/indexeddb-crypto-store.ts @@ -39,15 +39,11 @@ import { InboundGroupSessionData } from "../OlmDevice"; /** * Internal module. indexeddb storage for e2e. - * - * @module */ /** * An implementation of CryptoStore, which is normally backed by an indexeddb, * but with fallback to MemoryCryptoStore. - * - * @implements {module:crypto/store/base~CryptoStore} */ export class IndexedDBCryptoStore implements CryptoStore { public static STORE_ACCOUNT = 'account'; @@ -70,8 +66,8 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Create a new IndexedDBCryptoStore * - * @param {IDBFactory} indexedDB global indexedDB instance - * @param {string} dbName name of db to connect to + * @param indexedDB - global indexedDB instance + * @param dbName - name of db to connect to */ public constructor(private readonly indexedDB: IDBFactory, private readonly dbName: string) {} @@ -81,7 +77,7 @@ export class IndexedDBCryptoStore implements CryptoStore { * * This must be called before the store can be used. * - * @return {Promise} resolves to either an IndexedDBCryptoStoreBackend.Backend, + * @returns resolves to either an IndexedDBCryptoStoreBackend.Backend, * or a MemoryCryptoStore */ public startup(): Promise { @@ -167,7 +163,7 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Delete all data from this store. * - * @returns {Promise} resolves when the store has been cleared. + * @returns resolves when the store has been cleared. */ public deleteAllData(): Promise { return new Promise((resolve, reject) => { @@ -206,10 +202,9 @@ export class IndexedDBCryptoStore implements CryptoStore { * Look for an existing outgoing room key request, and if none is found, * add a new one * - * @param {module:crypto/store/base~OutgoingRoomKeyRequest} request * - * @returns {Promise} resolves to - * {@link module:crypto/store/base~OutgoingRoomKeyRequest}: either the + * @returns resolves to + * {@link OutgoingRoomKeyRequest}: either the * same instance as passed in, or the existing one. */ public getOrAddOutgoingRoomKeyRequest(request: OutgoingRoomKeyRequest): Promise { @@ -219,11 +214,10 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Look for an existing room key request * - * @param {module:crypto~RoomKeyRequestBody} requestBody - * existing request to look for + * @param requestBody - existing request to look for * - * @return {Promise} resolves to the matching - * {@link module:crypto/store/base~OutgoingRoomKeyRequest}, or null if + * @returns resolves to the matching + * {@link OutgoingRoomKeyRequest}, or null if * not found */ public getOutgoingRoomKeyRequest(requestBody: IRoomKeyRequestBody): Promise { @@ -233,10 +227,10 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Look for room key requests by state * - * @param {Array} wantedStates list of acceptable states + * @param wantedStates - list of acceptable states * - * @return {Promise} resolves to the a - * {@link module:crypto/store/base~OutgoingRoomKeyRequest}, or null if + * @returns resolves to the a + * {@link OutgoingRoomKeyRequest}, or null if * there are no pending requests in those states. If there are multiple * requests in those states, an arbitrary one is chosen. */ @@ -248,8 +242,7 @@ export class IndexedDBCryptoStore implements CryptoStore { * Look for room key requests by state – * unlike above, return a list of all entries in one state. * - * @param {Number} wantedState - * @return {Promise>} Returns an array of requests in the given state + * @returns Returns an array of requests in the given state */ public getAllOutgoingRoomKeyRequestsByState(wantedState: number): Promise { return this.backend!.getAllOutgoingRoomKeyRequestsByState(wantedState); @@ -258,12 +251,12 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Look for room key requests by target device and state * - * @param {string} userId Target user ID - * @param {string} deviceId Target device ID - * @param {Array} wantedStates list of acceptable states + * @param userId - Target user ID + * @param deviceId - Target device ID + * @param wantedStates - list of acceptable states * - * @return {Promise} resolves to a list of all the - * {@link module:crypto/store/base~OutgoingRoomKeyRequest} + * @returns resolves to a list of all the + * {@link OutgoingRoomKeyRequest} */ public getOutgoingRoomKeyRequestsByTarget( userId: string, @@ -279,12 +272,12 @@ export class IndexedDBCryptoStore implements CryptoStore { * Look for an existing room key request by id and state, and update it if * found * - * @param {string} requestId ID of request to update - * @param {number} expectedState state we expect to find the request in - * @param {Object} updates name/value map of updates to apply + * @param requestId - ID of request to update + * @param expectedState - state we expect to find the request in + * @param updates - name/value map of updates to apply * - * @returns {Promise} resolves to - * {@link module:crypto/store/base~OutgoingRoomKeyRequest} + * @returns resolves to + * {@link OutgoingRoomKeyRequest} * updated request, or null if no matching row was found */ public updateOutgoingRoomKeyRequest( @@ -301,10 +294,10 @@ export class IndexedDBCryptoStore implements CryptoStore { * Look for an existing room key request by id and state, and delete it if * found * - * @param {string} requestId ID of request to update - * @param {number} expectedState state we expect to find the request in + * @param requestId - ID of request to update + * @param expectedState - state we expect to find the request in * - * @returns {Promise} resolves once the operation is completed + * @returns resolves once the operation is completed */ public deleteOutgoingRoomKeyRequest( requestId: string, @@ -319,8 +312,8 @@ export class IndexedDBCryptoStore implements CryptoStore { * Get the account pickle from the store. * This requires an active transaction. See doTxn(). * - * @param {*} txn An active transaction. See doTxn(). - * @param {function(string)} func Called with the account pickle + * @param txn - An active transaction. See doTxn(). + * @param func - Called with the account pickle */ public getAccount(txn: IDBTransaction, func: (accountPickle: string | null) => void): void { this.backend!.getAccount(txn, func); @@ -330,8 +323,8 @@ export class IndexedDBCryptoStore implements CryptoStore { * Write the account pickle to the store. * This requires an active transaction. See doTxn(). * - * @param {*} txn An active transaction. See doTxn(). - * @param {string} accountPickle The new account pickle to store. + * @param txn - An active transaction. See doTxn(). + * @param accountPickle - The new account pickle to store. */ public storeAccount(txn: IDBTransaction, accountPickle: string): void { this.backend!.storeAccount(txn, accountPickle); @@ -341,9 +334,9 @@ export class IndexedDBCryptoStore implements CryptoStore { * Get the public part of the cross-signing keys (eg. self-signing key, * user signing key). * - * @param {*} txn An active transaction. See doTxn(). - * @param {function(string)} func Called with the account keys object: - * { key_type: base64 encoded seed } where key type = user_signing_key_seed or self_signing_key_seed + * @param txn - An active transaction. See doTxn(). + * @param func - Called with the account keys object: + * `{ key_type: base64 encoded seed }` where key type = user_signing_key_seed or self_signing_key_seed */ public getCrossSigningKeys( txn: IDBTransaction, @@ -353,9 +346,9 @@ export class IndexedDBCryptoStore implements CryptoStore { } /** - * @param {*} txn An active transaction. See doTxn(). - * @param {function(string)} func Called with the private key - * @param {string} type A key type + * @param txn - An active transaction. See doTxn(). + * @param func - Called with the private key + * @param type - A key type */ public getSecretStorePrivateKey( txn: IDBTransaction, @@ -368,8 +361,8 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Write the cross-signing keys back to the store * - * @param {*} txn An active transaction. See doTxn(). - * @param {string} keys keys object as getCrossSigningKeys() + * @param txn - An active transaction. See doTxn(). + * @param keys - keys object as getCrossSigningKeys() */ public storeCrossSigningKeys(txn: IDBTransaction, keys: Record): void { this.backend!.storeCrossSigningKeys(txn, keys); @@ -378,9 +371,9 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Write the cross-signing private keys back to the store * - * @param {*} txn An active transaction. See doTxn(). - * @param {string} type The type of cross-signing private key to store - * @param {string} key keys object as getCrossSigningKeys() + * @param txn - An active transaction. See doTxn(). + * @param type - The type of cross-signing private key to store + * @param key - keys object as getCrossSigningKeys() */ public storeSecretStorePrivateKey( txn: IDBTransaction, @@ -394,8 +387,8 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Returns the number of end-to-end sessions in the store - * @param {*} txn An active transaction. See doTxn(). - * @param {function(int)} func Called with the count of sessions + * @param txn - An active transaction. See doTxn(). + * @param func - Called with the count of sessions */ public countEndToEndSessions(txn: IDBTransaction, func: (count: number) => void): void { this.backend!.countEndToEndSessions(txn, func); @@ -404,10 +397,10 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Retrieve a specific end-to-end session between the logged-in user * and another device. - * @param {string} deviceKey The public key of the other device. - * @param {string} sessionId The ID of the session to retrieve - * @param {*} txn An active transaction. See doTxn(). - * @param {function(object)} func Called with A map from sessionId + * @param deviceKey - The public key of the other device. + * @param sessionId - The ID of the session to retrieve + * @param txn - An active transaction. See doTxn(). + * @param func - Called with A map from sessionId * to session information object with 'session' key being the * Base64 end-to-end session and lastReceivedMessageTs being the * timestamp in milliseconds at which the session last received @@ -425,9 +418,9 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Retrieve the end-to-end sessions between the logged-in user and another * device. - * @param {string} deviceKey The public key of the other device. - * @param {*} txn An active transaction. See doTxn(). - * @param {function(object)} func Called with A map from sessionId + * @param deviceKey - The public key of the other device. + * @param txn - An active transaction. See doTxn(). + * @param func - Called with A map from sessionId * to session information object with 'session' key being the * Base64 end-to-end session and lastReceivedMessageTs being the * timestamp in milliseconds at which the session last received @@ -443,8 +436,8 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Retrieve all end-to-end sessions - * @param {*} txn An active transaction. See doTxn(). - * @param {function(object)} func Called one for each session with + * @param txn - An active transaction. See doTxn(). + * @param func - Called one for each session with * an object with, deviceKey, lastReceivedMessageTs, sessionId * and session keys. */ @@ -454,10 +447,10 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Store a session between the logged-in user and another device - * @param {string} deviceKey The public key of the other device. - * @param {string} sessionId The ID for this end-to-end session. - * @param {string} sessionInfo Session information object - * @param {*} txn An active transaction. See doTxn(). + * @param deviceKey - The public key of the other device. + * @param sessionId - The ID for this end-to-end session. + * @param sessionInfo - Session information object + * @param txn - An active transaction. See doTxn(). */ public storeEndToEndSession( deviceKey: string, @@ -485,10 +478,10 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Retrieve the end-to-end inbound group session for a given * server key and session ID - * @param {string} senderCurve25519Key The sender's curve 25519 key - * @param {string} sessionId The ID of the session - * @param {*} txn An active transaction. See doTxn(). - * @param {function(object)} func Called with A map from sessionId + * @param senderCurve25519Key - The sender's curve 25519 key + * @param sessionId - The ID of the session + * @param txn - An active transaction. See doTxn(). + * @param func - Called with A map from sessionId * to Base64 end-to-end session. */ public getEndToEndInboundGroupSession( @@ -502,10 +495,10 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Fetches all inbound group sessions in the store - * @param {*} txn An active transaction. See doTxn(). - * @param {function(object)} func Called once for each group session - * in the store with an object having keys {senderKey, sessionId, - * sessionData}, then once with null to indicate the end of the list. + * @param txn - An active transaction. See doTxn(). + * @param func - Called once for each group session + * in the store with an object having keys `{senderKey, sessionId, sessionData}`, + * then once with null to indicate the end of the list. */ public getAllEndToEndInboundGroupSessions( txn: IDBTransaction, @@ -518,10 +511,10 @@ export class IndexedDBCryptoStore implements CryptoStore { * Adds an end-to-end inbound group session to the store. * If there already exists an inbound group session with the same * senderCurve25519Key and sessionID, the session will not be added. - * @param {string} senderCurve25519Key The sender's curve 25519 key - * @param {string} sessionId The ID of the session - * @param {object} sessionData The session data structure - * @param {*} txn An active transaction. See doTxn(). + * @param senderCurve25519Key - The sender's curve 25519 key + * @param sessionId - The ID of the session + * @param sessionData - The session data structure + * @param txn - An active transaction. See doTxn(). */ public addEndToEndInboundGroupSession( senderCurve25519Key: string, @@ -536,10 +529,10 @@ export class IndexedDBCryptoStore implements CryptoStore { * Writes an end-to-end inbound group session to the store. * If there already exists an inbound group session with the same * senderCurve25519Key and sessionID, it will be overwritten. - * @param {string} senderCurve25519Key The sender's curve 25519 key - * @param {string} sessionId The ID of the session - * @param {object} sessionData The session data structure - * @param {*} txn An active transaction. See doTxn(). + * @param senderCurve25519Key - The sender's curve 25519 key + * @param sessionId - The ID of the session + * @param sessionData - The session data structure + * @param txn - An active transaction. See doTxn(). */ public storeEndToEndInboundGroupSession( senderCurve25519Key: string, @@ -568,8 +561,7 @@ export class IndexedDBCryptoStore implements CryptoStore { * These all need to be written out in full each time such that the snapshot * is always consistent, so they are stored in one object. * - * @param {Object} deviceData - * @param {*} txn An active transaction. See doTxn(). + * @param txn - An active transaction. See doTxn(). */ public storeEndToEndDeviceData(deviceData: IDeviceData, txn: IDBTransaction): void { this.backend!.storeEndToEndDeviceData(deviceData, txn); @@ -578,8 +570,8 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Get the state of all tracked devices * - * @param {*} txn An active transaction. See doTxn(). - * @param {function(Object)} func Function called with the + * @param txn - An active transaction. See doTxn(). + * @param func - Function called with the * device data */ public getEndToEndDeviceData(txn: IDBTransaction, func: (deviceData: IDeviceData | null) => void): void { @@ -590,18 +582,18 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Store the end-to-end state for a room. - * @param {string} roomId The room's ID. - * @param {object} roomInfo The end-to-end info for the room. - * @param {*} txn An active transaction. See doTxn(). + * @param roomId - The room's ID. + * @param roomInfo - The end-to-end info for the room. + * @param txn - An active transaction. See doTxn(). */ public storeEndToEndRoom(roomId: string, roomInfo: IRoomEncryption, txn: IDBTransaction): void { this.backend!.storeEndToEndRoom(roomId, roomInfo, txn); } /** - * Get an object of roomId->roomInfo for all e2e rooms in the store - * @param {*} txn An active transaction. See doTxn(). - * @param {function(Object)} func Function called with the end to end encrypted rooms + * Get an object of `roomId->roomInfo` for all e2e rooms in the store + * @param txn - An active transaction. See doTxn(). + * @param func - Function called with the end-to-end encrypted rooms */ public getEndToEndRooms(txn: IDBTransaction, func: (rooms: Record) => void): void { this.backend!.getEndToEndRooms(txn, func); @@ -611,9 +603,9 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Get the inbound group sessions that need to be backed up. - * @param {number} limit The maximum number of sessions to retrieve. 0 + * @param limit - The maximum number of sessions to retrieve. 0 * for no limit. - * @returns {Promise} resolves to an array of inbound group sessions + * @returns resolves to an array of inbound group sessions */ public getSessionsNeedingBackup(limit: number): Promise { return this.backend!.getSessionsNeedingBackup(limit); @@ -621,8 +613,8 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Count the inbound group sessions that need to be backed up. - * @param {*} txn An active transaction. See doTxn(). (optional) - * @returns {Promise} resolves to the number of sessions + * @param txn - An active transaction. See doTxn(). (optional) + * @returns resolves to the number of sessions */ public countSessionsNeedingBackup(txn?: IDBTransaction): Promise { return this.backend!.countSessionsNeedingBackup(txn); @@ -630,9 +622,9 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Unmark sessions as needing to be backed up. - * @param {Array} sessions The sessions that need to be backed up. - * @param {*} txn An active transaction. See doTxn(). (optional) - * @returns {Promise} resolves when the sessions are unmarked + * @param sessions - The sessions that need to be backed up. + * @param txn - An active transaction. See doTxn(). (optional) + * @returns resolves when the sessions are unmarked */ public unmarkSessionsNeedingBackup(sessions: ISession[], txn?: IDBTransaction): Promise { return this.backend!.unmarkSessionsNeedingBackup(sessions, txn); @@ -640,9 +632,9 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Mark sessions as needing to be backed up. - * @param {Array} sessions The sessions that need to be backed up. - * @param {*} txn An active transaction. See doTxn(). (optional) - * @returns {Promise} resolves when the sessions are marked + * @param sessions - The sessions that need to be backed up. + * @param txn - An active transaction. See doTxn(). (optional) + * @returns resolves when the sessions are marked */ public markSessionsNeedingBackup(sessions: ISession[], txn?: IDBTransaction): Promise { return this.backend!.markSessionsNeedingBackup(sessions, txn); @@ -650,10 +642,10 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Add a shared-history group session for a room. - * @param {string} roomId The room that the key belongs to - * @param {string} senderKey The sender's curve 25519 key - * @param {string} sessionId The ID of the session - * @param {*} txn An active transaction. See doTxn(). (optional) + * @param roomId - The room that the key belongs to + * @param senderKey - The sender's curve 25519 key + * @param sessionId - The ID of the session + * @param txn - An active transaction. See doTxn(). (optional) */ public addSharedHistoryInboundGroupSession( roomId: string, @@ -666,9 +658,9 @@ export class IndexedDBCryptoStore implements CryptoStore { /** * Get the shared-history group session for a room. - * @param {string} roomId The room that the key belongs to - * @param {*} txn An active transaction. See doTxn(). (optional) - * @returns {Promise} Resolves to an array of [senderKey, sessionId] + * @param roomId - The room that the key belongs to + * @param txn - An active transaction. See doTxn(). (optional) + * @returns Promise which resolves to an array of [senderKey, sessionId] */ public getSharedHistoryInboundGroupSessions( roomId: string, @@ -704,16 +696,16 @@ export class IndexedDBCryptoStore implements CryptoStore { * only be called within a callback of either this function or * one of the store functions operating on the same transaction. * - * @param {string} mode 'readwrite' if you need to call setter + * @param mode - 'readwrite' if you need to call setter * functions with this transaction. Otherwise, 'readonly'. - * @param {string[]} stores List IndexedDBCryptoStore.STORE_* + * @param stores - List IndexedDBCryptoStore.STORE_* * options representing all types of object that will be * accessed or written to with this transaction. - * @param {function(*)} func Function called with the + * @param func - Function called with the * transaction object: an opaque object that should be passed * to store functions. - * @param {Logger} [log] A possibly customised log - * @return {Promise} Promise that resolves with the result of the `func` + * @param log - A possibly customised log + * @returns Promise that resolves with the result of the `func` * when the transaction is complete. If the backend is * async (ie. the indexeddb backend) any of the callback * functions throwing an exception will cause this promise to diff --git a/src/crypto/store/localStorage-crypto-store.ts b/src/crypto/store/localStorage-crypto-store.ts index c6f9a02d6..04815cf15 100644 --- a/src/crypto/store/localStorage-crypto-store.ts +++ b/src/crypto/store/localStorage-crypto-store.ts @@ -28,8 +28,6 @@ import { InboundGroupSessionData } from "../OlmDevice"; * some things backed by localStorage. It exists because indexedDB * is broken in Firefox private mode or set to, "will not remember * history". - * - * @module */ const E2E_PREFIX = "crypto."; @@ -62,9 +60,6 @@ function keyEndToEndRoomsPrefix(roomId: string): string { return KEY_ROOMS_PREFIX + roomId; } -/** - * @implements {module:crypto/store/base~CryptoStore} - */ export class LocalStorageCryptoStore extends MemoryCryptoStore { public static exists(store: Storage): boolean { const length = store.length; @@ -364,7 +359,7 @@ export class LocalStorageCryptoStore extends MemoryCryptoStore { /** * Delete all data from this store. * - * @returns {Promise} Promise which resolves when the store has been cleared. + * @returns Promise which resolves when the store has been cleared. */ public deleteAllData(): Promise { this.store.removeItem(KEY_END_TO_END_ACCOUNT); diff --git a/src/crypto/store/memory-crypto-store.ts b/src/crypto/store/memory-crypto-store.ts index f22379ee8..701f85fc3 100644 --- a/src/crypto/store/memory-crypto-store.ts +++ b/src/crypto/store/memory-crypto-store.ts @@ -35,13 +35,8 @@ import { InboundGroupSessionData } from "../OlmDevice"; /** * Internal module. in-memory storage for e2e. - * - * @module */ -/** - * @implements {module:crypto/store/base~CryptoStore} - */ export class MemoryCryptoStore implements CryptoStore { private outgoingRoomKeyRequests: OutgoingRoomKeyRequest[] = []; private account: string | null = null; @@ -65,7 +60,7 @@ export class MemoryCryptoStore implements CryptoStore { * * This must be called before the store can be used. * - * @return {Promise} resolves to the store. + * @returns resolves to the store. */ public async startup(): Promise { // No startup work to do for the memory store. @@ -75,7 +70,7 @@ export class MemoryCryptoStore implements CryptoStore { /** * Delete all data from this store. * - * @returns {Promise} Promise which resolves when the store has been cleared. + * @returns Promise which resolves when the store has been cleared. */ public deleteAllData(): Promise { return Promise.resolve(); @@ -85,10 +80,9 @@ export class MemoryCryptoStore implements CryptoStore { * Look for an existing outgoing room key request, and if none is found, * add a new one * - * @param {module:crypto/store/base~OutgoingRoomKeyRequest} request * - * @returns {Promise} resolves to - * {@link module:crypto/store/base~OutgoingRoomKeyRequest}: either the + * @returns resolves to + * {@link OutgoingRoomKeyRequest}: either the * same instance as passed in, or the existing one. */ public getOrAddOutgoingRoomKeyRequest(request: OutgoingRoomKeyRequest): Promise { @@ -122,11 +116,10 @@ export class MemoryCryptoStore implements CryptoStore { /** * Look for an existing room key request * - * @param {module:crypto~RoomKeyRequestBody} requestBody - * existing request to look for + * @param requestBody - existing request to look for * - * @return {Promise} resolves to the matching - * {@link module:crypto/store/base~OutgoingRoomKeyRequest}, or null if + * @returns resolves to the matching + * {@link OutgoingRoomKeyRequest}, or null if * not found */ public getOutgoingRoomKeyRequest(requestBody: IRoomKeyRequestBody): Promise { @@ -138,10 +131,9 @@ export class MemoryCryptoStore implements CryptoStore { * * @internal * - * @param {module:crypto~RoomKeyRequestBody} requestBody - * existing request to look for + * @param requestBody - existing request to look for * - * @return {module:crypto/store/base~OutgoingRoomKeyRequest?} + * @returns * the matching request, or null if not found */ // eslint-disable-next-line @typescript-eslint/naming-convention @@ -157,10 +149,10 @@ export class MemoryCryptoStore implements CryptoStore { /** * Look for room key requests by state * - * @param {Array} wantedStates list of acceptable states + * @param wantedStates - list of acceptable states * - * @return {Promise} resolves to the a - * {@link module:crypto/store/base~OutgoingRoomKeyRequest}, or null if + * @returns resolves to the a + * {@link OutgoingRoomKeyRequest}, or null if * there are no pending requests in those states */ public getOutgoingRoomKeyRequestByState(wantedStates: number[]): Promise { @@ -176,8 +168,7 @@ export class MemoryCryptoStore implements CryptoStore { /** * - * @param {Number} wantedState - * @return {Promise>} All OutgoingRoomKeyRequests in state + * @returns All OutgoingRoomKeyRequests in state */ public getAllOutgoingRoomKeyRequestsByState(wantedState: number): Promise { return Promise.resolve( @@ -210,12 +201,12 @@ export class MemoryCryptoStore implements CryptoStore { * Look for an existing room key request by id and state, and update it if * found * - * @param {string} requestId ID of request to update - * @param {number} expectedState state we expect to find the request in - * @param {Object} updates name/value map of updates to apply + * @param requestId - ID of request to update + * @param expectedState - state we expect to find the request in + * @param updates - name/value map of updates to apply * - * @returns {Promise} resolves to - * {@link module:crypto/store/base~OutgoingRoomKeyRequest} + * @returns resolves to + * {@link OutgoingRoomKeyRequest} * updated request, or null if no matching row was found */ public updateOutgoingRoomKeyRequest( @@ -246,10 +237,10 @@ export class MemoryCryptoStore implements CryptoStore { * Look for an existing room key request by id and state, and delete it if * found * - * @param {string} requestId ID of request to update - * @param {number} expectedState state we expect to find the request in + * @param requestId - ID of request to update + * @param expectedState - state we expect to find the request in * - * @returns {Promise} resolves once the operation is completed + * @returns resolves once the operation is completed */ public deleteOutgoingRoomKeyRequest( requestId: string, diff --git a/src/crypto/verification/Base.ts b/src/crypto/verification/Base.ts index 55b349e99..f2644b557 100644 --- a/src/crypto/verification/Base.ts +++ b/src/crypto/verification/Base.ts @@ -17,7 +17,6 @@ limitations under the License. /** * Base class for verification methods. - * @module crypto/verification/Base */ import { MatrixEvent } from '../../models/event'; @@ -74,21 +73,19 @@ export class VerificationBase< * *

Subclasses must have a NAME class property.

* - * @class - * - * @param {Object} channel the verification channel to send verification messages over. + * @param channel - the verification channel to send verification messages over. * TODO: Channel types * - * @param {MatrixClient} baseApis base matrix api interface + * @param baseApis - base matrix api interface * - * @param {string} userId the user ID that is being verified + * @param userId - the user ID that is being verified * - * @param {string} deviceId the device ID that is being verified + * @param deviceId - the device ID that is being verified * - * @param {object} [startEvent] the m.key.verification.start event that + * @param startEvent - the m.key.verification.start event that * initiated this verification, if any * - * @param {object} [request] the key verification request object related to + * @param request - the key verification request object related to * this verification, if any */ public constructor( @@ -279,7 +276,7 @@ export class VerificationBase< /** * Begin the key verification * - * @returns {Promise} Promise which resolves when the verification has + * @returns Promise which resolves when the verification has * completed. */ public verify(): Promise { diff --git a/src/crypto/verification/Error.ts b/src/crypto/verification/Error.ts index ca0fb20b5..0ad50b2ff 100644 --- a/src/crypto/verification/Error.ts +++ b/src/crypto/verification/Error.ts @@ -16,8 +16,6 @@ limitations under the License. /** * Error messages. - * - * @module crypto/verification/Error */ import { MatrixEvent } from "../../models/event"; diff --git a/src/crypto/verification/IllegalMethod.ts b/src/crypto/verification/IllegalMethod.ts index f01364a21..c437e0cd2 100644 --- a/src/crypto/verification/IllegalMethod.ts +++ b/src/crypto/verification/IllegalMethod.ts @@ -17,7 +17,6 @@ limitations under the License. /** * Verification method that is illegal to have (cannot possibly * do verification with this method). - * @module crypto/verification/IllegalMethod */ import { VerificationBase as Base, VerificationEvent, VerificationEventHandlerMap } from "./Base"; @@ -26,10 +25,6 @@ import { MatrixClient } from "../../client"; import { MatrixEvent } from "../../models/event"; import { VerificationRequest } from "./request/VerificationRequest"; -/** - * @class crypto/verification/IllegalMethod/IllegalMethod - * @extends {module:crypto/verification/Base} - */ export class IllegalMethod extends Base { public static factory( channel: IVerificationChannel, diff --git a/src/crypto/verification/QRCode.ts b/src/crypto/verification/QRCode.ts index 13053280d..c5c2735bc 100644 --- a/src/crypto/verification/QRCode.ts +++ b/src/crypto/verification/QRCode.ts @@ -16,7 +16,6 @@ limitations under the License. /** * QR code key verification. - * @module crypto/verification/QRCode */ import { VerificationBase as Base, VerificationEventHandlerMap } from "./Base"; @@ -44,10 +43,6 @@ type EventHandlerMap = { [QrCodeEvent.ShowReciprocateQr]: (qr: IReciprocateQr) => void; } & VerificationEventHandlerMap; -/** - * @class crypto/verification/QRCode/ReciprocateQRCode - * @extends {module:crypto/verification/Base} - */ export class ReciprocateQRCode extends Base { public reciprocateQREvent?: IReciprocateQr; diff --git a/src/crypto/verification/SAS.ts b/src/crypto/verification/SAS.ts index 168a85d28..9d831f5c6 100644 --- a/src/crypto/verification/SAS.ts +++ b/src/crypto/verification/SAS.ts @@ -16,7 +16,6 @@ limitations under the License. /** * Short Authentication String (SAS) verification. - * @module crypto/verification/SAS */ import anotherjson from 'another-json'; @@ -232,10 +231,6 @@ type EventHandlerMap = { [SasEvent.ShowSas]: (sas: ISasEvent) => void; } & VerificationEventHandlerMap; -/** - * @alias module:crypto/verification/SAS - * @extends {module:crypto/verification/Base} - */ export class SAS extends Base { private waitingForAccept?: boolean; public ourSASPubKey?: string; diff --git a/src/crypto/verification/SASDecimal.ts b/src/crypto/verification/SASDecimal.ts index c8fa73100..26dc8d2a0 100644 --- a/src/crypto/verification/SASDecimal.ts +++ b/src/crypto/verification/SASDecimal.ts @@ -17,11 +17,11 @@ limitations under the License. /** * Implementation of decimal encoding of SAS as per: * https://spec.matrix.org/v1.4/client-server-api/#sas-method-decimal - * @param sasBytes the five bytes generated by HKDF + * @param sasBytes - the five bytes generated by HKDF * @returns the derived three numbers between 1000 and 9191 inclusive */ export function generateDecimalSas(sasBytes: number[]): [number, number, number] { - /** + /* * +--------+--------+--------+--------+--------+ * | Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 | * +--------+--------+--------+--------+--------+ diff --git a/src/crypto/verification/request/InRoomChannel.ts b/src/crypto/verification/request/InRoomChannel.ts index 664a2dad6..edbf31f63 100644 --- a/src/crypto/verification/request/InRoomChannel.ts +++ b/src/crypto/verification/request/InRoomChannel.ts @@ -40,9 +40,9 @@ export class InRoomChannel implements IVerificationChannel { private requestEventId?: string; /** - * @param {MatrixClient} client the matrix client, to send messages with and get current user & device from. - * @param {string} roomId id of the room where verification events should be posted in, should be a DM with the given user. - * @param {string} userId id of user that the verification request is directed at, should be present in the room. + * @param client - the matrix client, to send messages with and get current user & device from. + * @param roomId - id of the room where verification events should be posted in, should be a DM with the given user. + * @param userId - id of user that the verification request is directed at, should be present in the room. */ public constructor( private readonly client: MatrixClient, @@ -78,8 +78,8 @@ export class InRoomChannel implements IVerificationChannel { } /** - * @param {MatrixEvent} event the event to get the timestamp of - * @return {number} the timestamp when the event was sent + * @param event - the event to get the timestamp of + * @returns the timestamp when the event was sent */ public getTimestamp(event: MatrixEvent): number { return event.getTs(); @@ -87,8 +87,8 @@ export class InRoomChannel implements IVerificationChannel { /** * Checks whether the given event type should be allowed to initiate a new VerificationRequest over this channel - * @param {string} type the event type to check - * @returns {boolean} boolean flag + * @param type - the event type to check + * @returns boolean flag */ public static canCreateRequest(type: string): boolean { return type === REQUEST_TYPE; @@ -100,8 +100,8 @@ export class InRoomChannel implements IVerificationChannel { /** * Extract the transaction id used by a given key verification event, if any - * @param {MatrixEvent} event the event - * @returns {string} the transaction id + * @param event - the event + * @returns the transaction id */ public static getTransactionId(event: MatrixEvent): string | undefined { if (InRoomChannel.getEventType(event) === REQUEST_TYPE) { @@ -119,9 +119,9 @@ export class InRoomChannel implements IVerificationChannel { * This only does checks that don't rely on the current state of a potentially already channel * so we can prevent channels being created by invalid events. * `handleEvent` can do more checks and choose to ignore invalid events. - * @param {MatrixEvent} event the event to validate - * @param {MatrixClient} client the client to get the current user and device id from - * @returns {boolean} whether the event is valid and should be passed to handleEvent + * @param event - the event to validate + * @param client - the client to get the current user and device id from + * @returns whether the event is valid and should be passed to handleEvent */ public static validateEvent(event: MatrixEvent, client: MatrixClient): boolean { const txnId = InRoomChannel.getTransactionId(event); @@ -156,8 +156,8 @@ export class InRoomChannel implements IVerificationChannel { * As m.key.verification.request events are as m.room.message events with the InRoomChannel * to have a fallback message in non-supporting clients, we map the real event type * to the symbolic one to keep things in unison with ToDeviceChannel - * @param {MatrixEvent} event the event to get the type of - * @returns {string} the "symbolic" event type + * @param event - the event to get the type of + * @returns the "symbolic" event type */ public static getEventType(event: MatrixEvent): string { const type = event.getType(); @@ -179,10 +179,10 @@ export class InRoomChannel implements IVerificationChannel { /** * Changes the state of the channel, request, and verifier in response to a key verification event. - * @param {MatrixEvent} event to handle - * @param {VerificationRequest} request the request to forward handling to - * @param {boolean} isLiveEvent whether this is an even received through sync or not - * @returns {Promise} a promise that resolves when any requests as an answer to the passed-in event are sent. + * @param event - to handle + * @param request - the request to forward handling to + * @param isLiveEvent - whether this is an even received through sync or not + * @returns a promise that resolves when any requests as an answer to the passed-in event are sent. */ public async handleEvent(event: MatrixEvent, request: VerificationRequest, isLiveEvent = false): Promise { // prevent processing the same event multiple times, as under @@ -228,8 +228,8 @@ export class InRoomChannel implements IVerificationChannel { * so it has the same format as returned by `completeContent` before sending. * The relation can not appear on the event content because of encryption, * relations are excluded from encryption. - * @param {MatrixEvent} event the received event - * @returns {Object} the content object with the relation added again + * @param event - the received event + * @returns the content object with the relation added again */ public completedContentFromEvent(event: MatrixEvent): Record { // ensure m.related_to is included in e2ee rooms @@ -244,9 +244,9 @@ export class InRoomChannel implements IVerificationChannel { * This is public so verification methods (SAS uses this) can get the exact * content that will be sent independent of the used channel, * as they need to calculate the hash of it. - * @param {string} type the event type - * @param {object} content the (incomplete) content - * @returns {object} the complete content, as it will be sent. + * @param type - the event type + * @param content - the (incomplete) content + * @returns the complete content, as it will be sent. */ public completeContent(type: string, content: Record): Record { content = Object.assign({}, content); @@ -276,9 +276,9 @@ export class InRoomChannel implements IVerificationChannel { /** * Send an event over the channel with the content not having gone through `completeContent`. - * @param {string} type the event type - * @param {object} uncompletedContent the (incomplete) content - * @returns {Promise} the promise of the request + * @param type - the event type + * @param uncompletedContent - the (incomplete) content + * @returns the promise of the request */ public send(type: string, uncompletedContent: Record): Promise { const content = this.completeContent(type, uncompletedContent); @@ -287,9 +287,8 @@ export class InRoomChannel implements IVerificationChannel { /** * Send an event over the channel with the content having gone through `completeContent` already. - * @param {string} type the event type - * @param {object} content - * @returns {Promise} the promise of the request + * @param type - the event type + * @returns the promise of the request */ public async sendCompleted(type: string, content: Record): Promise { let sendType = type; diff --git a/src/crypto/verification/request/ToDeviceChannel.ts b/src/crypto/verification/request/ToDeviceChannel.ts index 30d615251..5d92c3ed1 100644 --- a/src/crypto/verification/request/ToDeviceChannel.ts +++ b/src/crypto/verification/request/ToDeviceChannel.ts @@ -69,8 +69,8 @@ export class ToDeviceChannel implements IVerificationChannel { /** * Extract the transaction id used by a given key verification event, if any - * @param {MatrixEvent} event the event - * @returns {string} the transaction id + * @param event - the event + * @returns the transaction id */ public static getTransactionId(event: MatrixEvent): string { const content = event.getContent(); @@ -79,8 +79,8 @@ export class ToDeviceChannel implements IVerificationChannel { /** * Checks whether the given event type should be allowed to initiate a new VerificationRequest over this channel - * @param {string} type the event type to check - * @returns {boolean} boolean flag + * @param type - the event type to check + * @returns boolean flag */ public static canCreateRequest(type: string): boolean { return type === REQUEST_TYPE || type === START_TYPE; @@ -95,9 +95,9 @@ export class ToDeviceChannel implements IVerificationChannel { * This only does checks that don't rely on the current state of a potentially already channel * so we can prevent channels being created by invalid events. * `handleEvent` can do more checks and choose to ignore invalid events. - * @param {MatrixEvent} event the event to validate - * @param {MatrixClient} client the client to get the current user and device id from - * @returns {boolean} whether the event is valid and should be passed to handleEvent + * @param event - the event to validate + * @param client - the client to get the current user and device id from + * @returns whether the event is valid and should be passed to handleEvent */ public static validateEvent(event: MatrixEvent, client: MatrixClient): boolean { if (event.isCancelled()) { @@ -137,8 +137,8 @@ export class ToDeviceChannel implements IVerificationChannel { } /** - * @param {MatrixEvent} event the event to get the timestamp of - * @return {number} the timestamp when the event was sent + * @param event - the event to get the timestamp of + * @returns the timestamp when the event was sent */ public getTimestamp(event: MatrixEvent): number { const content = event.getContent(); @@ -147,10 +147,10 @@ export class ToDeviceChannel implements IVerificationChannel { /** * Changes the state of the channel, request, and verifier in response to a key verification event. - * @param {MatrixEvent} event to handle - * @param {VerificationRequest} request the request to forward handling to - * @param {boolean} isLiveEvent whether this is an even received through sync or not - * @returns {Promise} a promise that resolves when any requests as an answer to the passed-in event are sent. + * @param event - to handle + * @param request - the request to forward handling to + * @param isLiveEvent - whether this is an even received through sync or not + * @returns a promise that resolves when any requests as an answer to the passed-in event are sent. */ public async handleEvent(event: MatrixEvent, request: Request, isLiveEvent = false): Promise { const type = event.getType(); @@ -196,9 +196,9 @@ export class ToDeviceChannel implements IVerificationChannel { } /** - * See {InRoomChannel.completedContentFromEvent} why this is needed. - * @param {MatrixEvent} event the received event - * @returns {Object} the content object + * See {@link InRoomChannel#completedContentFromEvent} for why this is needed. + * @param event - the received event + * @returns the content object */ public completedContentFromEvent(event: MatrixEvent): Record { return event.getContent(); @@ -209,9 +209,9 @@ export class ToDeviceChannel implements IVerificationChannel { * This is public so verification methods (SAS uses this) can get the exact * content that will be sent independent of the used channel, * as they need to calculate the hash of it. - * @param {string} type the event type - * @param {object} content the (incomplete) content - * @returns {object} the complete content, as it will be sent. + * @param type - the event type + * @param content - the (incomplete) content + * @returns the complete content, as it will be sent. */ public completeContent(type: string, content: Record): Record { // make a copy @@ -230,9 +230,9 @@ export class ToDeviceChannel implements IVerificationChannel { /** * Send an event over the channel with the content not having gone through `completeContent`. - * @param {string} type the event type - * @param {object} uncompletedContent the (incomplete) content - * @returns {Promise} the promise of the request + * @param type - the event type + * @param uncompletedContent - the (incomplete) content + * @returns the promise of the request */ public send(type: string, uncompletedContent: Record = {}): Promise { // create transaction id when sending request @@ -245,9 +245,8 @@ export class ToDeviceChannel implements IVerificationChannel { /** * Send an event over the channel with the content having gone through `completeContent` already. - * @param {string} type the event type - * @param {object} content - * @returns {Promise} the promise of the request + * @param type - the event type + * @returns the promise of the request */ public async sendCompleted(type: string, content: Record): Promise { let result; @@ -286,7 +285,7 @@ export class ToDeviceChannel implements IVerificationChannel { /** * Allow Crypto module to create and know the transaction id before the .start event gets sent. - * @returns {string} the transaction id + * @returns the transaction id */ public static makeTransactionId(): string { return randomString(32); diff --git a/src/crypto/verification/request/VerificationRequest.ts b/src/crypto/verification/request/VerificationRequest.ts index 58de4b9a2..05f0cd75c 100644 --- a/src/crypto/verification/request/VerificationRequest.ts +++ b/src/crypto/verification/request/VerificationRequest.ts @@ -81,6 +81,9 @@ export enum VerificationRequestEvent { } type EventHandlerMap = { + /** + * Fires whenever the state of the request object has changed. + */ [VerificationRequestEvent.Change]: () => void; }; @@ -88,7 +91,6 @@ type EventHandlerMap = { * State machine for verification requests. * Things that differ based on what channel is used to * send and receive verification events are put in `InRoomChannel` or `ToDeviceChannel`. - * @event "change" whenever the state of the request object has changed. */ export class VerificationRequest< C extends IVerificationChannel = IVerificationChannel, @@ -129,10 +131,10 @@ export class VerificationRequest< /** * Stateless validation logic not specific to the channel. * Invoked by the same static method in either channel. - * @param {string} type the "symbolic" event type, as returned by the `getEventType` function on the channel. - * @param {MatrixEvent} event the event to validate. Don't call getType() on it but use the `type` parameter instead. - * @param {MatrixClient} client the client to get the current user and device id from - * @returns {boolean} whether the event is valid and should be passed to handleEvent + * @param type - the "symbolic" event type, as returned by the `getEventType` function on the channel. + * @param event - the event to validate. Don't call getType() on it but use the `type` parameter instead. + * @param client - the client to get the current user and device id from + * @returns whether the event is valid and should be passed to handleEvent */ public static validateEvent(type: string, event: MatrixEvent, client: MatrixClient): boolean { const content = event.getContent(); @@ -234,7 +236,7 @@ export class VerificationRequest< /** * The key verification request event. - * @returns {MatrixEvent} The request event, or falsey if not found. + * @returns The request event, or falsey if not found. */ public get requestEvent(): MatrixEvent | undefined { return this.getEventByEither(REQUEST_TYPE); @@ -278,9 +280,9 @@ export class VerificationRequest< * This is useful when setting up the QR code UI, as it is somewhat asymmetrical: * if the other party supports SCAN_QR, we should show a QR code in the UI, and vice versa. * For methods that need to be supported by both ends, use the `methods` property. - * @param {string} method the method to check - * @param {boolean} force to check even if the phase is not ready or started yet, internal usage - * @return {boolean} whether or not the other party said the supported the method */ + * @param method - the method to check + * @param force - to check even if the phase is not ready or started yet, internal usage + * @returns whether or not the other party said the supported the method */ public otherPartySupportsMethod(method: string, force = false): boolean { if (!force && !this.ready && !this.started) { return false; @@ -398,7 +400,7 @@ export class VerificationRequest< * given the events sent so far in the verification. This is the * same algorithm used to determine which device to send the * verification to when no specific device is specified. - * @returns {{userId: *, deviceId: *}} The device information + * @returns The device information */ public get targetDevice(): ITargetDevice { const theirFirstEvent = @@ -415,10 +417,10 @@ export class VerificationRequest< /* Start the key verification, creating a verifier and sending a .start event. * If no previous events have been sent, pass in `targetDevice` to set who to direct this request to. - * @param {string} method the name of the verification method to use. - * @param {string?} targetDevice.userId the id of the user to direct this request to - * @param {string?} targetDevice.deviceId the id of the device to direct this request to - * @returns {VerifierBase} the verifier of the given method + * @param method - the name of the verification method to use. + * @param targetDevice.userId the id of the user to direct this request to + * @param targetDevice.deviceId the id of the device to direct this request to + * @returns the verifier of the given method */ public beginKeyVerification( method: VerificationMethod, @@ -448,7 +450,7 @@ export class VerificationRequest< /** * sends the initial .request event. - * @returns {Promise} resolves when the event has been sent. + * @returns resolves when the event has been sent. */ public async sendRequest(): Promise { if (!this.observeOnly && this._phase === PHASE_UNSENT) { @@ -459,9 +461,9 @@ export class VerificationRequest< /** * Cancels the request, sending a cancellation to the other party - * @param {string?} error.reason the error reason to send the cancellation with - * @param {string?} error.code the error code to send the cancellation with - * @returns {Promise} resolves when the event has been sent. + * @param reason - the error reason to send the cancellation with + * @param code - the error code to send the cancellation with + * @returns resolves when the event has been sent. */ public async cancel({ reason = "User declined", code = "m.user" } = {}): Promise { if (!this.observeOnly && this._phase !== PHASE_CANCELLED) { @@ -478,7 +480,7 @@ export class VerificationRequest< /** * Accepts the request, sending a .ready event to the other party - * @returns {Promise} resolves when the event has been sent. + * @returns resolves when the event has been sent. */ public async accept(): Promise { if (!this.observeOnly && this.phase === PHASE_REQUESTED && !this.initiatedByMe) { @@ -491,10 +493,10 @@ export class VerificationRequest< /** * Can be used to listen for state changes until the callback returns true. - * @param {Function} fn callback to evaluate whether the request is in the desired state. + * @param fn - callback to evaluate whether the request is in the desired state. * Takes the request as an argument. - * @returns {Promise} that resolves once the callback returns true - * @throws {Error} when the request is cancelled + * @returns that resolves once the callback returns true + * @throws Error when the request is cancelled */ public waitFor(fn: (request: VerificationRequest) => boolean): Promise { return new Promise((resolve, reject) => { @@ -701,13 +703,13 @@ export class VerificationRequest< /** * Changes the state of the request and verifier in response to a key verification event. - * @param {string} type the "symbolic" event type, as returned by the `getEventType` function on the channel. - * @param {MatrixEvent} event the event to handle. Don't call getType() on it but use the `type` parameter instead. - * @param {boolean} isLiveEvent whether this is an even received through sync or not - * @param {boolean} isRemoteEcho whether this is the remote echo of an event sent by the same device - * @param {boolean} isSentByUs whether this event is sent by a party that can accept and/or observe the request like one of our peers. + * @param type - the "symbolic" event type, as returned by the `getEventType` function on the channel. + * @param event - the event to handle. Don't call getType() on it but use the `type` parameter instead. + * @param isLiveEvent - whether this is an even received through sync or not + * @param isRemoteEcho - whether this is the remote echo of an event sent by the same device + * @param isSentByUs - whether this event is sent by a party that can accept and/or observe the request like one of our peers. * For InRoomChannel this means any device for the syncing user. For ToDeviceChannel, just the syncing device. - * @returns {Promise} a promise that resolves when any requests as an answer to the passed-in event are sent. + * @returns a promise that resolves when any requests as an answer to the passed-in event are sent. */ public async handleEvent( type: string, diff --git a/src/embedded.ts b/src/embedded.ts index 27cf564a6..c5cbab80d 100644 --- a/src/embedded.ts +++ b/src/embedded.ts @@ -85,7 +85,7 @@ export interface ICapabilities { /** * Whether this client needs access to TURN servers. - * @default false + * @defaultValue false */ turnServers?: boolean; } diff --git a/src/event-mapper.ts b/src/event-mapper.ts index 6f2e25c1b..d40f579b5 100644 --- a/src/event-mapper.ts +++ b/src/event-mapper.ts @@ -20,8 +20,11 @@ import { IEvent, MatrixEvent, MatrixEventEvent } from "./models/event"; export type EventMapper = (obj: Partial) => MatrixEvent; export interface MapperOpts { + // don't re-emit events emitted on an event mapped by this mapper on the client preventReEmit?: boolean; + // decrypt event proactively decrypt?: boolean; + // the event is a to_device event toDevice?: boolean; } diff --git a/src/filter-component.ts b/src/filter-component.ts index 0bda7d379..5a4601258 100644 --- a/src/filter-component.ts +++ b/src/filter-component.ts @@ -22,16 +22,12 @@ import { THREAD_RELATION_TYPE, } from "./models/thread"; -/** - * @module filter-component - */ - /** * Checks if a value matches a given field value, which may be a * terminated * wildcard pattern. - * @param {String} actualValue The value to be compared - * @param {String} filterValue The filter pattern to be compared - * @return {boolean} true if the actualValue matches the filterValue + * @param actualValue - The value to be compared + * @param filterValue - The filter pattern to be compared + * @returns true if the actualValue matches the filterValue */ function matchesWildcard(actualValue: string, filterValue: string): boolean { if (filterValue.endsWith("*")) { @@ -68,17 +64,14 @@ export interface IFilterComponent { * * N.B. that synapse refers to these as 'Filters', and what js-sdk refers to as * 'Filters' are referred to as 'FilterCollections'. - * - * @constructor - * @param {Object} filterJson the definition of this filter JSON, e.g. { 'contains_url': true } */ export class FilterComponent { public constructor(private filterJson: IFilterComponent, public readonly userId?: string | undefined | null) {} /** * Checks with the filter component matches the given event - * @param {MatrixEvent} event event to be checked against the filter - * @return {boolean} true if the event matches the filter + * @param event - event to be checked against the filter + * @returns true if the event matches the filter */ public check(event: MatrixEvent): boolean { const bundledRelationships = event.getUnsigned()?.["m.relations"] || {}; @@ -122,13 +115,13 @@ export class FilterComponent { /** * Checks whether the filter component matches the given event fields. - * @param {String} roomId the roomId for the event being checked - * @param {String} sender the sender of the event being checked - * @param {String} eventType the type of the event being checked - * @param {boolean} containsUrl whether the event contains a content.url field - * @param {boolean} relationTypes whether has aggregated relation of the given type - * @param {boolean} relationSenders whether one of the relation is sent by the user listed - * @return {boolean} true if the event fields match the filter + * @param roomId - the roomId for the event being checked + * @param sender - the sender of the event being checked + * @param eventType - the type of the event being checked + * @param containsUrl - whether the event contains a content.url field + * @param relationTypes - whether has aggregated relation of the given type + * @param relationSenders - whether one of the relation is sent by the user listed + * @returns true if the event fields match the filter */ private checkFields( roomId: string | undefined, @@ -194,8 +187,8 @@ export class FilterComponent { /** * Filters a list of events down to those which match this filter component - * @param {MatrixEvent[]} events Events to be checked against the filter component - * @return {MatrixEvent[]} events which matched the filter component + * @param events - Events to be checked against the filter component + * @returns events which matched the filter component */ public filter(events: MatrixEvent[]): MatrixEvent[] { return events.filter(this.check, this); @@ -204,7 +197,7 @@ export class FilterComponent { /** * Returns the limit field for a given filter component, providing a default of * 10 if none is otherwise specified. Cargo-culted from Synapse. - * @return {Number} the limit for this filter component. + * @returns the limit for this filter component. */ public limit(): number { return this.filterJson.limit !== undefined ? this.filterJson.limit : 10; diff --git a/src/filter.ts b/src/filter.ts index 665227017..b5dc7140b 100644 --- a/src/filter.ts +++ b/src/filter.ts @@ -14,10 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/** - * @module filter - */ - import { EventType, RelationType, @@ -27,9 +23,6 @@ import { FilterComponent, IFilterComponent } from "./filter-component"; import { MatrixEvent } from "./models/event"; /** - * @param {Object} obj - * @param {string} keyNesting - * @param {*} val */ function setProp(obj: Record, keyNesting: string, val: any): void { const nestedKeys = keyNesting.split(".") as [keyof typeof obj]; @@ -78,14 +71,6 @@ interface IRoomFilter { } /* eslint-enable camelcase */ -/** - * Construct a new Filter. - * @constructor - * @param {string} userId The user ID for this filter. - * @param {string=} filterId The filter ID if known. - * @prop {string} userId The user ID of the filter - * @prop {?string} filterId The filter ID - */ export class Filter { public static LAZY_LOADING_MESSAGES_FILTER = { lazy_load_members: true, @@ -93,11 +78,6 @@ export class Filter { /** * Create a filter from existing data. - * @static - * @param {string} userId - * @param {string} filterId - * @param {Object} jsonObj - * @return {Filter} */ public static fromJson(userId: string | undefined | null, filterId: string, jsonObj: IFilterDefinition): Filter { const filter = new Filter(userId, filterId); @@ -109,11 +89,16 @@ export class Filter { private roomFilter?: FilterComponent; private roomTimelineFilter?: FilterComponent; + /** + * Construct a new Filter. + * @param userId - The user ID for this filter. + * @param filterId - The filter ID if known. + */ public constructor(public readonly userId: string | undefined | null, public filterId?: string) {} /** * Get the ID of this filter on your homeserver (if known) - * @return {?string} The filter ID + * @returns The filter ID */ public getFilterId(): string | undefined { return this.filterId; @@ -121,7 +106,7 @@ export class Filter { /** * Get the JSON body of the filter. - * @return {Object} The filter definition + * @returns The filter definition */ public getDefinition(): IFilterDefinition { return this.definition; @@ -129,7 +114,7 @@ export class Filter { /** * Set the JSON body of the filter - * @param {Object} definition The filter definition + * @param definition - The filter definition */ public setDefinition(definition: IFilterDefinition): void { this.definition = definition; @@ -198,7 +183,7 @@ export class Filter { /** * Get the room.timeline filter component of the filter - * @return {FilterComponent} room timeline filter component + * @returns room timeline filter component */ public getRoomTimelineFilterComponent(): FilterComponent | undefined { return this.roomTimelineFilter; @@ -207,8 +192,8 @@ export class Filter { /** * Filter the list of events based on whether they are allowed in a timeline * based on this filter - * @param {MatrixEvent[]} events the list of events being filtered - * @return {MatrixEvent[]} the list of events which match the filter + * @param events - the list of events being filtered + * @returns the list of events which match the filter */ public filterRoomTimeline(events: MatrixEvent[]): MatrixEvent[] { if (this.roomFilter) { @@ -222,7 +207,7 @@ export class Filter { /** * Set the max number of events to return for each room's timeline. - * @param {Number} limit The max number of events to return for each room. + * @param limit - The max number of events to return for each room. */ public setTimelineLimit(limit: number): void { setProp(this.definition, "room.timeline.limit", limit); @@ -230,7 +215,6 @@ export class Filter { /** * Enable threads unread notification - * @param {boolean} enabled */ public setUnreadThreadNotifications(enabled: boolean): void { this.definition = { @@ -251,7 +235,7 @@ export class Filter { /** * Control whether left rooms should be included in responses. - * @param {boolean} includeLeave True to make rooms the user has left appear + * @param includeLeave - True to make rooms the user has left appear * in responses. */ public setIncludeLeaveRooms(includeLeave: boolean): void { diff --git a/src/http-api/errors.ts b/src/http-api/errors.ts index 5ae0a0f50..e48fc029c 100644 --- a/src/http-api/errors.ts +++ b/src/http-api/errors.ts @@ -26,9 +26,8 @@ interface IErrorJson extends Partial { /** * Construct a generic HTTP error. This is a JavaScript Error with additional information * specific to HTTP responses. - * @constructor - * @param {string} msg The error message to include. - * @param {number} httpStatus The HTTP response status code. + * @param msg - The error message to include. + * @param httpStatus - The HTTP response status code. */ export class HTTPError extends Error { public constructor(msg: string, public readonly httpStatus?: number) { @@ -36,21 +35,18 @@ export class HTTPError extends Error { } } -/** - * Construct a Matrix error. This is a JavaScript Error with additional - * information specific to the standard Matrix error response. - * @constructor - * @param {Object} errorJson The Matrix error JSON returned from the homeserver. - * @prop {string} errcode The Matrix 'errcode' value, e.g. "M_FORBIDDEN". - * @prop {string} name Same as MatrixError.errcode but with a default unknown string. - * @prop {string} message The Matrix 'error' value, e.g. "Missing token." - * @prop {Object} data The raw Matrix error JSON used to construct this object. - * @prop {number} httpStatus The numeric HTTP status code given - */ export class MatrixError extends HTTPError { + // The Matrix 'errcode' value, e.g. "M_FORBIDDEN". public readonly errcode?: string; + // The raw Matrix error JSON used to construct this object. public data: IErrorJson; + /** + * Construct a Matrix error. This is a JavaScript Error with additional + * information specific to the standard Matrix error response. + * @param errorJson - The Matrix error JSON returned from the homeserver. + * @param httpStatus - The numeric HTTP status code given + */ public constructor( errorJson: IErrorJson = {}, public readonly httpStatus?: number, @@ -76,7 +72,6 @@ export class MatrixError extends HTTPError { * that a request failed because of some error with the connection, either * CORS was not correctly configured on the server, the server didn't response, * the request timed out, or the internet connection on the client side went down. - * @constructor */ export class ConnectionError extends Error { public constructor(message: string, cause?: Error) { diff --git a/src/http-api/fetch.ts b/src/http-api/fetch.ts index 71ba098e3..0c966d30d 100644 --- a/src/http-api/fetch.ts +++ b/src/http-api/fetch.ts @@ -16,7 +16,6 @@ limitations under the License. /** * This is an internal module. See {@link MatrixHttpApi} for the public class. - * @module http-api */ import * as utils from "../utils"; @@ -64,13 +63,13 @@ export class FetchHttpApi { /** * Sets the base URL for the identity server - * @param {string} url The new base url + * @param url - The new base url */ public setIdBaseUrl(url: string): void { this.opts.idBaseUrl = url; } - public idServerRequest( + public idServerRequest>( method: Method, path: string, params: Record | undefined, @@ -104,35 +103,29 @@ export class FetchHttpApi { /** * Perform an authorised request to the homeserver. - * @param {string} method The HTTP method e.g. "GET". - * @param {string} path The HTTP path after the supplied prefix e.g. + * @param method - The HTTP method e.g. "GET". + * @param path - The HTTP path after the supplied prefix e.g. * "/createRoom". * - * @param {Object=} queryParams A dict of query params (these will NOT be + * @param queryParams - A dict of query params (these will NOT be * urlencoded). If unspecified, there will be no query params. * - * @param {Object} [body] The HTTP JSON body. + * @param body - The HTTP JSON body. * - * @param {Object|Number=} opts additional options. If a number is specified, + * @param opts - additional options. If a number is specified, * this is treated as `opts.localTimeoutMs`. * - * @param {Number=} opts.localTimeoutMs The maximum amount of time to wait before - * timing out the request. If not specified, there is no timeout. - * - * @param {string=} opts.prefix The full prefix to use e.g. - * "/_matrix/client/v2_alpha". If not specified, uses this.opts.prefix. - * - * @param {string=} opts.baseUrl The alternative base url to use. - * If not specified, uses this.opts.baseUrl - * - * @param {Object=} opts.headers map of additional request headers - * - * @return {Promise} Resolves to {data: {Object}, - * headers: {Object}, code: {Number}}. - * If onlyData is set, this will resolve to the data - * object only. - * @return {module:http-api.MatrixError} Rejects with an error if a problem - * occurred. This includes network problems and Matrix-specific error JSON. + * @returns Promise which resolves to + * ``` + * { + * data: {Object}, + * headers: {Object}, + * code: {Number}, + * } + * ``` + * If `onlyData` is set, this will resolve to the `data` object only. + * @returns Rejects with an error if a problem occurred. + * This includes network problems and Matrix-specific error JSON. */ public authedRequest( method: Method, @@ -176,30 +169,28 @@ export class FetchHttpApi { /** * Perform a request to the homeserver without any credentials. - * @param {string} method The HTTP method e.g. "GET". - * @param {string} path The HTTP path after the supplied prefix e.g. + * @param method - The HTTP method e.g. "GET". + * @param path - The HTTP path after the supplied prefix e.g. * "/createRoom". * - * @param {Object=} queryParams A dict of query params (these will NOT be + * @param queryParams - A dict of query params (these will NOT be * urlencoded). If unspecified, there will be no query params. * - * @param {Object} [body] The HTTP JSON body. + * @param body - The HTTP JSON body. * - * @param {Object=} opts additional options + * @param opts - additional options * - * @param {Number=} opts.localTimeoutMs The maximum amount of time to wait before - * timing out the request. If not specified, there is no timeout. - * - * @param {string=} opts.prefix The full prefix to use e.g. - * "/_matrix/client/v2_alpha". If not specified, uses this.opts.prefix. - * - * @param {Object=} opts.headers map of additional request headers - * - * @return {Promise} Resolves to {data: {Object}, - * headers: {Object}, code: {Number}}. - * If onlyData is set, this will resolve to the data + * @returns Promise which resolves to + * ``` + * { + * data: {Object}, + * headers: {Object}, + * code: {Number}, + * } + * ``` + * If `onlyData is set, this will resolve to the data` * object only. - * @return {module:http-api.MatrixError} Rejects with an error if a problem + * @returns Rejects with an error if a problem * occurred. This includes network problems and Matrix-specific error JSON. */ public request( @@ -215,21 +206,16 @@ export class FetchHttpApi { /** * Perform a request to an arbitrary URL. - * @param {string} method The HTTP method e.g. "GET". - * @param {string} url The HTTP URL object. + * @param method - The HTTP method e.g. "GET". + * @param url - The HTTP URL object. * - * @param {Object} [body] The HTTP JSON body. + * @param body - The HTTP JSON body. * - * @param {Object=} opts additional options + * @param opts - additional options * - * @param {Number=} opts.localTimeoutMs The maximum amount of time to wait before - * timing out the request. If not specified, there is no timeout. - * - * @param {Object=} opts.headers map of additional request headers - * - * @return {Promise} Resolves to data unless `onlyData` is specified as false, + * @returns Promise which resolves to data unless `onlyData` is specified as false, * where the resolved value will be a fetch Response object. - * @return {module:http-api.MatrixError} Rejects with an error if a problem + * @returns Rejects with an error if a problem * occurred. This includes network problems and Matrix-specific error JSON. */ public async requestOtherUrl( @@ -310,11 +296,11 @@ export class FetchHttpApi { /** * Form and return a homeserver request URL based on the given path params and prefix. - * @param {string} path The HTTP path after the supplied prefix e.g. "/createRoom". - * @param {Object} queryParams A dict of query params (these will NOT be urlencoded). - * @param {string} prefix The full prefix to use e.g. "/_matrix/client/v2_alpha", defaulting to this.opts.prefix. - * @param {string} baseUrl The baseUrl to use e.g. "https://matrix.org/", defaulting to this.opts.baseUrl. - * @return {string} URL + * @param path - The HTTP path after the supplied prefix e.g. "/createRoom". + * @param queryParams - A dict of query params (these will NOT be urlencoded). + * @param prefix - The full prefix to use e.g. "/_matrix/client/v2_alpha", defaulting to this.opts.prefix. + * @param baseUrl - The baseUrl to use e.g. "https://matrix.org/", defaulting to this.opts.baseUrl. + * @returns URL */ public getUrl( path: string, diff --git a/src/http-api/index.ts b/src/http-api/index.ts index c7f782d89..3574f539e 100644 --- a/src/http-api/index.ts +++ b/src/http-api/index.ts @@ -35,27 +35,13 @@ export class MatrixHttpApi extends FetchHttpApi { /** * Upload content to the homeserver * - * @param {object} file The object to upload. On a browser, something that + * @param file - The object to upload. On a browser, something that * can be sent to XMLHttpRequest.send (typically a File). Under node.js, * a Buffer, String or ReadStream. * - * @param {object} opts options object + * @param opts - options object * - * @param {string=} opts.name Name to give the file on the server. Defaults - * to file.name. - * - * @param {boolean=} opts.includeFilename if false will not send the filename, - * e.g for encrypted file uploads where filename leaks are undesirable. - * Defaults to true. - * - * @param {string=} opts.type Content-type for the upload. Defaults to - * file.type, or application/octet-stream. - * - * @param {Function=} opts.progressHandler Optional. Called when a chunk of - * data has been uploaded, with an object containing the fields `loaded` - * (number of bytes transferred) and `total` (total size, if known). - * - * @return {Promise} Resolves to response object, as + * @returns Promise which resolves to response object, as * determined by this.opts.onlyData, opts.rawResponse, and * opts.onlyContentUri. Rejects with an error (usually a MatrixError). */ @@ -190,7 +176,7 @@ export class MatrixHttpApi extends FetchHttpApi { /** * Get the content repository url with query parameters. - * @return {Object} An object with a 'base', 'path' and 'params' for base URL, + * @returns An object with a 'base', 'path' and 'params' for base URL, * path and query parameters respectively. */ public getContentUri(): IContentUri { diff --git a/src/http-api/interface.ts b/src/http-api/interface.ts index 372179470..9946aa37b 100644 --- a/src/http-api/interface.ts +++ b/src/http-api/interface.ts @@ -32,11 +32,25 @@ export interface IHttpOpts { } export interface IRequestOpts { + /** + * The alternative base url to use. + * If not specified, uses this.opts.baseUrl + */ baseUrl?: string; + /** + * The full prefix to use e.g. + * "/_matrix/client/v2_alpha". If not specified, uses this.opts.prefix. + */ prefix?: string; - + /** + * map of additional request headers + */ headers?: Record; abortSignal?: AbortSignal; + /** + * The maximum amount of time to wait before + * timing out the request. If not specified, there is no timeout. + */ localTimeoutMs?: number; keepAlive?: boolean; // defaults to false json?: boolean; // defaults to true @@ -62,7 +76,29 @@ export enum HttpApiEvent { } export type HttpApiEventHandlerMap = { + /** + * Fires whenever the login session the JS SDK is using is no + * longer valid and the user must log in again. + * NB. This only fires when action is required from the user, not + * when then login session can be renewed by using a refresh token. + * @example + * ``` + * matrixClient.on("Session.logged_out", function(errorObj){ + * // show the login screen + * }); + * ``` + */ [HttpApiEvent.SessionLoggedOut]: (err: MatrixError) => void; + /** + * Fires when the JS SDK receives a M_CONSENT_NOT_GIVEN error in response + * to a HTTP request. + * @example + * ``` + * matrixClient.on("no_consent", function(message, contentUri) { + * console.info(message + ' Go to ' + contentUri); + * }); + * ``` + */ [HttpApiEvent.NoConsent]: (message: string, consentUri: string) => void; }; @@ -72,9 +108,26 @@ export interface UploadProgress { } export interface UploadOpts { + /** + * Name to give the file on the server. Defaults to file.name. + */ name?: string; + /** + * Content-type for the upload. Defaults to + * file.type, or applicaton/octet-stream. + */ type?: string; + /** + * if false will not send the filename, + * e.g for encrypted file uploads where filename leaks are undesirable. + * Defaults to true. + */ includeFilename?: boolean; + /** + * Optional. Called when a chunk of + * data has been uploaded, with an object containing the fields `loaded` + * (number of bytes transferred) and `total` (total size, if known). + */ progressHandler?(progress: UploadProgress): void; abortController?: AbortController; } diff --git a/src/http-api/utils.ts b/src/http-api/utils.ts index 504660950..c49be740e 100644 --- a/src/http-api/utils.ts +++ b/src/http-api/utils.ts @@ -67,9 +67,9 @@ export function anySignal(signals: AbortSignal[]): { * If it is a JSON response, we will parse it into a MatrixError. Otherwise * we return a generic Error. * - * @param {XMLHttpRequest|Response} response response object - * @param {String} body raw body of the response - * @returns {Error} + * @param response - response object + * @param body - raw body of the response + * @returns */ export function parseErrorResponse(response: XMLHttpRequest | Response, body?: string): Error { let contentType: ParsedMediaType | null; @@ -102,8 +102,8 @@ function isXhr(response: XMLHttpRequest | Response): response is XMLHttpRequest * * returns null if no content-type header could be found. * - * @param {XMLHttpRequest|Response} response response object - * @returns {{type: String, parameters: Object}?} parsed content-type header, or null if not found + * @param response - response object + * @returns parsed content-type header, or null if not found */ function getResponseContentType(response: XMLHttpRequest | Response): ParsedMediaType | null { let contentType: string | null; @@ -124,10 +124,10 @@ function getResponseContentType(response: XMLHttpRequest | Response): ParsedMedi /** * Retries a network operation run in a callback. - * @param {number} maxAttempts maximum attempts to try - * @param {Function} callback callback that returns a promise of the network operation. If rejected with ConnectionError, it will be retried by calling the callback again. - * @return {any} the result of the network operation - * @throws {ConnectionError} If after maxAttempts the callback still throws ConnectionError + * @param maxAttempts - maximum attempts to try + * @param callback - callback that returns a promise of the network operation. If rejected with ConnectionError, it will be retried by calling the callback again. + * @returns the result of the network operation + * @throws {@link ConnectionError} If after maxAttempts the callback still throws ConnectionError */ export async function retryNetworkOperation(maxAttempts: number, callback: () => Promise): Promise { let attempts = 0; diff --git a/src/indexeddb-helpers.ts b/src/indexeddb-helpers.ts index 695a3145f..6f99ae54b 100644 --- a/src/indexeddb-helpers.ts +++ b/src/indexeddb-helpers.ts @@ -18,9 +18,9 @@ limitations under the License. * Check if an IndexedDB database exists. The only way to do so is to try opening it, so * we do that and then delete it did not exist before. * - * @param {Object} indexedDB The `indexedDB` interface - * @param {string} dbName The database name to test for - * @returns {boolean} Whether the database exists + * @param indexedDB - The `indexedDB` interface + * @param dbName - The database name to test for + * @returns Whether the database exists */ export function exists(indexedDB: IDBFactory, dbName: string): Promise { return new Promise((resolve, reject) => { diff --git a/src/indexeddb-worker.ts b/src/indexeddb-worker.ts index 45facc485..78e87b373 100644 --- a/src/indexeddb-worker.ts +++ b/src/indexeddb-worker.ts @@ -20,6 +20,6 @@ limitations under the License. * to be used separately */ -/** The {@link module:indexeddb-store-worker~IndexedDBStoreWorker} class. */ +/** The {@link IndexedDBStoreWorker} class. */ export { IndexedDBStoreWorker } from "./store/indexeddb-store-worker"; diff --git a/src/interactive-auth.ts b/src/interactive-auth.ts index df4a42c27..219569e61 100644 --- a/src/interactive-auth.ts +++ b/src/interactive-auth.ts @@ -16,8 +16,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/** @module interactive-auth */ - import { logger } from './logger'; import { MatrixClient } from "./client"; import { defer, IDeferred } from "./utils"; @@ -31,8 +29,11 @@ interface IFlow { } export interface IInputs { + // An email address. If supplied, a flow using email verification will be chosen. emailAddress?: string; + // An ISO two letter country code. Gives the country that opts.phoneNumber should be resolved relative to. phoneCountry?: string; + // A phone number. If supplied, a flow using phone number validation will be chosen. phoneNumber?: string; registrationToken?: string; } @@ -106,15 +107,66 @@ class NoAuthFlowFoundError extends Error { } interface IOpts { + /** + * A matrix client to use for the auth process + */ matrixClient: MatrixClient; + /** + * Error response from the last request. If null, a request will be made with no auth before starting. + */ authData?: IAuthData; + /** + * Inputs provided by the user and used by different stages of the auto process. + * The inputs provided will affect what flow is chosen. + */ inputs?: IInputs; + /** + * If resuming an existing interactive auth session, the sessionId of that session. + */ sessionId?: string; + /** + * If resuming an existing interactive auth session, the client secret for that session + */ clientSecret?: string; + /** + * If returning from having completed m.login.email.identity auth, the sid for the email verification session. + */ emailSid?: string; + + /** + * Called with the new auth dict to submit the request. + * Also passes a second deprecated arg which is a flag set to true if this request is a background request. + * The busyChanged callback should be used instead of the background flag. + * Should return a promise which resolves to the successful response or rejects with a MatrixError. + */ doRequest(auth: IAuthData | null, background: boolean): Promise; + /** + * Called when the status of the UI auth changes, + * ie. when the state of an auth stage changes of when the auth flow moves to a new stage. + * The arguments are: the login type (eg m.login.password); and an object which is either an error or an + * informational object specific to the login type. + * If the 'errcode' key is defined, the object is an error, and has keys: + * errcode: string, the textual error code, eg. M_UNKNOWN + * error: string, human readable string describing the error + * + * The login type specific objects are as follows: + * m.login.email.identity: + * * emailSid: string, the sid of the active email auth session + */ stateUpdated(nextStage: AuthType, status: IStageStatus): void; + + /** + * A function that takes the email address (string), clientSecret (string), attempt number (int) and + * sessionId (string) and calls the relevant requestToken function and returns the promise returned by that + * function. + * If the resulting promise rejects, the rejection will propagate through to the attemptAuth promise. + */ requestEmailToken(email: string, secret: string, attempt: number, session: string): Promise<{ sid: string }>; + /** + * Called whenever the interactive auth logic becomes busy submitting information provided by the user or finishes. + * After this has been called with true the UI should indicate that a request is in progress + * until it is called again with false. + */ busyChanged?(busy: boolean): void; startAuthStage?(nextStage: string): Promise; // LEGACY } @@ -131,70 +183,7 @@ interface IOpts { * callbacks, and information gathered from the user can be submitted with * submitAuthDict. * - * @constructor - * @alias module:interactive-auth - * - * @param {object} opts options object - * - * @param {object} opts.matrixClient A matrix client to use for the auth process - * - * @param {object?} opts.authData error response from the last request. If - * null, a request will be made with no auth before starting. - * - * @param {function(object?): Promise} opts.doRequest - * called with the new auth dict to submit the request. Also passes a - * second deprecated arg which is a flag set to true if this request - * is a background request. The busyChanged callback should be used - * instead of the background flag. Should return a promise which resolves - * to the successful response or rejects with a MatrixError. - * - * @param {function(boolean): Promise} opts.busyChanged - * called whenever the interactive auth logic becomes busy submitting - * information provided by the user or finishes. After this has been - * called with true the UI should indicate that a request is in progress - * until it is called again with false. - * - * @param {function(string, object?)} opts.stateUpdated - * called when the status of the UI auth changes, ie. when the state of - * an auth stage changes of when the auth flow moves to a new stage. - * The arguments are: the login type (eg m.login.password); and an object - * which is either an error or an informational object specific to the - * login type. If the 'errcode' key is defined, the object is an error, - * and has keys: - * errcode: string, the textual error code, eg. M_UNKNOWN - * error: string, human readable string describing the error - * - * The login type specific objects are as follows: - * m.login.email.identity: - * * emailSid: string, the sid of the active email auth session - * - * @param {object?} opts.inputs Inputs provided by the user and used by different - * stages of the auto process. The inputs provided will affect what flow is chosen. - * - * @param {string?} opts.inputs.emailAddress An email address. If supplied, a flow - * using email verification will be chosen. - * - * @param {string?} opts.inputs.phoneCountry An ISO two letter country code. Gives - * the country that opts.phoneNumber should be resolved relative to. - * - * @param {string?} opts.inputs.phoneNumber A phone number. If supplied, a flow - * using phone number validation will be chosen. - * - * @param {string?} opts.sessionId If resuming an existing interactive auth session, - * the sessionId of that session. - * - * @param {string?} opts.clientSecret If resuming an existing interactive auth session, - * the client secret for that session - * - * @param {string?} opts.emailSid If returning from having completed m.login.email.identity - * auth, the sid for the email verification session. - * - * @param {function?} opts.requestEmailToken A function that takes the email address (string), - * clientSecret (string), attempt number (int) and sessionId (string) and calls the - * relevant requestToken function and returns the promise returned by that function. - * If the resulting promise rejects, the rejection will propagate through to the - * attemptAuth promise. - * + * @param opts - options object */ export class InteractiveAuth { private readonly matrixClient: MatrixClient; @@ -236,7 +225,7 @@ export class InteractiveAuth { /** * begin the authentication process. * - * @return {Promise} which resolves to the response on success, + * @returns which resolves to the response on success, * or rejects with the error on failure. Rejects with NoAuthFlowFoundError if * no suitable authentication flow can be found */ @@ -307,7 +296,7 @@ export class InteractiveAuth { /** * get the auth session ID * - * @return {string} session id + * @returns session id */ public getSessionId(): string | undefined { return this.data?.session; @@ -317,7 +306,7 @@ export class InteractiveAuth { * get the client secret used for validation sessions * with the identity server. * - * @return {string} client secret + * @returns client secret */ public getClientSecret(): string { return this.clientSecret; @@ -326,8 +315,8 @@ export class InteractiveAuth { /** * get the server params for a given stage * - * @param {string} loginType login type for the stage - * @return {object?} any parameters from the server for this stage + * @param loginType - login type for the stage + * @returns any parameters from the server for this stage */ public getStageParams(loginType: string): Record | undefined { return this.data.params?.[loginType]; @@ -342,10 +331,10 @@ export class InteractiveAuth { * make attemptAuth resolve/reject, or cause the startAuthStage callback * to be called for a new stage. * - * @param {object} authData new auth dict to send to the server. Should + * @param authData - new auth dict to send to the server. Should * include a `type` property denoting the login type, as well as any * other params for that stage. - * @param {boolean} background If true, this request failing will not result + * @param background - If true, this request failing will not result * in the attemptAuth promise being rejected. This can be set to true * for requests that just poll to see if auth has been completed elsewhere. */ @@ -398,7 +387,7 @@ export class InteractiveAuth { * Gets the sid for the email validation session * Specific to m.login.email.identity * - * @returns {string} The sid of the email auth session + * @returns The sid of the email auth session */ public getEmailSid(): string | undefined { return this.emailSid; @@ -410,7 +399,7 @@ export class InteractiveAuth { * of the email validation. * Specific to m.login.email.identity * - * @param {string} sid The sid for the email validation session + * @param sid - The sid for the email validation session */ public setEmailSid(sid: string): void { this.emailSid = sid; @@ -448,9 +437,9 @@ export class InteractiveAuth { * Fire off a request, and either resolve the promise, or call * startAuthStage. * - * @private - * @param {object?} auth new auth dict, including session id - * @param {boolean?} background If true, this request is a background poll, so it + * @internal + * @param auth - new auth dict, including session id + * @param background - If true, this request is a background poll, so it * failing will not result in the attemptAuth promise being rejected. * This can be set to true for requests that just poll to see if auth has * been completed elsewhere. @@ -526,8 +515,8 @@ export class InteractiveAuth { /** * Pick the next stage and call the callback * - * @private - * @throws {NoAuthFlowFoundError} If no suitable authentication flow can be found + * @internal + * @throws {@link NoAuthFlowFoundError} If no suitable authentication flow can be found */ private startNextAuthStage(): void { const nextStage = this.chooseStage(); @@ -559,9 +548,9 @@ export class InteractiveAuth { /** * Pick the next auth stage * - * @private - * @return {string?} login type - * @throws {NoAuthFlowFoundError} If no suitable authentication flow can be found + * @internal + * @returns login type + * @throws {@link NoAuthFlowFoundError} If no suitable authentication flow can be found */ private chooseStage(): AuthType | undefined { if (this.chosenFlow === null) { @@ -584,9 +573,9 @@ export class InteractiveAuth { * this could result in the email not being used which would leave * the account with no means to reset a password. * - * @private - * @return {object} flow - * @throws {NoAuthFlowFoundError} If no suitable authentication flow can be found + * @internal + * @returns flow + * @throws {@link NoAuthFlowFoundError} If no suitable authentication flow can be found */ private chooseFlow(): IFlow { const flows = this.data.flows || []; @@ -625,9 +614,8 @@ export class InteractiveAuth { /** * Get the first uncompleted stage in the given flow * - * @private - * @param {object} flow - * @return {string} login type + * @internal + * @returns login type */ private firstUncompletedStage(flow: IFlow): AuthType | undefined { const completed = this.data.completed || []; diff --git a/src/logger.ts b/src/logger.ts index de1ca6619..7077dee02 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -15,10 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/** - * @module logger - */ - import log, { Logger } from "loglevel"; // This is to demonstrate, that you can use any namespace you want. @@ -56,7 +52,7 @@ log.methodFactory = function(methodName, logLevel, loggerName) { }; /** - * Drop-in replacement for console using {@link https://www.npmjs.com/package/loglevel|loglevel}. + * Drop-in replacement for `console` using {@link https://www.npmjs.com/package/loglevel|loglevel}. * Can be tailored down to specific use cases if needed. */ export const logger = log.getLogger(DEFAULT_NAMESPACE) as PrefixedLogger; diff --git a/src/matrix.ts b/src/matrix.ts index 421e0e6ed..d075c098e 100644 --- a/src/matrix.ts +++ b/src/matrix.ts @@ -70,8 +70,7 @@ let cryptoStoreFactory = (): CryptoStore => new MemoryCryptoStore; /** * Configure a different factory to be used for creating crypto stores * - * @param {Function} fac a function which will return a new - * {@link module:crypto.store.base~CryptoStore}. + * @param fac - a function which will return a new {@link CryptoStore} */ export function setCryptoStoreFactory(fac: () => CryptoStore): void { cryptoStoreFactory = fac; @@ -88,24 +87,14 @@ function amendClientOpts(opts: ICreateClientOpts): ICreateClientOpts { } /** - * Construct a Matrix Client. Similar to {@link module:client.MatrixClient} + * Construct a Matrix Client. Similar to {@link MatrixClient} * except that the 'request', 'store' and 'scheduler' dependencies are satisfied. - * @param {Object} opts The configuration options for this client. These configuration - * options will be passed directly to {@link module:client.MatrixClient}. - * @param {Object} opts.store If not set, defaults to - * {@link module:store/memory.MemoryStore}. - * @param {Object} opts.scheduler If not set, defaults to - * {@link module:scheduler~MatrixScheduler}. + * @param opts - The configuration options for this client. These configuration + * options will be passed directly to {@link MatrixClient}. * - * @param {module:crypto.store.base~CryptoStore=} opts.cryptoStore - * crypto store implementation. Calls the factory supplied to - * {@link setCryptoStoreFactory} if unspecified; or if no factory has been - * specified, uses a default implementation (indexeddb in the browser, - * in-memory otherwise). - * - * @return {MatrixClient} A new matrix client. - * @see {@link module:client.MatrixClient} for the full list of options for - * opts. + * @returns A new matrix client. + * @see {@link MatrixClient} for the full list of options for + * `opts`. */ export function createClient(opts: ICreateClientOpts): MatrixClient { return new MatrixClient(amendClientOpts(opts)); diff --git a/src/models/MSC3089Branch.ts b/src/models/MSC3089Branch.ts index 25ce51a20..e4c0eb287 100644 --- a/src/models/MSC3089Branch.ts +++ b/src/models/MSC3089Branch.ts @@ -67,7 +67,7 @@ export class MSC3089Branch { /** * Deletes the file from the tree, including all prior edits/versions. - * @returns {Promise} Resolves when complete. + * @returns Promise which resolves when complete. */ public async delete(): Promise { await this.client.sendStateEvent(this.roomId, UNSTABLE_MSC3089_BRANCH.name, {}, this.id); @@ -79,7 +79,7 @@ export class MSC3089Branch { /** * Gets the name for this file. - * @returns {string} The name, or "Unnamed File" if unknown. + * @returns The name, or "Unnamed File" if unknown. */ public getName(): string { return this.indexEvent.getContent()['name'] || "Unnamed File"; @@ -87,8 +87,8 @@ export class MSC3089Branch { /** * Sets the name for this file. - * @param {string} name The new name for this file. - * @returns {Promise} Resolves when complete. + * @param name - The new name for this file. + * @returns Promise which resolves when complete. */ public async setName(name: string): Promise { await this.client.sendStateEvent(this.roomId, UNSTABLE_MSC3089_BRANCH.name, { @@ -99,7 +99,7 @@ export class MSC3089Branch { /** * Gets whether or not a file is locked. - * @returns {boolean} True if locked, false otherwise. + * @returns True if locked, false otherwise. */ public isLocked(): boolean { return this.indexEvent.getContent()['locked'] || false; @@ -107,8 +107,8 @@ export class MSC3089Branch { /** * Sets a file as locked or unlocked. - * @param {boolean} locked True to lock the file, false otherwise. - * @returns {Promise} Resolves when complete. + * @param locked - True to lock the file, false otherwise. + * @returns Promise which resolves when complete. */ public async setLocked(locked: boolean): Promise { await this.client.sendStateEvent(this.roomId, UNSTABLE_MSC3089_BRANCH.name, { @@ -119,7 +119,7 @@ export class MSC3089Branch { /** * Gets information about the file needed to download it. - * @returns {Promise<{info: IEncryptedFile, httpUrl: string}>} Information about the file. + * @returns Information about the file. */ public async getFileInfo(): Promise<{ info: IEncryptedFile, httpUrl: string }> { const event = await this.getFileEvent(); @@ -136,7 +136,7 @@ export class MSC3089Branch { /** * Gets the event the file points to. - * @returns {Promise} Resolves to the file's event. + * @returns Promise which resolves to the file's event. */ public async getFileEvent(): Promise { const room = this.client.getRoom(this.roomId); @@ -161,11 +161,11 @@ export class MSC3089Branch { /** * Creates a new version of this file with contents in a type that is compatible with MatrixClient.uploadContent(). - * @param {string} name The name of the file. - * @param {File | String | Buffer | ReadStream | Blob} encryptedContents The encrypted contents. - * @param {Partial} info The encrypted file information. - * @param {IContent} additionalContent Optional event content fields to include in the message. - * @returns {Promise} Resolves to the file event's sent response. + * @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. */ public async createNewVersion( name: string, @@ -200,7 +200,7 @@ export class MSC3089Branch { /** * Gets the file's version history, starting at this file. - * @returns {Promise} Resolves to the file's version history, with the + * @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. */ public async getVersionHistory(): Promise { diff --git a/src/models/MSC3089TreeSpace.ts b/src/models/MSC3089TreeSpace.ts index f437eab84..76c733996 100644 --- a/src/models/MSC3089TreeSpace.ts +++ b/src/models/MSC3089TreeSpace.ts @@ -111,8 +111,8 @@ export class MSC3089TreeSpace { /** * Sets the name of the tree space. - * @param {string} name The new name for the space. - * @returns {Promise} Resolves when complete. + * @param name - The new name for the space. + * @returns Promise which resolves when complete. */ public async setName(name: string): Promise { await this.client.sendStateEvent(this.roomId, EventType.RoomName, { name }, ""); @@ -121,15 +121,15 @@ export class MSC3089TreeSpace { /** * Invites a user to the tree space. They will be given the default Viewer * permission level unless specified elsewhere. - * @param {string} userId The user ID to invite. - * @param {boolean} andSubspaces True (default) to invite the user to all + * @param userId - The user ID to invite. + * @param andSubspaces - True (default) to invite the user to all * directories/subspaces too, recursively. - * @param {boolean} shareHistoryKeys True (default) to share encryption keys + * @param shareHistoryKeys - True (default) to share encryption keys * with the invited user. This will allow them to decrypt the events (files) * in the tree. Keys will not be shared if the room is lacking appropriate * history visibility (by default, history visibility is "shared" in trees, * which is an appropriate visibility for these purposes). - * @returns {Promise} Resolves when complete. + * @returns Promise which resolves when complete. */ public async invite(userId: string, andSubspaces = true, shareHistoryKeys = true): Promise { const promises: Promise[] = [this.retryInvite(userId)]; @@ -164,9 +164,9 @@ export class MSC3089TreeSpace { * Sets the permissions of a user to the given role. Note that if setting a user * to Owner then they will NOT be able to be demoted. If the user does not have * permission to change the power level of the target, an error will be thrown. - * @param {string} userId The user ID to change the role of. - * @param {TreePermissions} role The role to assign. - * @returns {Promise} Resolves when complete. + * @param userId - The user ID to change the role of. + * @param role - The role to assign. + * @returns Promise which resolves when complete. */ public async setPermissions(userId: string, role: TreePermissions): Promise { const currentPls = this.room.currentState.getStateEvents(EventType.RoomPowerLevels, ""); @@ -200,8 +200,8 @@ export class MSC3089TreeSpace { * Gets the current permissions of a user. Note that any users missing explicit permissions (or not * in the space) will be considered Viewers. Appropriate membership checks need to be performed * elsewhere. - * @param {string} userId The user ID to check permissions of. - * @returns {TreePermissions} The permissions for the user, defaulting to Viewer. + * @param userId - The user ID to check permissions of. + * @returns The permissions for the user, defaulting to Viewer. */ public getPermissions(userId: string): TreePermissions { const currentPls = this.room.currentState.getStateEvents(EventType.RoomPowerLevels, ""); @@ -220,8 +220,8 @@ export class MSC3089TreeSpace { /** * Creates a directory under this tree space, represented as another tree space. - * @param {string} name The name for the directory. - * @returns {Promise} Resolves to the created directory. + * @param name - The name for the directory. + * @returns Promise which resolves to the created directory. */ public async createDirectory(name: string): Promise { const directory = await this.client.unstableCreateFileTree(name); @@ -239,7 +239,7 @@ export class MSC3089TreeSpace { /** * Gets a list of all known immediate subdirectories to this tree space. - * @returns {MSC3089TreeSpace[]} The tree spaces (directories). May be empty, but not null. + * @returns The tree spaces (directories). May be empty, but not null. */ public getDirectories(): MSC3089TreeSpace[] { const trees: MSC3089TreeSpace[] = []; @@ -261,8 +261,8 @@ export class MSC3089TreeSpace { /** * Gets a subdirectory of a given ID under this tree space. Note that this will not recurse * into children and instead only look one level deep. - * @param {string} roomId The room ID (directory ID) to find. - * @returns {MSC3089TreeSpace | undefined} The directory, or undefined if not found. + * @param roomId - The room ID (directory ID) to find. + * @returns The directory, or undefined if not found. */ public getDirectory(roomId: string): MSC3089TreeSpace | undefined { return this.getDirectories().find(r => r.roomId === roomId); @@ -270,7 +270,7 @@ export class MSC3089TreeSpace { /** * Deletes the tree, kicking all members and deleting **all subdirectories**. - * @returns {Promise} Resolves when complete. + * @returns Promise which resolves when complete. */ public async delete(): Promise { const subdirectories = this.getDirectories(); @@ -341,7 +341,7 @@ export class MSC3089TreeSpace { /** * Gets the current order index for this directory. Note that if this is the top level space * then -1 will be returned. - * @returns {number} The order index of this space. + * @returns The order index of this space. */ public getOrder(): number { if (this.isTopLevel) return -1; @@ -357,8 +357,8 @@ export class MSC3089TreeSpace { * Sets the order index for this directory within its parent. Note that if this is a top level * space then an error will be thrown. -1 can be used to move the child to the start, and numbers * larger than the number of children can be used to move the child to the end. - * @param {number} index The new order index for this space. - * @returns {Promise} Resolves when complete. + * @param index - The new order index for this space. + * @returns Promise which resolves when complete. * @throws Throws if this is a top level space. */ public async setOrder(index: number): Promise { @@ -464,11 +464,11 @@ export class MSC3089TreeSpace { /** * Creates (uploads) a new file to this tree. The file must have already been encrypted for the room. * The file contents are in a type that is compatible with MatrixClient.uploadContent(). - * @param {string} name The name of the file. - * @param {File | String | Buffer | ReadStream | Blob} encryptedContents The encrypted contents. - * @param {Partial} info The encrypted file information. - * @param {IContent} additionalContent Optional event content fields to include in the message. - * @returns {Promise} Resolves to the file event's sent response. + * @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. */ public async createFile( name: string, @@ -512,8 +512,8 @@ export class MSC3089TreeSpace { /** * Retrieves a file from the tree. - * @param {string} fileEventId The event ID of the file. - * @returns {MSC3089Branch | null} The file, or null if not found. + * @param fileEventId - The event ID of the file. + * @returns The file, or null if not found. */ public getFile(fileEventId: string): MSC3089Branch | null { const branch = this.room.currentState.getStateEvents(UNSTABLE_MSC3089_BRANCH.name, fileEventId); @@ -522,7 +522,7 @@ export class MSC3089TreeSpace { /** * Gets an array of all known files for the tree. - * @returns {MSC3089Branch[]} The known files. May be empty, but not null. + * @returns The known files. May be empty, but not null. */ public listFiles(): MSC3089Branch[] { return this.listAllFiles().filter(b => b.isActive); @@ -530,7 +530,7 @@ export class MSC3089TreeSpace { /** * Gets an array of all known files for the tree, including inactive/invalid ones. - * @returns {MSC3089Branch[]} The known files. May be empty, but not null. + * @returns The known files. May be empty, but not null. */ public listAllFiles(): MSC3089Branch[] { const branches = this.room.currentState.getStateEvents(UNSTABLE_MSC3089_BRANCH.name) ?? []; diff --git a/src/models/event-context.ts b/src/models/event-context.ts index 60252627b..0401cd530 100644 --- a/src/models/event-context.ts +++ b/src/models/event-context.ts @@ -17,9 +17,6 @@ limitations under the License. import { MatrixEvent } from "./event"; import { Direction } from "./event-timeline"; -/** - * @module models/event-context - */ export class EventContext { private timeline: MatrixEvent[]; private ourEventIndex = 0; @@ -38,9 +35,7 @@ export class EventContext { * It also stores pagination tokens for going backwards and forwards in the * timeline. * - * @param {MatrixEvent} ourEvent the event at the centre of this context - * - * @constructor + * @param ourEvent - the event at the centre of this context */ public constructor(public readonly ourEvent: MatrixEvent) { this.timeline = [ourEvent]; @@ -51,7 +46,7 @@ export class EventContext { * * This is a convenience function for getTimeline()[getOurEventIndex()]. * - * @return {MatrixEvent} The event at the centre of this context. + * @returns The event at the centre of this context. */ public getEvent(): MatrixEvent { return this.timeline[this.ourEventIndex]; @@ -60,7 +55,7 @@ export class EventContext { /** * Get the list of events in this context * - * @return {Array} An array of MatrixEvents + * @returns An array of MatrixEvents */ public getTimeline(): MatrixEvent[] { return this.timeline; @@ -68,8 +63,6 @@ export class EventContext { /** * Get the index in the timeline of our event - * - * @return {Number} */ public getOurEventIndex(): number { return this.ourEventIndex; @@ -78,9 +71,7 @@ export class EventContext { /** * Get a pagination token. * - * @param {boolean} backwards true to get the pagination token for going - * backwards in time - * @return {string} + * @param backwards - true to get the pagination token for going */ public getPaginateToken(backwards = false): string | null { return this.paginateTokens[backwards ? Direction.Backward : Direction.Forward]; @@ -91,8 +82,8 @@ export class EventContext { * * Generally this will be used only by the matrix js sdk. * - * @param {string} token pagination token - * @param {boolean} backwards true to set the pagination token for going + * @param token - pagination token + * @param backwards - true to set the pagination token for going * backwards in time */ public setPaginateToken(token?: string, backwards = false): void { @@ -102,8 +93,8 @@ export class EventContext { /** * Add more events to the timeline * - * @param {Array} events new events, in timeline order - * @param {boolean} atStart true to insert new events at the start + * @param events - new events, in timeline order + * @param atStart - true to insert new events at the start */ public addEvents(events: MatrixEvent[], atStart = false): void { // TODO: should we share logic with Room.addEventsToTimeline? diff --git a/src/models/event-status.ts b/src/models/event-status.ts index faca97186..a5113e0b7 100644 --- a/src/models/event-status.ts +++ b/src/models/event-status.ts @@ -17,7 +17,6 @@ limitations under the License. /** * Enum for event statuses. * @readonly - * @enum {string} */ export enum EventStatus { /** The event was not sent and will no longer be retried. */ diff --git a/src/models/event-timeline-set.ts b/src/models/event-timeline-set.ts index 6dd2a0e77..e1da746c9 100644 --- a/src/models/event-timeline-set.ts +++ b/src/models/event-timeline-set.ts @@ -14,10 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/** - * @module models/event-timeline-set - */ - import { EventTimeline, IAddEventOptions } from "./event-timeline"; import { MatrixEvent } from "./event"; import { logger } from '../logger'; @@ -31,16 +27,20 @@ import { Thread, ThreadFilterType } from "./thread"; const DEBUG = true; +/* istanbul ignore next */ let debuglog: (...args: any[]) => void; if (DEBUG) { // using bind means that we get to keep useful line numbers in the console debuglog = logger.log.bind(logger); } else { + /* istanbul ignore next */ debuglog = function(): void {}; } interface IOpts { + // Set to true to enable improved timeline support. timelineSupport?: boolean; + // The filter object, if any, for this timelineSet. filter?: Filter; pendingEvents?: boolean; } @@ -51,7 +51,9 @@ export enum DuplicateStrategy { } export interface IRoomTimelineData { + // the timeline the event was added to/removed from timeline: EventTimeline; + // true if the event was a real-time event added to the end of the live timeline liveEvent?: boolean; } @@ -75,6 +77,26 @@ export interface IAddLiveEventOptions type EmittedEvents = RoomEvent.Timeline | RoomEvent.TimelineReset; export type EventTimelineSetHandlerMap = { + /** + * Fires whenever the timeline in a room is updated. + * @param event - The matrix event which caused this event to fire. + * @param room - The room, if any, whose timeline was updated. + * @param toStartOfTimeline - True if this event was added to the start + * @param removed - True if this event has just been removed from the timeline + * (beginning; oldest) of the timeline e.g. due to pagination. + * + * @param data - more data about the event + * + * @example + * ``` + * matrixClient.on("Room.timeline", + * function(event, room, toStartOfTimeline, removed, data) { + * if (!toStartOfTimeline && data.liveEvent) { + * var messageToAppend = room.timeline.[room.timeline.length - 1]; + * } + * }); + * ``` + */ [RoomEvent.Timeline]: ( event: MatrixEvent, room: Room | undefined, @@ -82,6 +104,18 @@ export type EventTimelineSetHandlerMap = { removed: boolean, data: IRoomTimelineData, ) => void; + /** + * Fires whenever the live timeline in a room is reset. + * + * When we get a 'limited' sync (for example, after a network outage), we reset + * the live timeline to be empty before adding the recent events to the new + * timeline. This event is fired after the timeline is reset, and before the + * new events are added. + * + * @param room - The room whose live timeline was reset, if any + * @param timelineSet - timelineSet room whose live timeline was reset + * @param resetAllTimelines - True if all timelines were reset. + */ [RoomEvent.TimelineReset]: ( room: Room | undefined, eventTimelineSet: EventTimelineSet, @@ -119,20 +153,13 @@ export class EventTimelineSet extends TypedEventEmitterIn order that we can find events from their ids later, we also maintain a * map from event_id to timeline and index. * - * @constructor - * @param {Room=} room - * Room for this timelineSet. May be null for non-room cases, such as the + * @param room - Room for this timelineSet. May be null for non-room cases, such as the * notification timeline. - * @param {Object} opts Options inherited from Room. - * - * @param {boolean} [opts.timelineSupport = false] - * Set to true to enable improved timeline support. - * @param {Object} [opts.filter = null] - * The filter object, if any, for this timelineSet. - * @param {MatrixClient=} client the Matrix client which owns this EventTimelineSet, + * @param opts - Options inherited from Room. + * @param client - the Matrix client which owns this EventTimelineSet, * can be omitted if room is specified. - * @param {Thread=} thread the thread to which this timeline set relates. - * @param {boolean} isThreadTimeline Whether this timeline set relates to a thread list timeline + * @param thread - the thread to which this timeline set relates. + * @param isThreadTimeline - Whether this timeline set relates to a thread list timeline * (e.g., All threads or My threads) */ public constructor( @@ -159,7 +186,7 @@ export class EventTimelineSet extends TypedEventEmitteropts.pendingEventOrdering was not 'detached' + * @throws If `opts.pendingEventOrdering` was not 'detached' */ public getPendingEvents(): MatrixEvent[] { if (!this.room || !this.displayPendingEvents) { @@ -201,7 +228,7 @@ export class EventTimelineSet extends TypedEventEmitterThis is used when /sync returns a 'limited' timeline. * - * @param {string=} backPaginationToken token for back-paginating the new timeline - * @param {string=} forwardPaginationToken token for forward-paginating the old live timeline, + * @param backPaginationToken - token for back-paginating the new timeline + * @param forwardPaginationToken - token for forward-paginating the old live timeline, * if absent or null, all timelines are reset. * - * @fires module:client~MatrixClient#event:"Room.timelineReset" + * @remarks + * Fires {@link RoomEvent.TimelineReset} */ public resetLiveTimeline(backPaginationToken?: string, forwardPaginationToken?: string): void { // Each EventTimeline has RoomState objects tracking the state at the start @@ -293,8 +321,8 @@ export class EventTimelineSet extends TypedEventEmitterWill fire "Room.timeline" for each event added. * - * @param {MatrixEvent[]} events A list of events to add. + * @param events - A list of events to add. * - * @param {boolean} toStartOfTimeline True to add these events to the start + * @param toStartOfTimeline - True to add these events to the start * (oldest) instead of the end (newest) of the timeline. If true, the oldest * event will be the last element of 'events'. * - * @param {module:models/event-timeline~EventTimeline} timeline timeline to + * @param timeline - timeline to * add events to. * - * @param {string=} paginationToken token for the next batch of events + * @param paginationToken - token for the next batch of events * - * @fires module:client~MatrixClient#event:"Room.timeline" + * @remarks + * Fires {@link RoomEvent.Timeline} * */ public addEventsToTimeline( @@ -557,8 +586,8 @@ export class EventTimelineSet extends TypedEventEmitterOnce a timeline joins up with its neighbour, they are linked together into a * doubly-linked list. * - * @param {EventTimelineSet} eventTimelineSet the set of timelines this is part of - * @constructor + * @param eventTimelineSet - the set of timelines this is part of */ public constructor(private readonly eventTimelineSet: EventTimelineSet) { this.roomId = eventTimelineSet.room?.roomId ?? null; @@ -148,9 +143,9 @@ export class EventTimeline { * *

This can only be called before any events are added. * - * @param {MatrixEvent[]} stateEvents list of state events to initialise the + * @param stateEvents - list of state events to initialise the * state with. - * @throws {Error} if an attempt is made to call this after addEvent is called. + * @throws Error if an attempt is made to call this after addEvent is called. */ public initialiseState(stateEvents: MatrixEvent[], { timelineWasEmpty }: IInitialiseStateOptions = {}): void { if (this.events.length > 0) { @@ -167,11 +162,11 @@ export class EventTimeline { * The end state of this timeline gets replaced with an independent copy of the current RoomState, * and will need a new pagination token if it ever needs to paginate forwards. - * @param {string} direction EventTimeline.BACKWARDS to get the state at the + * @param direction - EventTimeline.BACKWARDS to get the state at the * start of the timeline; EventTimeline.FORWARDS to get the state at the end * of the timeline. * - * @return {EventTimeline} the new timeline + * @returns the new timeline */ public forkLive(direction: Direction): EventTimeline { const forkState = this.getState(direction); @@ -191,11 +186,11 @@ export class EventTimeline { /** * Creates an independent timeline, inheriting the directional state from this timeline. * - * @param {string} direction EventTimeline.BACKWARDS to get the state at the + * @param direction - EventTimeline.BACKWARDS to get the state at the * start of the timeline; EventTimeline.FORWARDS to get the state at the end * of the timeline. * - * @return {EventTimeline} the new timeline + * @returns the new timeline */ public fork(direction: Direction): EventTimeline { const forkState = this.getState(direction); @@ -207,7 +202,7 @@ export class EventTimeline { /** * Get the ID of the room for this timeline - * @return {string} room ID + * @returns room ID */ public getRoomId(): string | null { return this.roomId; @@ -215,7 +210,7 @@ export class EventTimeline { /** * Get the filter for this timeline's timelineSet (if any) - * @return {Filter} filter + * @returns filter */ public getFilter(): Filter | undefined { return this.eventTimelineSet.getFilter(); @@ -223,7 +218,7 @@ export class EventTimeline { /** * Get the timelineSet for this timeline - * @return {EventTimelineSet} timelineSet + * @returns timelineSet */ public getTimelineSet(): EventTimelineSet { return this.eventTimelineSet; @@ -237,8 +232,6 @@ export class EventTimeline { * relative to the base index (although note that a given event's index may * well be less than the base index, thus giving that event a negative relative * index). - * - * @return {number} */ public getBaseIndex(): number { return this.baseIndex; @@ -247,7 +240,7 @@ export class EventTimeline { /** * Get the list of events in this context * - * @return {MatrixEvent[]} An array of MatrixEvents + * @returns An array of MatrixEvents */ public getEvents(): MatrixEvent[] { return this.events; @@ -256,11 +249,11 @@ export class EventTimeline { /** * Get the room state at the start/end of the timeline * - * @param {string} direction EventTimeline.BACKWARDS to get the state at the + * @param direction - EventTimeline.BACKWARDS to get the state at the * start of the timeline; EventTimeline.FORWARDS to get the state at the end * of the timeline. * - * @return {RoomState} state at the start/end of the timeline + * @returns state at the start/end of the timeline */ public getState(direction: Direction): RoomState | undefined { if (direction == EventTimeline.BACKWARDS) { @@ -275,11 +268,11 @@ export class EventTimeline { /** * Get a pagination token * - * @param {string} direction EventTimeline.BACKWARDS to get the pagination + * @param direction - EventTimeline.BACKWARDS to get the pagination * token for going backwards in time; EventTimeline.FORWARDS to get the * pagination token for going forwards in time. * - * @return {?string} pagination token + * @returns pagination token */ public getPaginationToken(direction: Direction): string | null { if (this.roomId) { @@ -294,9 +287,9 @@ export class EventTimeline { /** * Set a pagination token * - * @param {?string} token pagination token + * @param token - pagination token * - * @param {string} direction EventTimeline.BACKWARDS to set the pagination + * @param direction - EventTimeline.BACKWARDS to set the pagination * token for going backwards in time; EventTimeline.FORWARDS to set the * pagination token for going forwards in time. */ @@ -313,10 +306,10 @@ export class EventTimeline { /** * Get the next timeline in the series * - * @param {string} direction EventTimeline.BACKWARDS to get the previous + * @param direction - EventTimeline.BACKWARDS to get the previous * timeline; EventTimeline.FORWARDS to get the next timeline. * - * @return {?EventTimeline} previous or following timeline, if they have been + * @returns previous or following timeline, if they have been * joined up. */ public getNeighbouringTimeline(direction: Direction): EventTimeline | null { @@ -332,12 +325,12 @@ export class EventTimeline { /** * Set the next timeline in the series * - * @param {EventTimeline} neighbour previous/following timeline + * @param neighbour - previous/following timeline * - * @param {string} direction EventTimeline.BACKWARDS to set the previous + * @param direction - EventTimeline.BACKWARDS to set the previous * timeline; EventTimeline.FORWARDS to set the next timeline. * - * @throws {Error} if an attempt is made to set the neighbouring timeline when + * @throws Error if an attempt is made to set the neighbouring timeline when * it is already set. */ public setNeighbouringTimeline(neighbour: EventTimeline, direction: Direction): void { @@ -361,8 +354,8 @@ export class EventTimeline { /** * Add a new event to the timeline, and update the state * - * @param {MatrixEvent} event new event - * @param {IAddEventOptions} options addEvent options + * @param event - new event + * @param options - addEvent options */ public addEvent( event: MatrixEvent, @@ -447,8 +440,8 @@ export class EventTimeline { /** * Remove an event from the timeline * - * @param {string} eventId ID of event to be removed - * @return {?MatrixEvent} removed event, or null if not found + * @param eventId - ID of event to be removed + * @returns removed event, or null if not found */ public removeEvent(eventId: string): MatrixEvent | null { for (let i = this.events.length - 1; i >= 0; i--) { @@ -467,7 +460,7 @@ export class EventTimeline { /** * Return a string to identify this timeline, for debugging * - * @return {string} name for this timeline + * @returns name for this timeline */ public toString(): string { return this.name; diff --git a/src/models/event.ts b/src/models/event.ts index 2864aa6b5..2b082f9b6 100644 --- a/src/models/event.ts +++ b/src/models/event.ts @@ -17,7 +17,6 @@ limitations under the License. /** * This is an internal module. See {@link MatrixEvent} and {@link RoomEvent} for * the public classes. - * @module models/event */ import { ExtensibleEvent, ExtensibleEvents, Optional } from "matrix-events-sdk"; @@ -80,15 +79,15 @@ export interface IEvent { redacts?: string; /** - * @deprecated + * @deprecated in favour of `sender` */ user_id?: string; /** - * @deprecated + * @deprecated in favour of `unsigned.prev_content` */ prev_content?: IContent; /** - * @deprecated + * @deprecated in favour of `origin_server_ts` */ age?: number; } @@ -150,8 +149,11 @@ interface IKeyRequestRecipient { } export interface IDecryptOptions { + // Emits "event.decrypted" if set to true emit?: boolean; + // True if this is a retry (enables more logging) isRetry?: boolean; + // whether the message should be re-decrypted if it was previously successfully decrypted with an untrusted key forceRedecryptIfUntrusted?: boolean; } @@ -192,6 +194,12 @@ export enum MatrixEventEvent { export type MatrixEventEmittedEvents = MatrixEventEvent | ThreadEvent.Update; export type MatrixEventHandlerMap = { + /** + * Fires when an event is decrypted + * + * @param event - The matrix event which has been decrypted + * @param err - The error that occurred during decryption, or `undefined` if no error occurred. + */ [MatrixEventEvent.Decrypted]: (event: MatrixEvent, err?: Error) => void; [MatrixEventEvent.BeforeRedaction]: (event: MatrixEvent, redactionEvent: MatrixEvent) => void; [MatrixEventEvent.VisibilityChange]: (event: MatrixEvent, visible: boolean) => void; @@ -271,12 +279,43 @@ export class MatrixEvent extends TypedEventEmitterThis property is experimental and may change. + * @privateRemarks + * Should be read-only + */ + public forwardLooking = true; /* If the event is a `m.key.verification.request` (or to_device `m.key.verification.start`) event, * `Crypto` will set this the `VerificationRequest` for the event @@ -288,26 +327,11 @@ export class MatrixEvent extends TypedEventEmitterDo not access + * @param event - The raw (possibly encrypted) event. Do not access * this property directly unless you absolutely have to. Prefer the getter * methods defined on this class. Using the getter methods shields your app * from changes to event JSON between Matrix versions. - * - * @prop {RoomMember} sender The room member who sent this event, or null e.g. - * this is a presence event. This is only guaranteed to be set for events that - * appear in a timeline, ie. do not guarantee that it will be set on state - * events. - * @prop {RoomMember} target The room member who is the target of this event, e.g. - * the invitee, the person being banned, etc. - * @prop {EventStatus} status The sending status of the event. - * @prop {Error} error most recent error associated with sending the event, if any - * @prop {boolean} forwardLooking True if this event is 'forward looking', meaning - * that getDirectionalContent() will return event.content and not event.prev_content. - * Default: true. This property is experimental and may change. */ public constructor(public event: Partial = {}) { super(); @@ -360,7 +384,7 @@ export class MatrixEvent extends TypedEventEmitter$143350589368169JsLZx:localhost + * @returns The event ID, e.g. $143350589368169JsLZx:localhost * */ public getId(): string | undefined { @@ -398,7 +422,7 @@ export class MatrixEvent extends TypedEventEmitter@alice:matrix.org + * @returns The user ID, e.g. `@alice:matrix.org` */ public getSender(): string | undefined { return this.event.sender || this.event.user_id; // v2 / v1 @@ -407,7 +431,7 @@ export class MatrixEvent extends TypedEventEmitterm.room.message + * @returns The event type, e.g. `m.room.message` */ public getType(): EventType | string { if (this.clearEvent) { @@ -420,16 +444,16 @@ export class MatrixEvent extends TypedEventEmitterundefined - * for m.presence events. - * @return {string?} The room ID, e.g. !cURbafjkfsMDVwdRDQ:matrix.org + * Get the room_id for this event. This will return `undefined` + * for `m.presence` events. + * @returns The room ID, e.g. !cURbafjkfsMDVwdRDQ:matrix.org * */ public getRoomId(): string | undefined { @@ -438,7 +462,7 @@ export class MatrixEvent extends TypedEventEmitter1433502692297 + * @returns The event timestamp, e.g. `1433502692297` */ public getTs(): number { return this.event.origin_server_ts!; @@ -446,7 +470,7 @@ export class MatrixEvent extends TypedEventEmitternew Date(1433502692297) + * @returns The event date, e.g. `new Date(1433502692297)` */ public getDate(): Date | null { return this.event.origin_server_ts ? new Date(this.event.origin_server_ts) : null; @@ -457,7 +481,11 @@ export class MatrixEvent extends TypedEventEmitter(): T { if (this._localRedactionEvent) { @@ -493,7 +521,7 @@ export class MatrixEvent extends TypedEventEmitter(): T { if (this._localRedactionEvent) { @@ -509,7 +537,7 @@ export class MatrixEvent extends TypedEventEmitterThis method is experimental and may change. - * @return {Object} event.content if this event is forward-looking, else + * @returns event.content if this event is forward-looking, else * event.prev_content. */ public getDirectionalContent(): IContent { @@ -585,7 +613,7 @@ export class MatrixEvent extends TypedEventEmitterundefined * for message events. - * @return {string} The event's state_key. + * @returns The event's `state_key`. */ public getStateKey(): string | undefined { return this.event.state_key; @@ -612,7 +640,7 @@ export class MatrixEvent extends TypedEventEmitter"m.room.encrypted" * - * @param {object} cryptoContent raw 'content' for the encrypted event. + * @param cryptoContent - raw 'content' for the encrypted event. * - * @param {string} senderCurve25519Key curve25519 key to record for the + * @param senderCurve25519Key - curve25519 key to record for the * sender of this event. - * See {@link module:models/event.MatrixEvent#getSenderKey}. + * See {@link MatrixEvent#getSenderKey}. * - * @param {string} claimedEd25519Key claimed ed25519 key to record for the + * @param claimedEd25519Key - claimed ed25519 key to record for the * sender if this event. - * See {@link module:models/event.MatrixEvent#getClaimedEd25519Key} + * See {@link MatrixEvent#getClaimedEd25519Key} */ public makeEncrypted( cryptoType: string, @@ -657,7 +685,7 @@ export class MatrixEvent extends TypedEventEmitter { @@ -741,10 +764,10 @@ export class MatrixEvent extends TypedEventEmitter { const wireContent = this.getWireContent(); @@ -759,9 +782,9 @@ export class MatrixEvent extends TypedEventEmitter} */ public getKeysClaimed(): Partial> { if (!this.claimedEd25519Key) return {}; @@ -982,8 +1001,6 @@ export class MatrixEvent extends TypedEventEmitter

When an event is first transmitted, a temporary copy of the event is + * inserted into the timeline, with a temporary event id, and a status of + * 'SENDING'. + * + *

Once the echo comes back from the server, the content of the event + * (MatrixEvent.event) is replaced by the complete event from the homeserver, + * thus updating its event id, as well as server-generated fields such as the + * timestamp. Its status is set to null. + * + *

Once the /send request completes, if the remote echo has not already + * arrived, the event is updated with a new event id and the status is set to + * 'SENT'. The server-generated fields are of course not updated yet. + * + *

If the /send fails, In this case, the event's status is set to + * 'NOT_SENT'. If it is later resent, the process starts again, setting the + * status to 'SENDING'. Alternatively, the message may be cancelled, which + * removes the event from the room, and sets the status to 'CANCELLED'. + * + *

This event is raised to reflect each of the transitions above. + * + * @param event - The matrix event which has been updated + * + * @param room - The room containing the redacted event + * + * @param oldEventId - The previous event id (the temporary event id, + * except when updating a successfully-sent event when its echo arrives) + * + * @param oldStatus - The previous event status. + */ [RoomEvent.LocalEchoUpdated]: ( event: MatrixEvent, room: Room, @@ -227,7 +337,7 @@ export class Room extends ReadReceipt { public normalizedName: string; /** * Dict of room tags; the keys are the tag name and the values - * are any metadata associated with the tag - e.g. { "fav" : { order: 1 } } + * are any metadata associated with the tag - e.g. `{ "fav" : { order: 1 } }` */ public tags: Record> = {}; // $tagName: { $metadata: $value } /** @@ -301,21 +411,10 @@ export class Room extends ReadReceipt { *

In order that we can find events from their ids later, we also maintain a * map from event_id to timeline and index. * - * @constructor - * @alias module:models/room - * @param {string} roomId Required. The ID of this room. - * @param {MatrixClient} client Required. The client, used to lazy load members. - * @param {string} myUserId Required. The ID of the syncing user. - * @param {Object=} opts Configuration options - * - * @param {String=} opts.pendingEventOrdering Controls where pending messages - * appear in a room's timeline. If "chronological", messages will appear - * in the timeline when the call to sendEvent was made. If - * "detached", pending messages will appear in a separate list, - * accessible via {@link module:models/room#getPendingEvents}. Default: - * "chronological". - * @param {boolean} [opts.timelineSupport = false] Set to true to enable improved - * timeline support. + * @param roomId - Required. The ID of this room. + * @param client - Required. The client, used to lazy load members. + * @param myUserId - Required. The ID of the syncing user. + * @param opts - Configuration options */ public constructor( public readonly roomId: string, @@ -402,7 +501,7 @@ export class Room extends ReadReceipt { * - Last event of every room (to generate likely message preview) * - All events up to the read receipt (to calculate an accurate notification count) * - * @returns {Promise} Signals when all events have been decrypted + * @returns Signals when all events have been decrypted */ public async decryptCriticalEvents(): Promise { if (!this.client.isCryptoEnabled()) return; @@ -425,7 +524,7 @@ export class Room extends ReadReceipt { /** * Bulk decrypt events in a room * - * @returns {Promise} Signals when all events have been decrypted + * @returns Signals when all events have been decrypted */ public async decryptAllEvents(): Promise { if (!this.client.isCryptoEnabled()) return; @@ -443,7 +542,7 @@ export class Room extends ReadReceipt { /** * Gets the creator of the room - * @returns {string} The creator of the room, or null if it could not be determined + * @returns The creator of the room, or null if it could not be determined */ public getCreator(): string | null { const createEvent = this.currentState.getStateEvents(EventType.RoomCreate, ""); @@ -452,7 +551,7 @@ export class Room extends ReadReceipt { /** * Gets the version of the room - * @returns {string} The version of the room, or null if it could not be determined + * @returns The version of the room, or null if it could not be determined */ public getVersion(): string { const createEvent = this.currentState.getStateEvents(EventType.RoomCreate, ""); @@ -468,7 +567,7 @@ export class Room extends ReadReceipt { /** * Determines whether this room needs to be upgraded to a new version - * @returns {string?} What version the room should be upgraded to, or null if + * @returns What version the room should be upgraded to, or null if * the room does not require upgrading at this time. * @deprecated Use #getRecommendedVersion() instead */ @@ -489,13 +588,13 @@ export class Room extends ReadReceipt { /** * Determines the recommended room version for the room. This returns an - * object with 3 properties: version as the new version the + * object with 3 properties: `version` as the new version the * room should be upgraded to (may be the same as the current version); - * needsUpgrade to indicate if the room actually can be - * upgraded (ie: does the current version not match?); and urgent + * `needsUpgrade` to indicate if the room actually can be + * upgraded (ie: does the current version not match?); and `urgent` * to indicate if the new version patches a vulnerability in a previous * version. - * @returns {Promise<{version: string, needsUpgrade: boolean, urgent: boolean}>} + * @returns * Resolves to the version the room should be upgraded to. */ public async getRecommendedVersion(): Promise { @@ -576,8 +675,8 @@ export class Room extends ReadReceipt { /** * Determines whether the given user is permitted to perform a room upgrade - * @param {String} userId The ID of the user to test against - * @returns {boolean} True if the given user is permitted to upgrade the room + * @param userId - The ID of the user to test against + * @returns True if the given user is permitted to upgrade the room */ public userMayUpgradeRoom(userId: string): boolean { return this.currentState.maySendStateEvent(EventType.RoomTombstone, userId); @@ -586,10 +685,10 @@ export class Room extends ReadReceipt { /** * Get the list of pending sent events for this room * - * @return {module:models/event.MatrixEvent[]} A list of the sent events + * @returns A list of the sent events * waiting for remote echo. * - * @throws If opts.pendingEventOrdering was not 'detached' + * @throws If `opts.pendingEventOrdering` was not 'detached' */ public getPendingEvents(): MatrixEvent[] { if (!this.pendingEventList) { @@ -604,8 +703,7 @@ export class Room extends ReadReceipt { /** * Removes a pending event for this room * - * @param {string} eventId - * @return {boolean} True if an element was removed. + * @returns True if an element was removed. */ public removePendingEvent(eventId: string): boolean { if (!this.pendingEventList) { @@ -630,8 +728,7 @@ export class Room extends ReadReceipt { * Check whether the pending event list contains a given event by ID. * If pending event ordering is not "detached" then this returns false. * - * @param {string} eventId The event ID to check for. - * @return {boolean} + * @param eventId - The event ID to check for. */ public hasPendingEvent(eventId: string): boolean { return this.pendingEventList?.some(event => event.getId() === eventId) ?? false; @@ -640,8 +737,7 @@ export class Room extends ReadReceipt { /** * Get a specific event from the pending event list, if configured, null otherwise. * - * @param {string} eventId The event ID to check for. - * @return {MatrixEvent} + * @param eventId - The event ID to check for. */ public getPendingEvent(eventId: string): MatrixEvent | null { return this.pendingEventList?.find(event => event.getId() === eventId) ?? null; @@ -650,7 +746,7 @@ export class Room extends ReadReceipt { /** * Get the live unfiltered timeline for this room. * - * @return {module:models/event-timeline~EventTimeline} live timeline + * @returns live timeline */ public getLiveTimeline(): EventTimeline { return this.getUnfilteredTimelineSet().getLiveTimeline(); @@ -659,7 +755,7 @@ export class Room extends ReadReceipt { /** * Get the timestamp of the last message in the room * - * @return {number} the timestamp of the last message in the room + * @returns the timestamp of the last message in the room */ public getLastActiveTimestamp(): number { const timeline = this.getLiveTimeline(); @@ -673,7 +769,7 @@ export class Room extends ReadReceipt { } /** - * @return {string} the membership type (join | leave | invite) for the logged in user + * @returns the membership type (join | leave | invite) for the logged in user */ public getMyMembership(): string { return this.selfMembership ?? "leave"; @@ -682,7 +778,7 @@ export class Room extends ReadReceipt { /** * If this room is a DM we're invited to, * try to find out who invited us - * @return {string} user id of the inviter + * @returns user id of the inviter */ public getDMInviter(): string | undefined { const me = this.getMember(this.myUserId); @@ -701,7 +797,7 @@ export class Room extends ReadReceipt { /** * Assuming this room is a DM room, tries to guess with which user. - * @return {string} user id of the other member (could be syncing user) + * @returns user id of the other member (could be syncing user) */ public guessDMUserId(): string { const me = this.getMember(this.myUserId); @@ -768,7 +864,7 @@ export class Room extends ReadReceipt { /** * Sets the membership this room was received as during sync - * @param {string} membership join | leave | invite + * @param membership - join | leave | invite */ public updateMyMembership(membership: string): void { const prevMembership = this.selfMembership; @@ -812,7 +908,7 @@ export class Room extends ReadReceipt { * Preloads the member list in case lazy loading * of memberships is in use. Can be called multiple times, * it will only preload once. - * @return {Promise} when preloading is done and + * @returns when preloading is done and * accessing the members on the room will take * all members in the room into account */ @@ -893,7 +989,7 @@ export class Room extends ReadReceipt { /** * Empty out the current live timeline and re-request it. This is used when - * historical messages are imported into the room via MSC2716 `/batch_send + * historical messages are imported into the room via MSC2716 `/batch_send` * because the client may already have that section of the timeline loaded. * We need to force the client to throw away their current timeline so that * when they back paginate over the area again with the historical messages @@ -998,8 +1094,8 @@ export class Room extends ReadReceipt { * *

This is used when /sync returns a 'limited' timeline. * - * @param {string=} backPaginationToken token for back-paginating the new timeline - * @param {string=} forwardPaginationToken token for forward-paginating the old live timeline, + * @param backPaginationToken - token for back-paginating the new timeline + * @param forwardPaginationToken - token for forward-paginating the old live timeline, * if absent or null, all timelines are reset, removing old ones (including the previous live * timeline which would otherwise be unable to paginate forwards without this token). * Removing just the old live timeline whilst preserving previous ones is not supported. @@ -1018,7 +1114,7 @@ export class Room extends ReadReceipt { /** * Fix up this.timeline, this.oldState and this.currentState * - * @private + * @internal */ private fixUpLegacyTimelineFields(): void { const previousOldState = this.oldState; @@ -1077,7 +1173,7 @@ export class Room extends ReadReceipt { * disabled, then we aren't tracking room devices at all, so we can't answer this, and an * error will be thrown. * - * @return {boolean} the result + * @returns the result */ public async hasUnverifiedDevices(): Promise { if (!this.client.isRoomEncrypted(this.roomId)) { @@ -1095,7 +1191,7 @@ export class Room extends ReadReceipt { /** * Return the timeline sets for this room. - * @return {EventTimelineSet[]} array of timeline sets for this room + * @returns array of timeline sets for this room */ public getTimelineSets(): EventTimelineSet[] { return this.timelineSets; @@ -1103,7 +1199,7 @@ export class Room extends ReadReceipt { /** * Helper to return the main unfiltered timeline set for this room - * @return {EventTimelineSet} room's unfiltered timeline set + * @returns room's unfiltered timeline set */ public getUnfilteredTimelineSet(): EventTimelineSet { return this.timelineSets[0]; @@ -1112,8 +1208,8 @@ export class Room extends ReadReceipt { /** * Get the timeline which contains the given event from the unfiltered set, if any * - * @param {string} eventId event ID to look for - * @return {?module:models/event-timeline~EventTimeline} timeline containing + * @param eventId - event ID to look for + * @returns timeline containing * the given event, or null if unknown */ public getTimelineForEvent(eventId: string): EventTimeline | null { @@ -1129,7 +1225,7 @@ export class Room extends ReadReceipt { /** * Add a new timeline to this room's unfiltered timeline set * - * @return {module:models/event-timeline~EventTimeline} newly-created timeline + * @returns newly-created timeline */ public addTimeline(): EventTimeline { return this.getUnfilteredTimelineSet().addTimeline(); @@ -1138,7 +1234,7 @@ export class Room extends ReadReceipt { /** * Whether the timeline needs to be refreshed in order to pull in new * historical messages that were imported. - * @param {Boolean} value The value to set + * @param value - The value to set */ public setTimelineNeedsRefresh(value: boolean): void { this.timelineNeedsRefresh = value; @@ -1147,7 +1243,7 @@ export class Room extends ReadReceipt { /** * Whether the timeline needs to be refreshed in order to pull in new * historical messages that were imported. - * @return {Boolean} . + * @returns . */ public getTimelineNeedsRefresh(): boolean { return this.timelineNeedsRefresh; @@ -1156,8 +1252,8 @@ export class Room extends ReadReceipt { /** * Get an event which is stored in our unfiltered timeline set, or in a thread * - * @param {string} eventId event ID to look for - * @return {?module:models/event.MatrixEvent} the given event, or undefined if unknown + * @param eventId - event ID to look for + * @returns the given event, or undefined if unknown */ public findEventById(eventId: string): MatrixEvent | undefined { let event = this.getUnfilteredTimelineSet().findEventById(eventId); @@ -1178,8 +1274,8 @@ export class Room extends ReadReceipt { /** * Get one of the notification counts for this room - * @param {String} type The type of notification count to get. default: 'total' - * @return {Number} The notification count, or undefined if there is no count + * @param type - The type of notification count to get. default: 'total' + * @returns The notification count, or undefined if there is no count * for this type. */ public getUnreadNotificationCount(type = NotificationCountType.Total): number { @@ -1205,8 +1301,8 @@ export class Room extends ReadReceipt { /** * Get one of the notification counts for this room - * @param {String} type The type of notification count to get. default: 'total' - * @return {Number} The notification count, or undefined if there is no count + * @param type - The type of notification count to get. default: 'total' + * @returns The notification count, or undefined if there is no count * for this type. */ public getRoomUnreadNotificationCount(type = NotificationCountType.Total): number { @@ -1216,8 +1312,8 @@ export class Room extends ReadReceipt { /** * @experimental * Get one of the notification counts for a thread - * @param threadId the root event ID - * @param type The type of notification count to get. default: 'total' + * @param threadId - the root event ID + * @param type - The type of notification count to get. default: 'total' * @returns The notification count, or undefined if there is no count * for this type. */ @@ -1228,7 +1324,7 @@ export class Room extends ReadReceipt { /** * @experimental * Checks if the current room has unread thread notifications - * @returns {boolean} + * @returns */ public hasThreadUnreadNotification(): boolean { for (const notification of this.threadNotifications.values()) { @@ -1242,9 +1338,9 @@ export class Room extends ReadReceipt { /** * @experimental * Swet one of the notification count for a thread - * @param threadId the root event ID - * @param type The type of notification count to get. default: 'total' - * @returns {void} + * @param threadId - the root event ID + * @param type - The type of notification count to get. default: 'total' + * @returns */ public setThreadUnreadNotificationCount(threadId: string, type: NotificationCountType, count: number): void { const notification: NotificationCount = { @@ -1299,8 +1395,8 @@ export class Room extends ReadReceipt { /** * Set one of the notification counts for this room - * @param {String} type The type of notification count to set. - * @param {Number} count The new count + * @param type - The type of notification count to set. + * @param count - The new count */ public setUnreadNotificationCount(type: NotificationCountType, count: number): void { this.notificationCounts[type] = count; @@ -1329,7 +1425,7 @@ export class Room extends ReadReceipt { /** * Whether to send encrypted messages to devices within this room. - * @param {Boolean} value true to blacklist unverified devices, null + * @param value - true to blacklist unverified devices, null * to use the global value for this room. */ public setBlacklistUnverifiedDevices(value: boolean): void { @@ -1338,7 +1434,7 @@ export class Room extends ReadReceipt { /** * Whether to send encrypted messages to devices within this room. - * @return {Boolean} true if blacklisting unverified devices, null + * @returns true if blacklisting unverified devices, null * if the global value should be used for this room. */ public getBlacklistUnverifiedDevices(): boolean | null { @@ -1348,15 +1444,15 @@ export class Room extends ReadReceipt { /** * Get the avatar URL for a room if one was set. - * @param {String} baseUrl The homeserver base URL. See - * {@link module:client~MatrixClient#getHomeserverUrl}. - * @param {Number} width The desired width of the thumbnail. - * @param {Number} height The desired height of the thumbnail. - * @param {string} resizeMethod The thumbnail resize method to use, either + * @param baseUrl - The homeserver base URL. See + * {@link MatrixClient#getHomeserverUrl}. + * @param width - The desired width of the thumbnail. + * @param height - The desired height of the thumbnail. + * @param resizeMethod - The thumbnail resize method to use, either * "crop" or "scale". - * @param {boolean} allowDefault True to allow an identicon for this room if an + * @param allowDefault - True to allow an identicon for this room if an * avatar URL wasn't explicitly set. Default: true. (Deprecated) - * @return {?string} the avatar URL or null. + * @returns the avatar URL or null. */ public getAvatarUrl( baseUrl: string, @@ -1380,7 +1476,7 @@ export class Room extends ReadReceipt { /** * Get the mxc avatar url for the room, if one was set. - * @return {string} the mxc avatar url or falsy + * @returns the mxc avatar url or falsy */ public getMxcAvatarUrl(): string | null { return this.currentState.getStateEvents(EventType.RoomAvatar, "")?.getContent()?.url || null; @@ -1390,7 +1486,7 @@ export class Room extends ReadReceipt { * Get this room's canonical alias * The alias returned by this function may not necessarily * still point to this room. - * @return {?string} The room's canonical alias, or null if there is none + * @returns The room's canonical alias, or null if there is none */ public getCanonicalAlias(): string | null { const canonicalAlias = this.currentState.getStateEvents(EventType.RoomCanonicalAlias, ""); @@ -1402,7 +1498,7 @@ export class Room extends ReadReceipt { /** * Get this room's alternative aliases - * @return {array} The room's alternative aliases, or an empty array + * @returns The room's alternative aliases, or an empty array */ public getAltAliases(): string[] { const canonicalAlias = this.currentState.getStateEvents(EventType.RoomCanonicalAlias, ""); @@ -1417,19 +1513,19 @@ export class Room extends ReadReceipt { * *

Will fire "Room.timeline" for each event added. * - * @param {MatrixEvent[]} events A list of events to add. + * @param events - A list of events to add. * - * @param {boolean} toStartOfTimeline True to add these events to the start + * @param toStartOfTimeline - True to add these events to the start * (oldest) instead of the end (newest) of the timeline. If true, the oldest * event will be the last element of 'events'. * - * @param {module:models/event-timeline~EventTimeline} timeline timeline to + * @param timeline - timeline to * add events to. * - * @param {string=} paginationToken token for the next batch of events - * - * @fires module:client~MatrixClient#event:"Room.timeline" + * @param paginationToken - token for the next batch of events * + * @remarks + * Fires {@link RoomEvent.Timeline} */ public addEventsToTimeline( events: MatrixEvent[], @@ -1456,8 +1552,8 @@ export class Room extends ReadReceipt { /** * Get a member from the current room state. - * @param {string} userId The user ID of the member. - * @return {RoomMember} The member or null. + * @param userId - The user ID of the member. + * @returns The member or `null`. */ public getMember(userId: string): RoomMember | null { return this.currentState.getMember(userId); @@ -1466,7 +1562,7 @@ export class Room extends ReadReceipt { /** * Get all currently loaded members from the current * room state. - * @returns {RoomMember[]} Room members + * @returns Room members */ public getMembers(): RoomMember[] { return this.currentState.getMembers(); @@ -1474,7 +1570,7 @@ export class Room extends ReadReceipt { /** * Get a list of members whose membership state is "join". - * @return {RoomMember[]} A list of currently joined members. + * @returns A list of currently joined members. */ public getJoinedMembers(): RoomMember[] { return this.getMembersWithMembership("join"); @@ -1485,7 +1581,7 @@ export class Room extends ReadReceipt { * This method caches the result. * This is a wrapper around the method of the same name in roomState, returning * its result for the room's current state. - * @return {number} The number of members in this room whose membership is 'join' + * @returns The number of members in this room whose membership is 'join' */ public getJoinedMemberCount(): number { return this.currentState.getJoinedMemberCount(); @@ -1493,7 +1589,7 @@ export class Room extends ReadReceipt { /** * Returns the number of invited members in this room - * @return {number} The number of members in this room whose membership is 'invite' + * @returns The number of members in this room whose membership is 'invite' */ public getInvitedMemberCount(): number { return this.currentState.getInvitedMemberCount(); @@ -1501,7 +1597,7 @@ export class Room extends ReadReceipt { /** * Returns the number of invited + joined members in this room - * @return {number} The number of members in this room whose membership is 'invite' or 'join' + * @returns The number of members in this room whose membership is 'invite' or 'join' */ public getInvitedAndJoinedMemberCount(): number { return this.getInvitedMemberCount() + this.getJoinedMemberCount(); @@ -1509,8 +1605,8 @@ export class Room extends ReadReceipt { /** * Get a list of members with given membership state. - * @param {string} membership The membership state. - * @return {RoomMember[]} A list of members with the given membership state. + * @param membership - The membership state. + * @returns A list of members with the given membership state. */ public getMembersWithMembership(membership: string): RoomMember[] { return this.currentState.getMembers().filter(function(m) { @@ -1520,7 +1616,7 @@ export class Room extends ReadReceipt { /** * Get a list of members we should be encrypting for in this room - * @return {Promise} A list of members who + * @returns A list of members who * we should encrypt messages for in this room. */ public async getEncryptionTargetMembers(): Promise { @@ -1534,7 +1630,7 @@ export class Room extends ReadReceipt { /** * Determine whether we should encrypt messages for invited users in this room - * @return {boolean} if we should encrypt messages for invited users + * @returns if we should encrypt messages for invited users */ public shouldEncryptForInvitedMembers(): boolean { const ev = this.currentState.getStateEvents(EventType.RoomHistoryVisibility, ""); @@ -1544,9 +1640,9 @@ export class Room extends ReadReceipt { /** * Get the default room name (i.e. what a given user would see if the * room had no m.room.name) - * @param {string} userId The userId from whose perspective we want + * @param userId - The userId from whose perspective we want * to calculate the default name - * @return {string} The default room name + * @returns The default room name */ public getDefaultRoomName(userId: string): string { return this.calculateRoomName(userId, true); @@ -1554,9 +1650,9 @@ export class Room extends ReadReceipt { /** * Check if the given user_id has the given membership state. - * @param {string} userId The user ID to check. - * @param {string} membership The membership e.g. 'join' - * @return {boolean} True if this user_id has the given membership state. + * @param userId - The user ID to check. + * @param membership - The membership e.g. `'join'` + * @returns True if this user_id has the given membership state. */ public hasMembershipState(userId: string, membership: string): boolean { const member = this.getMember(userId); @@ -1568,9 +1664,9 @@ export class Room extends ReadReceipt { /** * Add a timelineSet for this room with the given filter - * @param {Filter} filter The filter to be applied to this timelineSet - * @param {Object=} opts Configuration options - * @return {EventTimelineSet} The timelineSet + * @param filter - The filter to be applied to this timelineSet + * @param opts - Configuration options + * @returns The timelineSet */ public getOrCreateFilteredTimelineSet( filter: Filter, @@ -1714,8 +1810,6 @@ export class Room extends ReadReceipt { /** * Takes the given thread root events and creates threads for them. - * @param events - * @param toStartOfTimeline */ public processThreadRoots(events: MatrixEvent[], toStartOfTimeline: boolean): void { for (const rootEvent of events) { @@ -1809,8 +1903,7 @@ export class Room extends ReadReceipt { /** * Fetch a single page of threadlist messages for the specific thread filter - * @param filter - * @private + * @internal */ private async fetchRoomThreadList(filter?: ThreadFilterType): Promise { const timelineSet = filter === ThreadFilterType.My @@ -1864,7 +1957,7 @@ export class Room extends ReadReceipt { /** * Forget the timelineSet for this room with the given filter * - * @param {Filter} filter the filter whose timelineSet is to be forgotten + * @param filter - the filter whose timelineSet is to be forgotten */ public removeFilteredTimelineSet(filter: Filter): void { const timelineSet = this.filteredTimelineSets[filter.filterId!]; @@ -2142,10 +2235,12 @@ export class Room extends ReadReceipt { * Add an event to the end of this room's live timelines. Will fire * "Room.timeline". * - * @param {MatrixEvent} event Event to be added - * @param {IAddLiveEventOptions} addLiveEventOptions addLiveEvent options - * @fires module:client~MatrixClient#event:"Room.timeline" - * @private + * @param event - Event to be added + * @param addLiveEventOptions - addLiveEvent options + * @internal + * + * @remarks + * Fires {@link RoomEvent.Timeline} */ private addLiveEvent(event: MatrixEvent, addLiveEventOptions: IAddLiveEventOptions): void { const { duplicateStrategy, timelineWasEmpty, fromCache } = addLiveEventOptions; @@ -2185,14 +2280,15 @@ export class Room extends ReadReceipt { * *

This is an internal method, intended for use by MatrixClient. * - * @param {module:models/event.MatrixEvent} event The event to add. + * @param event - The event to add. * - * @param {string} txnId Transaction id for this outgoing event - * - * @fires module:client~MatrixClient#event:"Room.localEchoUpdated" + * @param txnId - Transaction id for this outgoing event * * @throws if the event doesn't have status SENDING, or we aren't given a * unique transaction id. + * + * @remarks + * Fires {@link RoomEvent.LocalEchoUpdated} */ public addPendingEvent(event: MatrixEvent, txnId: string): void { if (event.status !== EventStatus.SENDING && event.status !== EventStatus.NOT_SENT) { @@ -2264,7 +2360,7 @@ export class Room extends ReadReceipt { * all messages that are not yet encrypted will be discarded * * This is because the flow of EVENT_STATUS transition is - * queued => sending => encrypting => sending => sent + * `queued => sending => encrypting => sending => sent` * * Steps 3 and 4 are skipped for unencrypted room. * It is better to discard an unencrypted message rather than persisting @@ -2296,7 +2392,7 @@ export class Room extends ReadReceipt { * which are just kept detached for their local echo. * * Also note that live events are aggregated in the live EventTimelineSet. - * @param {module:models/event.MatrixEvent} event the relation event that needs to be aggregated. + * @param event - the relation event that needs to be aggregated. */ private aggregateNonLiveRelation(event: MatrixEvent): void { this.relations.aggregateChildEvent(event); @@ -2312,13 +2408,15 @@ export class Room extends ReadReceipt { *

We move the event to the live timeline if it isn't there already, and * update it. * - * @param {module:models/event.MatrixEvent} remoteEvent The event received from + * @param remoteEvent - The event received from * /sync - * @param {module:models/event.MatrixEvent} localEvent The local echo, which + * @param localEvent - The local echo, which * should be either in the pendingEventList or the timeline. * - * @fires module:client~MatrixClient#event:"Room.localEchoUpdated" - * @private + * @internal + * + * @remarks + * Fires {@link RoomEvent.LocalEchoUpdated} */ public handleRemoteEcho(remoteEvent: MatrixEvent, localEvent: MatrixEvent): void { const oldEventId = localEvent.getId()!; @@ -2359,11 +2457,12 @@ export class Room extends ReadReceipt { * *

This is an internal method. * - * @param {MatrixEvent} event local echo event - * @param {EventStatus} newStatus status to assign - * @param {string} newEventId new event id to assign. Ignored unless - * newStatus == EventStatus.SENT. - * @fires module:client~MatrixClient#event:"Room.localEchoUpdated" + * @param event - local echo event + * @param newStatus - status to assign + * @param newEventId - new event id to assign. Ignored unless newStatus == EventStatus.SENT. + * + * @remarks + * Fires {@link RoomEvent.LocalEchoUpdated} */ public updatePendingEvent(event: MatrixEvent, newStatus: EventStatus, newEventId?: string): void { logger.log( @@ -2470,9 +2569,9 @@ export class Room extends ReadReceipt { * events and typing notifications. These events are treated as "live" so * they will go to the end of the timeline. * - * @param {MatrixEvent[]} events A list of events to add. - * @param {IAddLiveEventOptions} addLiveEventOptions addLiveEvent options - * @throws If duplicateStrategy is not falsey, 'replace' or 'ignore'. + * @param events - A list of events to add. + * @param addLiveEventOptions - addLiveEvent options + * @throws If `duplicateStrategy` is not falsey, 'replace' or 'ignore'. */ public addLiveEvents(events: MatrixEvent[], addLiveEventOptions?: IAddLiveEventOptions): void; /** @@ -2615,8 +2714,8 @@ export class Room extends ReadReceipt { /** * Add a receipt event to the room. - * @param {MatrixEvent} event The m.receipt event. - * @param {Boolean} synthetic True if this event is implicit. + * @param event - The m.receipt event. + * @param synthetic - True if this event is implicit. */ public addReceipt(event: MatrixEvent, synthetic = false): void { const content = event.getContent(); @@ -2646,7 +2745,7 @@ export class Room extends ReadReceipt { /** * Adds/handles ephemeral events such as typing notifications and read receipts. - * @param {MatrixEvent[]} events A list of events to process + * @param events - A list of events to process */ public addEphemeralEvents(events: MatrixEvent[]): void { for (const event of events) { @@ -2660,7 +2759,7 @@ export class Room extends ReadReceipt { /** * Removes events from this room. - * @param {String[]} eventIds A list of eventIds to remove. + * @param eventIds - A list of eventIds to remove. */ public removeEvents(eventIds: string[]): void { for (const eventId of eventIds) { @@ -2671,9 +2770,9 @@ export class Room extends ReadReceipt { /** * Removes a single event from this room. * - * @param {String} eventId The id of the event to remove + * @param eventId - The id of the event to remove * - * @return {boolean} true if the event was removed from any of the room's timeline sets + * @returns true if the event was removed from any of the room's timeline sets */ public removeEvent(eventId: string): boolean { let removedAny = false; @@ -2693,7 +2792,9 @@ export class Room extends ReadReceipt { * Recalculate various aspects of the room, including the room name and * room summary. Call this any time the room's current state is modified. * May fire "Room.name" if the room name is updated. - * @fires module:client~MatrixClient#event:"Room.name" + * + * @remarks + * Fires {@link RoomEvent.Name} */ public recalculate(): void { // set fake stripped state events if this is an invite room so logic remains @@ -2736,7 +2837,7 @@ export class Room extends ReadReceipt { /** * Update the room-tag event for the room. The previous one is overwritten. - * @param {MatrixEvent} event the m.tag event + * @param event - the m.tag event */ public addTags(event: MatrixEvent): void { // event content looks like: @@ -2757,7 +2858,7 @@ export class Room extends ReadReceipt { /** * Update the account_data events for this room, overwriting events of the same type. - * @param {Array} events an array of account_data events to add + * @param events - an array of account_data events to add */ public addAccountData(events: MatrixEvent[]): void { for (const event of events) { @@ -2772,8 +2873,8 @@ export class Room extends ReadReceipt { /** * Access account_data event of given event type for this room - * @param {string} type the type of account_data event to be accessed - * @return {?MatrixEvent} the account_data event in question + * @param type - the type of account_data event to be accessed + * @returns the account_data event in question */ public getAccountData(type: EventType | string): MatrixEvent | undefined { return this.accountData[type]; @@ -2781,7 +2882,7 @@ export class Room extends ReadReceipt { /** * Returns whether the syncing user has permission to send a message in the room - * @return {boolean} true if the user should be permitted to send + * @returns true if the user should be permitted to send * message events into the room. */ public maySendMessage(): boolean { @@ -2792,8 +2893,8 @@ export class Room extends ReadReceipt { /** * Returns whether the given user has permissions to issue an invite for this room. - * @param {string} userId the ID of the Matrix user to check permissions for - * @returns {boolean} true if the user should be permitted to issue invites for this room. + * @param userId - the ID of the Matrix user to check permissions for + * @returns true if the user should be permitted to issue invites for this room. */ public canInvite(userId: string): boolean { let canInvite = this.getMyMembership() === "join"; @@ -2808,7 +2909,7 @@ export class Room extends ReadReceipt { /** * Returns the join rule based on the m.room.join_rule state event, defaulting to `invite`. - * @returns {string} the join_rule applied to this room + * @returns the join_rule applied to this room */ public getJoinRule(): JoinRule { return this.currentState.getJoinRule(); @@ -2816,7 +2917,7 @@ export class Room extends ReadReceipt { /** * Returns the history visibility based on the m.room.history_visibility state event, defaulting to `shared`. - * @returns {HistoryVisibility} the history_visibility applied to this room + * @returns the history_visibility applied to this room */ public getHistoryVisibility(): HistoryVisibility { return this.currentState.getHistoryVisibility(); @@ -2824,7 +2925,7 @@ export class Room extends ReadReceipt { /** * Returns the history visibility based on the m.room.history_visibility state event, defaulting to `shared`. - * @returns {HistoryVisibility} the history_visibility applied to this room + * @returns the history_visibility applied to this room */ public getGuestAccess(): GuestAccess { return this.currentState.getGuestAccess(); @@ -2832,7 +2933,7 @@ export class Room extends ReadReceipt { /** * Returns the type of the room from the `m.room.create` event content or undefined if none is set - * @returns {?string} the type of the room. + * @returns the type of the room. */ public getType(): RoomType | string | undefined { const createEvent = this.currentState.getStateEvents(EventType.RoomCreate, ""); @@ -2848,7 +2949,7 @@ export class Room extends ReadReceipt { /** * Returns whether the room is a space-room as defined by MSC1772. - * @returns {boolean} true if the room's type is RoomType.Space + * @returns true if the room's type is RoomType.Space */ public isSpaceRoom(): boolean { return this.getType() === RoomType.Space; @@ -2856,7 +2957,7 @@ export class Room extends ReadReceipt { /** * Returns whether the room is a call-room as defined by MSC3417. - * @returns {boolean} true if the room's type is RoomType.UnstableCall + * @returns true if the room's type is RoomType.UnstableCall */ public isCallRoom(): boolean { return this.getType() === RoomType.UnstableCall; @@ -2864,7 +2965,7 @@ export class Room extends ReadReceipt { /** * Returns whether the room is a video room. - * @returns {boolean} true if the room's type is RoomType.ElementVideo + * @returns true if the room's type is RoomType.ElementVideo */ public isElementVideoRoom(): boolean { return this.getType() === RoomType.ElementVideo; @@ -2900,11 +3001,11 @@ export class Room extends ReadReceipt { /** * This is an internal method. Calculates the name of the room from the current * room state. - * @param {string} userId The client's user ID. Used to filter room members + * @param userId - The client's user ID. Used to filter room members * correctly. - * @param {boolean} ignoreRoomNameEvent Return the implicit room name that we'd see if there + * @param ignoreRoomNameEvent - Return the implicit room name that we'd see if there * was no m.room.name event. - * @return {string} The calculated room name. + * @returns The calculated room name. */ private calculateRoomName(userId: string, ignoreRoomNameEvent = false): string { if (!ignoreRoomNameEvent) { @@ -3151,7 +3252,7 @@ export class Room extends ReadReceipt { * a (more recent) visibility change event, patch the event in * place so that clients now not to display it. * - * @param event Any matrix event. If this event has at least one a + * @param event - Any matrix event. If this event has at least one a * pending visibility change event, apply the latest visibility * change event. */ @@ -3250,118 +3351,3 @@ function memberNamesToRoomName(names: string[], count: number): string { } } } - -/** - * Fires when an event we had previously received is redacted. - * - * (Note this is *not* fired when the redaction happens before we receive the - * event). - * - * @event module:client~MatrixClient#"Room.redaction" - * @param {MatrixEvent} event The matrix redaction event - * @param {Room} room The room containing the redacted event - */ - -/** - * Fires when an event that was previously redacted isn't anymore. - * This happens when the redaction couldn't be sent and - * was subsequently cancelled by the user. Redactions have a local echo - * which is undone in this scenario. - * - * @event module:client~MatrixClient#"Room.redactionCancelled" - * @param {MatrixEvent} event The matrix redaction event that was cancelled. - * @param {Room} room The room containing the unredacted event - */ - -/** - * Fires whenever the name of a room is updated. - * @event module:client~MatrixClient#"Room.name" - * @param {Room} room The room whose Room.name was updated. - * @example - * matrixClient.on("Room.name", function(room){ - * var newName = room.name; - * }); - */ - -/** - * Fires whenever a receipt is received for a room - * @event module:client~MatrixClient#"Room.receipt" - * @param {event} event The receipt event - * @param {Room} room The room whose receipts was updated. - * @example - * matrixClient.on("Room.receipt", function(event, room){ - * var receiptContent = event.getContent(); - * }); - */ - -/** - * Fires whenever a room's tags are updated. - * @event module:client~MatrixClient#"Room.tags" - * @param {event} event The tags event - * @param {Room} room The room whose Room.tags was updated. - * @example - * matrixClient.on("Room.tags", function(event, room){ - * var newTags = event.getContent().tags; - * if (newTags["favourite"]) showStar(room); - * }); - */ - -/** - * Fires whenever a room's account_data is updated. - * @event module:client~MatrixClient#"Room.accountData" - * @param {event} event The account_data event - * @param {Room} room The room whose account_data was updated. - * @param {MatrixEvent} prevEvent The event being replaced by - * the new account data, if known. - * @example - * matrixClient.on("Room.accountData", function(event, room, oldEvent){ - * if (event.getType() === "m.room.colorscheme") { - * applyColorScheme(event.getContents()); - * } - * }); - */ - -/** - * Fires when the status of a transmitted event is updated. - * - *

When an event is first transmitted, a temporary copy of the event is - * inserted into the timeline, with a temporary event id, and a status of - * 'SENDING'. - * - *

Once the echo comes back from the server, the content of the event - * (MatrixEvent.event) is replaced by the complete event from the homeserver, - * thus updating its event id, as well as server-generated fields such as the - * timestamp. Its status is set to null. - * - *

Once the /send request completes, if the remote echo has not already - * arrived, the event is updated with a new event id and the status is set to - * 'SENT'. The server-generated fields are of course not updated yet. - * - *

If the /send fails, In this case, the event's status is set to - * 'NOT_SENT'. If it is later resent, the process starts again, setting the - * status to 'SENDING'. Alternatively, the message may be cancelled, which - * removes the event from the room, and sets the status to 'CANCELLED'. - * - *

This event is raised to reflect each of the transitions above. - * - * @event module:client~MatrixClient#"Room.localEchoUpdated" - * - * @param {MatrixEvent} event The matrix event which has been updated - * - * @param {Room} room The room containing the redacted event - * - * @param {string} oldEventId The previous event id (the temporary event id, - * except when updating a successfully-sent event when its echo arrives) - * - * @param {EventStatus} oldStatus The previous event status. - */ - -/** - * Fires when the logged in user's membership in the room is updated. - * - * @event module:models/room~Room#"Room.myMembership" - * @param {Room} room The room in which the membership has been updated - * @param {string} membership The new membership value - * @param {string} prevMembership The previous membership value - */ - diff --git a/src/models/search-result.ts b/src/models/search-result.ts index f598301d7..2f27495ac 100644 --- a/src/models/search-result.ts +++ b/src/models/search-result.ts @@ -14,10 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/** - * @module models/search-result - */ - import { EventContext } from "./event-context"; import { EventMapper } from "../event-mapper"; import { IResultContext, ISearchResult } from "../@types/search"; @@ -25,10 +21,6 @@ import { IResultContext, ISearchResult } from "../@types/search"; export class SearchResult { /** * Create a SearchResponse from the response to /search - * @static - * @param {Object} jsonObj - * @param {function} eventMapper - * @return {SearchResult} */ public static fromJson(jsonObj: ISearchResult, eventMapper: EventMapper): SearchResult { @@ -54,11 +46,9 @@ export class SearchResult { /** * Construct a new SearchResult * - * @param {number} rank where this SearchResult ranks in the results - * @param {event-context.EventContext} context the matching event and its + * @param rank - where this SearchResult ranks in the results + * @param context - the matching event and its * context - * - * @constructor */ public constructor(public readonly rank: number, public readonly context: EventContext) {} } diff --git a/src/models/thread.ts b/src/models/thread.ts index c595995b1..61b010a18 100644 --- a/src/models/thread.ts +++ b/src/models/thread.ts @@ -247,10 +247,10 @@ export class Thread extends ReadReceipt { * Add an event to the thread and updates * the tail/root references if needed * Will fire "Thread.update" - * @param event The event to add - * @param {boolean} toStartOfTimeline whether the event is being added + * @param event - The event to add + * @param toStartOfTimeline - whether the event is being added * to the start (and not the end) of the timeline. - * @param {boolean} emit whether to emit the Update event if the thread was updated or not. + * @param emit - whether to emit the Update event if the thread was updated or not. */ public async addEvent(event: MatrixEvent, toStartOfTimeline: boolean, emit = true): Promise { this.setEventMetadata(event); diff --git a/src/models/typed-event-emitter.ts b/src/models/typed-event-emitter.ts index 691ec5ec3..f91500778 100644 --- a/src/models/typed-event-emitter.ts +++ b/src/models/typed-event-emitter.ts @@ -69,7 +69,7 @@ export class TypedEventEmitter< return super.listenerCount(event); } - public listeners(event: Events | EventEmitterEvents): Function[] { + public listeners(event: Events | EventEmitterEvents): ReturnType { return super.listeners(event); } @@ -119,7 +119,7 @@ export class TypedEventEmitter< return super.removeListener(event, listener); } - public rawListeners(event: Events | EventEmitterEvents): Function[] { + public rawListeners(event: Events | EventEmitterEvents): ReturnType { return super.rawListeners(event); } } diff --git a/src/models/user.ts b/src/models/user.ts index 5d92ca494..3dd199f3b 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -14,10 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/** - * @module models/user - */ - import { MatrixEvent } from "./event"; import { TypedEventEmitter } from "./typed-event-emitter"; @@ -30,51 +26,132 @@ export enum UserEvent { } export type UserEventHandlerMap = { + /** + * Fires whenever any user's display name changes. + * @param event - The matrix event which caused this event to fire. + * @param user - The user whose User.displayName changed. + * @example + * ``` + * matrixClient.on("User.displayName", function(event, user){ + * var newName = user.displayName; + * }); + * ``` + */ [UserEvent.DisplayName]: (event: MatrixEvent | undefined, user: User) => void; + /** + * Fires whenever any user's avatar URL changes. + * @param event - The matrix event which caused this event to fire. + * @param user - The user whose User.avatarUrl changed. + * @example + * ``` + * matrixClient.on("User.avatarUrl", function(event, user){ + * var newUrl = user.avatarUrl; + * }); + * ``` + */ [UserEvent.AvatarUrl]: (event: MatrixEvent | undefined, user: User) => void; + /** + * Fires whenever any user's presence changes. + * @param event - The matrix event which caused this event to fire. + * @param user - The user whose User.presence changed. + * @example + * ``` + * matrixClient.on("User.presence", function(event, user){ + * var newPresence = user.presence; + * }); + * ``` + */ [UserEvent.Presence]: (event: MatrixEvent | undefined, user: User) => void; + /** + * Fires whenever any user's currentlyActive changes. + * @param event - The matrix event which caused this event to fire. + * @param user - The user whose User.currentlyActive changed. + * @example + * ``` + * matrixClient.on("User.currentlyActive", function(event, user){ + * var newCurrentlyActive = user.currentlyActive; + * }); + * ``` + */ [UserEvent.CurrentlyActive]: (event: MatrixEvent | undefined, user: User) => void; + /** + * Fires whenever any user's lastPresenceTs changes, + * ie. whenever any presence event is received for a user. + * @param event - The matrix event which caused this event to fire. + * @param user - The user whose User.lastPresenceTs changed. + * @example + * ``` + * matrixClient.on("User.lastPresenceTs", function(event, user){ + * var newlastPresenceTs = user.lastPresenceTs; + * }); + * ``` + */ [UserEvent.LastPresenceTs]: (event: MatrixEvent | undefined, user: User) => void; }; export class User extends TypedEventEmitter { private modified = -1; - // XXX these should be read-only + /** + * The 'displayname' of the user if known. + * @privateRemarks + * Should be read-only + */ public displayName?: string; public rawDisplayName?: string; + /** + * The 'avatar_url' of the user if known. + * @privateRemarks + * Should be read-only + */ public avatarUrl?: string; + /** + * The presence status message if known. + * @privateRemarks + * Should be read-only + */ public presenceStatusMsg?: string; + /** + * The presence enum if known. + * @privateRemarks + * Should be read-only + */ public presence = "offline"; + /** + * Timestamp (ms since the epoch) for when we last received presence data for this user. + * We can subtract lastActiveAgo from this to approximate an absolute value for when a user was last active. + * @privateRemarks + * Should be read-only + */ public lastActiveAgo = 0; + /** + * The time elapsed in ms since the user interacted proactively with the server, + * or we saw a message from the user + * @privateRemarks + * Should be read-only + */ public lastPresenceTs = 0; + /** + * Whether we should consider lastActiveAgo to be an approximation + * and that the user should be seen as active 'now' + * @privateRemarks + * Should be read-only + */ public currentlyActive = false; + /** + * The events describing this user. + * @privateRemarks + * Should be read-only + */ public events: { + /** The m.presence event for this user. */ presence?: MatrixEvent; profile?: MatrixEvent; } = {}; /** - * Construct a new User. A User must have an ID and can optionally have extra - * information associated with it. - * @constructor - * @param {string} userId Required. The ID of this user. - * @prop {string} userId The ID of the user. - * @prop {Object} info The info object supplied in the constructor. - * @prop {string} displayName The 'displayname' of the user if known. - * @prop {string} avatarUrl The 'avatar_url' of the user if known. - * @prop {string} presence The presence enum if known. - * @prop {string} presenceStatusMsg The presence status message if known. - * @prop {Number} lastActiveAgo The time elapsed in ms since the user interacted - * proactively with the server, or we saw a message from the user - * @prop {Number} lastPresenceTs Timestamp (ms since the epoch) for when we last - * received presence data for this user. We can subtract - * lastActiveAgo from this to approximate an absolute value for - * when a user was last active. - * @prop {Boolean} currentlyActive Whether we should consider lastActiveAgo to be - * an approximation and that the user should be seen as active 'now' - * @prop {Object} events The events describing this user. - * @prop {MatrixEvent} events.presence The m.presence event for this user. + * Construct a new User. A User must have an ID and can optionally have extra information associated with it. + * @param userId - Required. The ID of this user. */ public constructor(public readonly userId: string) { super(); @@ -87,10 +164,12 @@ export class User extends TypedEventEmitter { * Update this User with the given presence event. May fire "User.presence", * "User.avatarUrl" and/or "User.displayName" if this event updates this user's * properties. - * @param {MatrixEvent} event The m.presence event. - * @fires module:client~MatrixClient#event:"User.presence" - * @fires module:client~MatrixClient#event:"User.displayName" - * @fires module:client~MatrixClient#event:"User.avatarUrl" + * @param event - The `m.presence` event. + * + * @remarks + * Fires {@link UserEvent.Presence} + * Fires {@link UserEvent.DisplayName} + * Fires {@link UserEvent.AvatarUrl} */ public setPresenceEvent(event: MatrixEvent): void { if (event.getType() !== "m.presence") { @@ -142,7 +221,7 @@ export class User extends TypedEventEmitter { /** * Manually set this user's display name. No event is emitted in response to this * as there is no underlying MatrixEvent to emit with. - * @param {string} name The new display name. + * @param name - The new display name. */ public setDisplayName(name: string): void { const oldName = this.displayName; @@ -155,7 +234,7 @@ export class User extends TypedEventEmitter { /** * Manually set this user's non-disambiguated display name. No event is emitted * in response to this as there is no underlying MatrixEvent to emit with. - * @param {string} name The new display name. + * @param name - The new display name. */ public setRawDisplayName(name?: string): void { this.rawDisplayName = name; @@ -164,7 +243,7 @@ export class User extends TypedEventEmitter { /** * Manually set this user's avatar URL. No event is emitted in response to this * as there is no underlying MatrixEvent to emit with. - * @param {string} url The new avatar URL. + * @param url - The new avatar URL. */ public setAvatarUrl(url?: string): void { const oldUrl = this.avatarUrl; @@ -185,7 +264,7 @@ export class User extends TypedEventEmitter { * Get the timestamp when this User was last updated. This timestamp is * updated when this User receives a new Presence event which has updated a * property on this object. It is updated before firing events. - * @return {number} The timestamp + * @returns The timestamp */ public getLastModifiedTime(): number { return this.modified; @@ -194,65 +273,9 @@ export class User extends TypedEventEmitter { /** * Get the absolute timestamp when this User was last known active on the server. * It is *NOT* accurate if this.currentlyActive is true. - * @return {number} The timestamp + * @returns The timestamp */ public getLastActiveTs(): number { return this.lastPresenceTs - this.lastActiveAgo; } } - -/** - * Fires whenever any user's lastPresenceTs changes, - * ie. whenever any presence event is received for a user. - * @event module:client~MatrixClient#"User.lastPresenceTs" - * @param {MatrixEvent} event The matrix event which caused this event to fire. - * @param {User} user The user whose User.lastPresenceTs changed. - * @example - * matrixClient.on("User.lastPresenceTs", function(event, user){ - * var newlastPresenceTs = user.lastPresenceTs; - * }); - */ - -/** - * Fires whenever any user's presence changes. - * @event module:client~MatrixClient#"User.presence" - * @param {MatrixEvent} event The matrix event which caused this event to fire. - * @param {User} user The user whose User.presence changed. - * @example - * matrixClient.on("User.presence", function(event, user){ - * var newPresence = user.presence; - * }); - */ - -/** - * Fires whenever any user's currentlyActive changes. - * @event module:client~MatrixClient#"User.currentlyActive" - * @param {MatrixEvent} event The matrix event which caused this event to fire. - * @param {User} user The user whose User.currentlyActive changed. - * @example - * matrixClient.on("User.currentlyActive", function(event, user){ - * var newCurrentlyActive = user.currentlyActive; - * }); - */ - -/** - * Fires whenever any user's display name changes. - * @event module:client~MatrixClient#"User.displayName" - * @param {MatrixEvent} event The matrix event which caused this event to fire. - * @param {User} user The user whose User.displayName changed. - * @example - * matrixClient.on("User.displayName", function(event, user){ - * var newName = user.displayName; - * }); - */ - -/** - * Fires whenever any user's avatar URL changes. - * @event module:client~MatrixClient#"User.avatarUrl" - * @param {MatrixEvent} event The matrix event which caused this event to fire. - * @param {User} user The user whose User.avatarUrl changed. - * @example - * matrixClient.on("User.avatarUrl", function(event, user){ - * var newUrl = user.avatarUrl; - * }); - */ diff --git a/src/pushprocessor.ts b/src/pushprocessor.ts index cc1246825..e6a307692 100644 --- a/src/pushprocessor.ts +++ b/src/pushprocessor.ts @@ -38,10 +38,6 @@ import { } from "./@types/PushRules"; import { EventType } from "./@types/event"; -/** - * @module pushprocessor - */ - const RULEKINDS_IN_ORDER = [ PushRuleKind.Override, PushRuleKind.ContentSpecific, @@ -116,25 +112,27 @@ const DEFAULT_UNDERRIDE_RULES: IPushRule[] = [ ]; export interface IActionsObject { + /** Whether this event should notify the user or not. */ notify: boolean; + /** How this event should be notified. */ tweaks: Partial>; } export class PushProcessor { /** * Construct a Push Processor. - * @constructor - * @param {Object} client The Matrix client object to use + * @param client - The Matrix client object to use */ public constructor(private readonly client: MatrixClient) {} /** * Convert a list of actions into a object with the actions as keys and their values - * eg. [ 'notify', { set_tweak: 'sound', value: 'default' } ] - * becomes { notify: true, tweaks: { sound: 'default' } } - * @param {array} actionList The actions list + * @example + * eg. `[ 'notify', { set_tweak: 'sound', value: 'default' } ]` + * becomes `{ notify: true, tweaks: { sound: 'default' } }` + * @param actionList - The actions list * - * @return {object} A object with key 'notify' (true or false) and an object of actions + * @returns A object with key 'notify' (true or false) and an object of actions */ public static actionListToActionsObject(actionList: PushRuleAction[]): IActionsObject { const actionObj: IActionsObject = { notify: false, tweaks: {} }; @@ -155,8 +153,8 @@ export class PushProcessor { * Rewrites conditions on a client's push rules to match the defaults * where applicable. Useful for upgrading push rules to more strict * conditions when the server is falling behind on defaults. - * @param {object} incomingRules The client's existing push rules - * @returns {object} The rewritten rules + * @param incomingRules - The client's existing push rules + * @returns The rewritten rules */ public static rewriteDefaultRules(incomingRules: IPushRules): IPushRules { let newRules: IPushRules = JSON.parse(JSON.stringify(incomingRules)); // deep clone @@ -502,10 +500,6 @@ export class PushProcessor { /** * Get the user's push actions for the given event - * - * @param {module:models/event.MatrixEvent} ev - * - * @return {PushAction} */ public actionsForEvent(ev: MatrixEvent): IActionsObject { return this.pushActionsForEventAndRulesets(ev, this.client.pushRules); @@ -514,8 +508,8 @@ export class PushProcessor { /** * Get one of the users push rules by its ID * - * @param {string} ruleId The ID of the rule to search for - * @return {object} The push rule, or null if no such rule was found + * @param ruleId - The ID of the rule to search for + * @returns The push rule, or null if no such rule was found */ public getPushRuleById(ruleId: string): IPushRule | null { for (const scope of ['global'] as const) { @@ -532,15 +526,3 @@ export class PushProcessor { return null; } } - -/** - * @typedef {Object} PushAction - * @type {Object} - * @property {boolean} notify Whether this event should notify the user or not. - * @property {Object} tweaks How this event should be notified. - * @property {boolean} tweaks.highlight Whether this event should be highlighted - * on the UI. - * @property {boolean} tweaks.sound Whether this notification should produce a - * noise. - */ - diff --git a/src/realtime-callbacks.ts b/src/realtime-callbacks.ts index 4677b0c1e..005e9816b 100644 --- a/src/realtime-callbacks.ts +++ b/src/realtime-callbacks.ts @@ -48,16 +48,17 @@ type Callback = { const callbackList: Callback[] = []; // var debuglog = logger.log.bind(logger); +/* istanbul ignore next */ const debuglog = function(...params: any[]): void {}; /** * reimplementation of window.setTimeout, which will call the callback if * the wallclock time goes past the deadline. * - * @param {function} func callback to be called after a delay - * @param {Number} delayMs number of milliseconds to delay by + * @param func - callback to be called after a delay + * @param delayMs - number of milliseconds to delay by * - * @return {Number} an identifier for this callback, which may be passed into + * @returns an identifier for this callback, which may be passed into * clearTimeout later. */ export function setTimeout(func: (...params: any[]) => void, delayMs: number, ...params: any[]): number { @@ -93,7 +94,7 @@ export function setTimeout(func: (...params: any[]) => void, delayMs: number, .. /** * reimplementation of window.clearTimeout, which mirrors setTimeout * - * @param {Number} key result from an earlier setTimeout call + * @param key - result from an earlier setTimeout call */ export function clearTimeout(key: number): void { if (callbackList.length === 0) { diff --git a/src/rendezvous/MSC3906Rendezvous.ts b/src/rendezvous/MSC3906Rendezvous.ts index a93d4c476..d4ed1bc17 100644 --- a/src/rendezvous/MSC3906Rendezvous.ts +++ b/src/rendezvous/MSC3906Rendezvous.ts @@ -67,9 +67,9 @@ export class MSC3906Rendezvous { private _code?: string; /** - * @param channel The secure channel used for communication - * @param client The Matrix client in used on the device already logged in - * @param onFailure Callback for when the rendezvous fails + * @param channel - The secure channel used for communication + * @param client - The Matrix client in used on the device already logged in + * @param onFailure - Callback for when the rendezvous fails */ public constructor( private channel: RendezvousChannel, @@ -217,7 +217,7 @@ export class MSC3906Rendezvous { /** * Verify the device and cross-sign it. - * @param timeout time in milliseconds to wait for device to come online + * @param timeout - time in milliseconds to wait for device to come online * @returns the new device info if the device was verified */ public async verifyNewDeviceOnExistingDevice( diff --git a/src/rendezvous/RendezvousChannel.ts b/src/rendezvous/RendezvousChannel.ts index 9b1060304..f5c35217f 100644 --- a/src/rendezvous/RendezvousChannel.ts +++ b/src/rendezvous/RendezvousChannel.ts @@ -28,7 +28,7 @@ export interface RendezvousChannel { /** * Send a payload via the channel. - * @param data payload to send + * @param data - payload to send */ send(data: T): Promise; diff --git a/src/rendezvous/RendezvousTransport.ts b/src/rendezvous/RendezvousTransport.ts index 231a0f1c4..8721febff 100644 --- a/src/rendezvous/RendezvousTransport.ts +++ b/src/rendezvous/RendezvousTransport.ts @@ -41,7 +41,7 @@ export interface RendezvousTransport { /** * Send data via the transport. - * @param data the data itself + * @param data - the data itself */ send(data: T): Promise; @@ -52,7 +52,7 @@ export interface RendezvousTransport { /** * Cancel the rendezvous. This will call `onCancelled()` if it is set. - * @param reason the reason for the cancellation/failure + * @param reason - the reason for the cancellation/failure */ cancel(reason: RendezvousFailureReason): Promise; } diff --git a/src/room-hierarchy.ts b/src/room-hierarchy.ts index c15f2ac56..3ed020527 100644 --- a/src/room-hierarchy.ts +++ b/src/room-hierarchy.ts @@ -14,10 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/** - * @module room-hierarchy - */ - import { Room } from "./models/room"; import { IHierarchyRoom, IHierarchyRelation } from "./@types/spaces"; import { MatrixClient } from "./client"; @@ -41,11 +37,10 @@ export class RoomHierarchy { * * A RoomHierarchy instance allows you to easily make use of the /hierarchy API and paginate it. * - * @param {Room} root the root of this hierarchy - * @param {number} pageSize the maximum number of rooms to return per page, can be overridden per load request. - * @param {number} maxDepth the maximum depth to traverse the hierarchy to - * @param {boolean} suggestedOnly whether to only return rooms with suggested=true. - * @constructor + * @param root - the root of this hierarchy + * @param pageSize - the maximum number of rooms to return per page, can be overridden per load request. + * @param maxDepth - the maximum depth to traverse the hierarchy to + * @param suggestedOnly - whether to only return rooms with suggested=true. */ public constructor( public readonly root: Room, diff --git a/src/scheduler.ts b/src/scheduler.ts index 74bf7dd25..d6cfef362 100644 --- a/src/scheduler.ts +++ b/src/scheduler.ts @@ -17,7 +17,6 @@ limitations under the License. /** * This is an internal module which manages queuing, scheduling and retrying * of requests. - * @module scheduler */ import * as utils from "./utils"; import { logger } from './logger'; @@ -35,20 +34,13 @@ interface IQueueEntry { attempts: number; } +/** + * The function to invoke to process (send) events in the queue. + * @param event - The event to send. + * @returns Resolved/rejected depending on the outcome of the request. + */ type ProcessFunction = (event: MatrixEvent) => Promise; -/** - * Construct a scheduler for Matrix. Requires - * {@link module:scheduler~MatrixScheduler#setProcessFunction} to be provided - * with a way of processing events. - * @constructor - * @param {module:scheduler~retryAlgorithm} retryAlgorithm Optional. The retry - * algorithm to apply when determining when to try to send an event again. - * Defaults to {@link module:scheduler~MatrixScheduler.RETRY_BACKOFF_RATELIMIT}. - * @param {module:scheduler~queueAlgorithm} queueAlgorithm Optional. The queuing - * algorithm to apply when determining which events should be sent before the - * given event. Defaults to {@link module:scheduler~MatrixScheduler.QUEUE_MESSAGES}. - */ // eslint-disable-next-line camelcase export class MatrixScheduler { /** @@ -56,11 +48,8 @@ export class MatrixScheduler { * times of 2, 4, 8, and 16 seconds (30s total) after which we give up. If the * failure was due to a rate limited request, the time specified in the error is * waited before being retried. - * @param {MatrixEvent} event - * @param {Number} attempts Number of attempts that have been made, including the one that just failed (ie. starting at 1) - * @param {MatrixError} err - * @return {Number} - * @see module:scheduler~retryAlgorithm + * @param attempts - Number of attempts that have been made, including the one that just failed (ie. starting at 1) + * @see retryAlgorithm */ // eslint-disable-next-line @typescript-eslint/naming-convention public static RETRY_BACKOFF_RATELIMIT(event: MatrixEvent | null, attempts: number, err: MatrixError): number { @@ -90,11 +79,9 @@ export class MatrixScheduler { } /** - * Queues m.room.message events and lets other events continue + * Queues `m.room.message` events and lets other events continue * concurrently. - * @param {MatrixEvent} event - * @return {string} - * @see module:scheduler~queueAlgorithm + * @see queueAlgorithm */ // eslint-disable-next-line @typescript-eslint/naming-convention public static QUEUE_MESSAGES(event: MatrixEvent): string | null { @@ -116,16 +103,52 @@ export class MatrixScheduler { private activeQueues: string[] = []; private procFn: ProcessFunction | null = null; + /** + * Construct a scheduler for Matrix. Requires + * {@link MatrixScheduler#setProcessFunction} to be provided + * with a way of processing events. + * @param retryAlgorithm - Optional. The retry + * algorithm to apply when determining when to try to send an event again. + * Defaults to {@link MatrixScheduler.RETRY_BACKOFF_RATELIMIT}. + * @param queueAlgorithm - Optional. The queuing + * algorithm to apply when determining which events should be sent before the + * given event. Defaults to {@link MatrixScheduler.QUEUE_MESSAGES}. + */ public constructor( + /** + * The retry algorithm to apply when retrying events. To stop retrying, return + * `-1`. If this event was part of a queue, it will be removed from + * the queue. + * @param event - The event being retried. + * @param attempts - The number of failed attempts. This will always be \>= 1. + * @param err - The most recent error message received when trying + * to send this event. + * @returns The number of milliseconds to wait before trying again. If + * this is 0, the request will be immediately retried. If this is + * `-1`, the event will be marked as + * {@link EventStatus.NOT_SENT} and will not be retried. + */ public readonly retryAlgorithm = MatrixScheduler.RETRY_BACKOFF_RATELIMIT, + /** + * The queuing algorithm to apply to events. This function must be idempotent as + * it may be called multiple times with the same event. All queues created are + * serviced in a FIFO manner. To send the event ASAP, return `null` + * which will not put this event in a queue. Events that fail to send that form + * part of a queue will be removed from the queue and the next event in the + * queue will be sent. + * @param event - The event to be sent. + * @returns The name of the queue to put the event into. If a queue with + * this name does not exist, it will be created. If this is `null`, + * the event is not put into a queue and will be sent concurrently. + */ public readonly queueAlgorithm = MatrixScheduler.QUEUE_MESSAGES, ) {} /** * Retrieve a queue based on an event. The event provided does not need to be in * the queue. - * @param {MatrixEvent} event An event to get the queue for. - * @return {?Array} A shallow copy of events in the queue or null. + * @param event - An event to get the queue for. + * @returns A shallow copy of events in the queue or null. * Modifying this array will not modify the list itself. Modifying events in * this array will modify the underlying event in the queue. * @see MatrixScheduler.removeEventFromQueue To remove an event from the queue. @@ -143,8 +166,8 @@ export class MatrixScheduler { /** * Remove this event from the queue. The event is equal to another event if they * have the same ID returned from event.getId(). - * @param {MatrixEvent} event The event to remove. - * @return {boolean} True if this event was removed. + * @param event - The event to remove. + * @returns True if this event was removed. */ public removeEventFromQueue(event: MatrixEvent): boolean { const name = this.queueAlgorithm(event); @@ -168,7 +191,7 @@ export class MatrixScheduler { * Set the process function. Required for events in the queue to be processed. * If set after events have been added to the queue, this will immediately start * processing them. - * @param {module:scheduler~processFn} fn The function that can process events + * @param fn - The function that can process events * in the queue. */ public setProcessFunction(fn: ProcessFunction): void { @@ -178,8 +201,8 @@ export class MatrixScheduler { /** * Queue an event if it is required and start processing queues. - * @param {MatrixEvent} event The event that may be queued. - * @return {?Promise} A promise if the event was queued, which will be + * @param event - The event that may be queued. + * @returns A promise if the event was queued, which will be * resolved or rejected in due time, else null. */ public queueEvent(event: MatrixEvent): Promise | null { @@ -283,46 +306,9 @@ export class MatrixScheduler { } } +/* istanbul ignore next */ function debuglog(...args: any[]): void { if (DEBUG) { logger.log(...args); } } - -/** - * The retry algorithm to apply when retrying events. To stop retrying, return - * -1. If this event was part of a queue, it will be removed from - * the queue. - * @callback retryAlgorithm - * @param {MatrixEvent} event The event being retried. - * @param {Number} attempts The number of failed attempts. This will always be - * >= 1. - * @param {MatrixError} err The most recent error message received when trying - * to send this event. - * @return {Number} The number of milliseconds to wait before trying again. If - * this is 0, the request will be immediately retried. If this is - * -1, the event will be marked as - * {@link module:models/event.EventStatus.NOT_SENT} and will not be retried. - */ - -/** - * The queuing algorithm to apply to events. This function must be idempotent as - * it may be called multiple times with the same event. All queues created are - * serviced in a FIFO manner. To send the event ASAP, return null - * which will not put this event in a queue. Events that fail to send that form - * part of a queue will be removed from the queue and the next event in the - * queue will be sent. - * @callback queueAlgorithm - * @param {MatrixEvent} event The event to be sent. - * @return {string} The name of the queue to put the event into. If a queue with - * this name does not exist, it will be created. If this is null, - * the event is not put into a queue and will be sent concurrently. - */ - -/** - * The function to invoke to process (send) events in the queue. - * @callback processFn - * @param {MatrixEvent} event The event to send. - * @return {Promise} Resolved/rejected depending on the outcome of the request. - */ - diff --git a/src/sliding-sync-sdk.ts b/src/sliding-sync-sdk.ts index d103eb39b..f9bddd875 100644 --- a/src/sliding-sync-sdk.ts +++ b/src/sliding-sync-sdk.ts @@ -458,7 +458,7 @@ export class SlidingSyncSdk { /** * Sync rooms the user has left. - * @return {Promise} Resolved when they've been added to the store. + * @returns Resolved when they've been added to the store. */ public async syncLeftRooms(): Promise { return []; // TODO @@ -467,8 +467,8 @@ export class SlidingSyncSdk { /** * Peek into a room. This will result in the room in question being synced so it * is accessible via getRooms(). Live updates for the room will be provided. - * @param {string} roomId The room ID to peek into. - * @return {Promise} A promise which resolves once the room has been added to the + * @param roomId - The room ID to peek into. + * @returns A promise which resolves once the room has been added to the * store. */ public async peek(_roomId: string): Promise { @@ -485,8 +485,7 @@ export class SlidingSyncSdk { /** * Returns the current state of this sync object - * @see module:client~MatrixClient#event:"sync" - * @return {?String} + * @see MatrixClient#event:"sync" */ public getSyncState(): SyncState | null { return this.syncState; @@ -498,7 +497,6 @@ export class SlidingSyncSdk { * such data. * Sync errors, if available, are put in the 'error' key of * this object. - * @return {?Object} */ public getSyncStateData(): ISyncStateData | null { return this.syncStateData ?? null; @@ -765,12 +763,11 @@ export class SlidingSyncSdk { /** * Injects events into a room's model. - * @param {Room} room - * @param {MatrixEvent[]} stateEventList A list of state events. This is the state + * @param stateEventList - A list of state events. This is the state * at the *START* of the timeline list if it is supplied. - * @param {MatrixEvent[]} [timelineEventList] A list of timeline events. Lower index + * @param timelineEventList - A list of timeline events. Lower index * is earlier in time. Higher index is later. - * @param {number} numLive the number of events in timelineEventList which just happened, + * @param numLive - the number of events in timelineEventList which just happened, * supplied from the server. */ public injectRoomEvents( @@ -933,8 +930,8 @@ export class SlidingSyncSdk { /** * Sets the sync state and emits an event to say so - * @param {String} newState The new state string - * @param {Object} data Object of additional data to emit in the event + * @param newState - The new state string + * @param data - Object of additional data to emit in the event */ private updateSyncState(newState: SyncState, data?: ISyncStateData): void { const old = this.syncState; @@ -948,7 +945,7 @@ export class SlidingSyncSdk { * as appropriate. * This must be called after the room the events belong to has been stored. * - * @param {MatrixEvent[]} [timelineEventList] A list of timeline events. Lower index + * @param timelineEventList - A list of timeline events. Lower index * is earlier in time. Higher index is later. */ private addNotifications(timelineEventList: MatrixEvent[]): void { diff --git a/src/sliding-sync.ts b/src/sliding-sync.ts index a3daf3af6..81a67f05e 100644 --- a/src/sliding-sync.ts +++ b/src/sliding-sync.ts @@ -156,7 +156,7 @@ export enum SlidingSyncState { /** * Internal Class. SlidingList represents a single list in sliding sync. The list can have filters, - * multiple sliding windows, and maintains the index->room_id mapping. + * multiple sliding windows, and maintains the index-\>room_id mapping. */ class SlidingList { private list!: MSC3575List; @@ -168,7 +168,7 @@ class SlidingList { /** * Construct a new sliding list. - * @param {MSC3575List} list The range, sort and filter values to use for this list. + * @param list - The range, sort and filter values to use for this list. */ public constructor(list: MSC3575List) { this.replaceList(list); @@ -177,7 +177,7 @@ class SlidingList { /** * Mark this list as modified or not. Modified lists will return sticky params with calls to getList. * This is useful for the first time the list is sent, or if the list has changed in some way. - * @param modified True to mark this list as modified so all sticky parameters will be re-sent. + * @param modified - True to mark this list as modified so all sticky parameters will be re-sent. */ public setModified(modified: boolean): void { this.isModified = modified; @@ -185,7 +185,7 @@ class SlidingList { /** * Update the list range for this list. Does not affect modified status as list ranges are non-sticky. - * @param newRanges The new ranges for the list + * @param newRanges - The new ranges for the list */ public updateListRange(newRanges: number[][]): void { this.list.ranges = JSON.parse(JSON.stringify(newRanges)); @@ -193,7 +193,7 @@ class SlidingList { /** * Replace list parameters. All fields will be replaced with the new list parameters. - * @param list The new list parameters + * @param list - The new list parameters */ public replaceList(list: MSC3575List): void { list.filters = list.filters || {}; @@ -213,7 +213,7 @@ class SlidingList { /** * Return a copy of the list suitable for a request body. - * @param {boolean} forceIncludeAllParams True to forcibly include all params even if the list + * @param forceIncludeAllParams - True to forcibly include all params even if the list * hasn't been modified. Callers may want to do this if they are modifying the list prior to calling * updateList. */ @@ -235,7 +235,7 @@ class SlidingList { * a b c d _ f COMMAND: DELETE 7; * e a b c d f COMMAND: INSERT 0 e; * c=3 is wrong as we are not tracking it, ergo we need to see if `i` is in range else drop it - * @param i The index to check + * @param i - The index to check * @returns True if the index is within a sliding window */ public isIndexInRange(i: number): boolean { @@ -274,13 +274,13 @@ export interface Extension { /** * A function which is called when the request JSON is being formed. * Returns the data to insert under this key. - * @param isInitial True when this is part of the initial request (send sticky params) + * @param isInitial - True when this is part of the initial request (send sticky params) * @returns The request JSON to send. */ onRequest(isInitial: boolean): Req | undefined; /** * A function which is called when there is response JSON under this extension. - * @param data The response JSON under the extension name. + * @param data - The response JSON under the extension name. */ onResponse(data: Res): void; /** @@ -368,11 +368,11 @@ export class SlidingSync extends TypedEventEmitter} | null { @@ -435,7 +435,7 @@ export class SlidingSync extends TypedEventEmitter): void { if (this.extensions[ext.name()]) { @@ -552,8 +552,8 @@ export class SlidingSync extends TypedEventEmitter void) => void; - /** @return {Promise} whether or not the database was newly created in this session. */ + /** @returns whether or not the database was newly created in this session. */ isNewlyCreated(): Promise; /** * Get the sync token. - * @return {string} */ getSyncToken(): string | null; /** * Set the sync token. - * @param {string} token */ setSyncToken(token: string): void; /** * Store the given room. - * @param {Room} room The room to be stored. All properties must be stored. + * @param room - The room to be stored. All properties must be stored. */ storeRoom(room: Room): void; /** * Retrieve a room by its' room ID. - * @param {string} roomId The room ID. - * @return {Room} The room or null. + * @param roomId - The room ID. + * @returns The room or null. */ getRoom(roomId: string): Room | null; /** * Retrieve all known rooms. - * @return {Room[]} A list of rooms, which may be empty. + * @returns A list of rooms, which may be empty. */ getRooms(): Room[]; /** * Permanently delete a room. - * @param {string} roomId */ removeRoom(roomId: string): void; /** * Retrieve a summary of all the rooms. - * @return {RoomSummary[]} A summary of each room. + * @returns A summary of each room. */ getRoomSummaries(): RoomSummary[]; /** * Store a User. - * @param {User} user The user to store. + * @param user - The user to store. */ storeUser(user: User): void; /** * Retrieve a User by its' user ID. - * @param {string} userId The user ID. - * @return {User} The user or null. + * @param userId - The user ID. + * @returns The user or null. */ getUser(userId: string): User | null; /** * Retrieve all known users. - * @return {User[]} A list of users, which may be empty. + * @returns A list of users, which may be empty. */ getUsers(): User[]; /** * Retrieve scrollback for this room. - * @param {Room} room The matrix room - * @param {number} limit The max number of old events to retrieve. - * @return {Array} An array of objects which will be at most 'limit' + * @param room - The matrix room + * @param limit - The max number of old events to retrieve. + * @returns An array of objects which will be at most 'limit' * length and at least 0. The objects are the raw event JSON. */ scrollback(room: Room, limit: number): MatrixEvent[]; /** * Store events for a room. - * @param {Room} room The room to store events for. - * @param {Array} events The events to store. - * @param {string} token The token associated with these events. - * @param {boolean} toStart True if these are paginated results. + * @param room - The room to store events for. + * @param events - The events to store. + * @param token - The token associated with these events. + * @param toStart - True if these are paginated results. */ storeEvents(room: Room, events: MatrixEvent[], token: string | null, toStart: boolean): void; /** * Store a filter. - * @param {Filter} filter */ storeFilter(filter: Filter): void; /** * Retrieve a filter. - * @param {string} userId - * @param {string} filterId - * @return {?Filter} A filter or null. + * @returns A filter or null. */ getFilter(userId: string, filterId: string): Filter | null; /** * Retrieve a filter ID with the given name. - * @param {string} filterName The filter name. - * @return {?string} The filter ID or null. + * @param filterName - The filter name. + * @returns The filter ID or null. */ getFilterIdByName(filterName: string): string | null; /** * Set a filter name to ID mapping. - * @param {string} filterName - * @param {string} filterId */ setFilterIdByName(filterName: string, filterId?: string): void; /** * Store user-scoped account data events - * @param {Array} events The events to store. + * @param events - The events to store. */ storeAccountDataEvents(events: MatrixEvent[]): void; /** * Get account data event by event type - * @param {string} eventType The event type being queried + * @param eventType - The event type being queried */ getAccountData(eventType: EventType | string): MatrixEvent | undefined; /** * setSyncData does nothing as there is no backing data store. * - * @param {Object} syncData The sync data - * @return {Promise} An immediately resolved promise. + * @param syncData - The sync data + * @returns An immediately resolved promise. */ setSyncData(syncData: ISyncResponse): Promise; /** * We never want to save because we have nothing to save to. * - * @return {boolean} If the store wants to save + * @returns If the store wants to save */ wantsSave(): boolean; @@ -187,19 +179,19 @@ export interface IStore { /** * Startup does nothing. - * @return {Promise} An immediately resolved promise. + * @returns An immediately resolved promise. */ startup(): Promise; /** - * @return {Promise} Resolves with a sync response to restore the + * @returns Promise which resolves with a sync response to restore the * client state to where it was at the last save, or null if there * is no saved sync data. */ getSavedSync(): Promise; /** - * @return {Promise} If there is a saved sync, the nextBatch token + * @returns If there is a saved sync, the nextBatch token * for this sync, otherwise null. */ getSavedSyncToken(): Promise; @@ -207,16 +199,15 @@ export interface IStore { /** * Delete all data from this store. Does nothing since this store * doesn't store anything. - * @return {Promise} An immediately resolved promise. + * @returns An immediately resolved promise. */ deleteAllData(): Promise; /** * Returns the out-of-band membership events for this room that * were previously loaded. - * @param {string} roomId - * @returns {event[]} the events, potentially an empty array if OOB loading didn't yield any new members - * @returns {null} in case the members for this room haven't been stored yet + * @returns the events, potentially an empty array if OOB loading didn't yield any new members + * @returns in case the members for this room haven't been stored yet */ getOutOfBandMembers(roomId: string): Promise; @@ -224,9 +215,8 @@ export interface IStore { * Stores the out-of-band membership events for this room. Note that * it still makes sense to store an empty array as the OOB status for the room is * marked as fetched, and getOutOfBandMembers will return an empty array instead of null - * @param {string} roomId - * @param {event[]} membershipEvents the membership events to store - * @returns {Promise} when all members have been stored + * @param membershipEvents - the membership events to store + * @returns when all members have been stored */ setOutOfBandMembers(roomId: string, membershipEvents: IStateEventWithRoomId[]): Promise; diff --git a/src/store/indexeddb-local-backend.ts b/src/store/indexeddb-local-backend.ts index 2b94af256..fe61f11df 100644 --- a/src/store/indexeddb-local-backend.ts +++ b/src/store/indexeddb-local-backend.ts @@ -51,12 +51,12 @@ const VERSION = DB_MIGRATIONS.length; /** * Helper method to collect results from a Cursor and promiseify it. - * @param {ObjectStore|Index} store The store to perform openCursor on. - * @param {IDBKeyRange=} keyRange Optional key range to apply on the cursor. - * @param {Function} resultMapper A function which is repeatedly called with a + * @param store - The store to perform openCursor on. + * @param keyRange - Optional key range to apply on the cursor. + * @param resultMapper - A function which is repeatedly called with a * Cursor. * Return the data you want to keep. - * @return {Promise} Resolves to an array of whatever you returned from + * @returns Promise which resolves to an array of whatever you returned from * resultMapper. */ function selectQuery( @@ -134,11 +134,10 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { * Does the actual reading from and writing to the indexeddb * * Construct a new Indexed Database store backend. This requires a call to - * connect() before this store can be used. - * @constructor - * @param {Object} indexedDB The Indexed DB interface e.g - * window.indexedDB - * @param {string=} dbName Optional database name. The same name must be used + * `connect()` before this store can be used. + * @param indexedDB - The Indexed DB interface e.g + * `window.indexedDB` + * @param dbName - Optional database name. The same name must be used * to open the same database. */ public constructor(private readonly indexedDB: IDBFactory, dbName = "default") { @@ -149,7 +148,7 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { /** * Attempt to connect to the database. This can fail if the user does not * grant permission. - * @return {Promise} Resolves if successfully connected. + * @returns Promise which resolves if successfully connected. */ public connect(): Promise { if (!this.disconnected) { @@ -195,14 +194,14 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { }); } - /** @return {boolean} whether or not the database was newly created in this session. */ + /** @returns whether or not the database was newly created in this session. */ public isNewlyCreated(): Promise { return Promise.resolve(this._isNewlyCreated); } /** * Having connected, load initial data from the database and prepare for use - * @return {Promise} Resolves on success + * @returns Promise which resolves on success */ private init(): Promise { return Promise.all([ @@ -223,9 +222,8 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { /** * Returns the out-of-band membership events for this room that * were previously loaded. - * @param {string} roomId - * @returns {Promise} the events, potentially an empty array if OOB loading didn't yield any new members - * @returns {null} in case the members for this room haven't been stored yet + * @returns the events, potentially an empty array if OOB loading didn't yield any new members + * @returns in case the members for this room haven't been stored yet */ public getOutOfBandMembers(roomId: string): Promise { return new Promise((resolve, reject) => { @@ -273,8 +271,7 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { * Stores the out-of-band membership events for this room. Note that * it still makes sense to store an empty array as the OOB status for the room is * marked as fetched, and getOutOfBandMembers will return an empty array instead of null - * @param {string} roomId - * @param {event[]} membershipEvents the membership events to store + * @param membershipEvents - the membership events to store */ public async setOutOfBandMembers(roomId: string, membershipEvents: IStateEventWithRoomId[]): Promise { logger.log(`LL: backend about to store ${membershipEvents.length}` + @@ -339,7 +336,7 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { /** * Clear the entire database. This should be used when logging out of a client * to prevent mixing data between accounts. - * @return {Promise} Resolved when the database is cleared. + * @returns Resolved when the database is cleared. */ public clearDatabase(): Promise { return new Promise((resolve) => { @@ -366,11 +363,11 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { } /** - * @param {boolean=} copy If false, the data returned is from internal + * @param copy - If false, the data returned is from internal * buffers and must not be mutated. Otherwise, a copy is made before * returning such that the data can be safely mutated. Default: true. * - * @return {Promise} Resolves with a sync response to restore the + * @returns Promise which resolves with a sync response to restore the * client state to where it was at the last save, or null if there * is no saved sync data. */ @@ -421,9 +418,9 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { /** * Persist rooms /sync data along with the next batch token. - * @param {string} nextBatch The next_batch /sync value. - * @param {Object} roomsData The 'rooms' /sync data from a SyncAccumulator - * @return {Promise} Resolves if the data was persisted. + * @param nextBatch - The next_batch /sync value. + * @param roomsData - The 'rooms' /sync data from a SyncAccumulator + * @returns Promise which resolves if the data was persisted. */ private persistSyncData( nextBatch: string, @@ -447,8 +444,8 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { /** * Persist a list of account data events. Events with the same 'type' will * be replaced. - * @param {Object[]} accountData An array of raw user-scoped account data events - * @return {Promise} Resolves if the events were persisted. + * @param accountData - An array of raw user-scoped account data events + * @returns Promise which resolves if the events were persisted. */ private persistAccountData(accountData: IMinimalEvent[]): Promise { return utils.promiseTry(() => { @@ -466,8 +463,8 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { * Users with the same 'userId' will be replaced. * Presence events should be the event in its raw form (not the Event * object) - * @param {Object[]} tuples An array of [userid, event] tuples - * @return {Promise} Resolves if the users were persisted. + * @param tuples - An array of [userid, event] tuples + * @returns Promise which resolves if the users were persisted. */ private persistUserPresenceEvents(tuples: UserTuple[]): Promise { return utils.promiseTry(() => { @@ -487,7 +484,7 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { * Load all user presence events from the database. This is not cached. * FIXME: It would probably be more sensible to store the events in the * sync. - * @return {Promise} A list of presence events in their raw form. + * @returns A list of presence events in their raw form. */ public getUserPresenceEvents(): Promise { return utils.promiseTry(() => { @@ -501,7 +498,7 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { /** * Load all the account data events from the database. This is not cached. - * @return {Promise} A list of raw global account events. + * @returns A list of raw global account events. */ private loadAccountData(): Promise { logger.log(`LocalIndexedDBStoreBackend: loading account data...`); @@ -519,7 +516,7 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { /** * Load the sync data from the database. - * @return {Promise} An object with "roomsData" and "nextBatch" keys. + * @returns An object with "roomsData" and "nextBatch" keys. */ private loadSyncData(): Promise { logger.log(`LocalIndexedDBStoreBackend: loading sync data...`); diff --git a/src/store/indexeddb-remote-backend.ts b/src/store/indexeddb-remote-backend.ts index 1ca6fc03a..05909b0e3 100644 --- a/src/store/indexeddb-remote-backend.ts +++ b/src/store/indexeddb-remote-backend.ts @@ -36,10 +36,9 @@ export class RemoteIndexedDBStoreBackend implements IIndexedDBBackend { * worker. * * Construct a new Indexed Database store backend. This requires a call to - * connect() before this store can be used. - * @constructor - * @param {Function} workerFactory Factory which produces a Worker - * @param {string=} dbName Optional database name. The same name must be used + * `connect()` before this store can be used. + * @param workerFactory - Factory which produces a Worker + * @param dbName - Optional database name. The same name must be used * to open the same database. */ public constructor( @@ -50,7 +49,7 @@ export class RemoteIndexedDBStoreBackend implements IIndexedDBBackend { /** * Attempt to connect to the database. This can fail if the user does not * grant permission. - * @return {Promise} Resolves if successfully connected. + * @returns Promise which resolves if successfully connected. */ public connect(): Promise { return this.ensureStarted().then(() => this.doCmd('connect')); @@ -59,19 +58,19 @@ export class RemoteIndexedDBStoreBackend implements IIndexedDBBackend { /** * Clear the entire database. This should be used when logging out of a client * to prevent mixing data between accounts. - * @return {Promise} Resolved when the database is cleared. + * @returns Resolved when the database is cleared. */ public clearDatabase(): Promise { return this.ensureStarted().then(() => this.doCmd('clearDatabase')); } - /** @return {Promise} whether or not the database was newly created in this session. */ + /** @returns whether or not the database was newly created in this session. */ public isNewlyCreated(): Promise { return this.doCmd('isNewlyCreated'); } /** - * @return {Promise} Resolves with a sync response to restore the + * @returns Promise which resolves with a sync response to restore the * client state to where it was at the last save, or null if there * is no saved sync data. */ @@ -94,9 +93,8 @@ export class RemoteIndexedDBStoreBackend implements IIndexedDBBackend { /** * Returns the out-of-band membership events for this room that * were previously loaded. - * @param {string} roomId - * @returns {event[]} the events, potentially an empty array if OOB loading didn't yield any new members - * @returns {null} in case the members for this room haven't been stored yet + * @returns the events, potentially an empty array if OOB loading didn't yield any new members + * @returns in case the members for this room haven't been stored yet */ public getOutOfBandMembers(roomId: string): Promise { return this.doCmd('getOutOfBandMembers', [roomId]); @@ -106,9 +104,8 @@ export class RemoteIndexedDBStoreBackend implements IIndexedDBBackend { * Stores the out-of-band membership events for this room. Note that * it still makes sense to store an empty array as the OOB status for the room is * marked as fetched, and getOutOfBandMembers will return an empty array instead of null - * @param {string} roomId - * @param {event[]} membershipEvents the membership events to store - * @returns {Promise} when all members have been stored + * @param membershipEvents - the membership events to store + * @returns when all members have been stored */ public setOutOfBandMembers(roomId: string, membershipEvents: IStateEventWithRoomId[]): Promise { return this.doCmd('setOutOfBandMembers', [roomId, membershipEvents]); @@ -128,7 +125,7 @@ export class RemoteIndexedDBStoreBackend implements IIndexedDBBackend { /** * Load all user presence events from the database. This is not cached. - * @return {Promise} A list of presence events in their raw form. + * @returns A list of presence events in their raw form. */ public getUserPresenceEvents(): Promise { return this.doCmd('getUserPresenceEvents'); diff --git a/src/store/indexeddb-store-worker.ts b/src/store/indexeddb-store-worker.ts index 57e7da983..a9bc2abcd 100644 --- a/src/store/indexeddb-store-worker.ts +++ b/src/store/indexeddb-store-worker.ts @@ -27,12 +27,14 @@ interface ICmd { * This class lives in the webworker and drives a LocalIndexedDBStoreBackend * controlled by messages from the main process. * + * @example * It should be instantiated by a web worker script provided by the application * in a script, for example: - * + * ``` * import {IndexedDBStoreWorker} from 'matrix-js-sdk/lib/indexeddb-worker.js'; * const remoteWorker = new IndexedDBStoreWorker(postMessage); * onmessage = remoteWorker.onMessage; + * ``` * * Note that it is advisable to import this class by referencing the file directly to * avoid a dependency on the whole js-sdk. @@ -42,7 +44,7 @@ export class IndexedDBStoreWorker { private backend?: LocalIndexedDBStoreBackend; /** - * @param {function} postMessage The web worker postMessage function that + * @param postMessage - The web worker postMessage function that * should be used to communicate back to the main script. */ public constructor(private readonly postMessage: InstanceType["postMessage"]) {} @@ -51,7 +53,7 @@ export class IndexedDBStoreWorker { * Passes a message event from the main script into the class. This method * can be directly assigned to the web worker `onmessage` variable. * - * @param {Object} ev The message event + * @param ev - The message event */ public onMessage = (ev: MessageEvent): void => { const msg: ICmd = ev.data; diff --git a/src/store/indexeddb.ts b/src/store/indexeddb.ts index 55f8261fa..656049f2b 100644 --- a/src/store/indexeddb.ts +++ b/src/store/indexeddb.ts @@ -32,7 +32,6 @@ import { IStoredClientOpts } from "../client"; /** * This is an internal module. See {@link IndexedDBStore} for the public class. - * @module store/indexeddb */ // If this value is too small we'll be writing very often which will cause @@ -43,8 +42,11 @@ import { IStoredClientOpts } from "../client"; const WRITE_DELAY_MS = 1000 * 60 * 5; // once every 5 minutes interface IOpts extends IBaseOpts { + /** The Indexed DB interface e.g. `window.indexedDB` */ indexedDB: IDBFactory; + /** Optional database name. The same name must be used to open the same database. */ dbName?: string; + /** Optional factory to spin up a Worker to execute the IDB transactions within. */ workerFactory?: () => Worker; } @@ -57,6 +59,10 @@ export class IndexedDBStore extends MemoryStore { return LocalIndexedDBStoreBackend.exists(indexedDB, dbName); } + /** + * The backend instance. + * Call through to this API if you need to perform specific indexeddb actions like deleting the database. + */ public readonly backend: IIndexedDBBackend; private startedUp = false; @@ -74,10 +80,10 @@ export class IndexedDBStore extends MemoryStore { * the contents of the store to an IndexedDB backend. * * All data is still kept in-memory but can be loaded from disk by calling - * startup(). This can make startup times quicker as a complete + * `startup()`. This can make startup times quicker as a complete * sync from the server is not required. This does not reduce memory usage as all - * the data is eagerly fetched when startup() is called. - *
+     * the data is eagerly fetched when `startup()` is called.
+     * ```
      * let opts = { indexedDB: window.indexedDB, localStorage: window.localStorage };
      * let store = new IndexedDBStore(opts);
      * await store.startup(); // load from indexed db
@@ -90,24 +96,9 @@ export class IndexedDBStore extends MemoryStore {
      *         console.log("Started up, now with go faster stripes!");
      *     }
      * });
-     * 
+ * ``` * - * @constructor - * @extends MemoryStore - * @param {Object} opts Options object. - * @param {Object} opts.indexedDB The Indexed DB interface e.g. - * window.indexedDB - * @param {string=} opts.dbName Optional database name. The same name must be used - * to open the same database. - * @param {string=} opts.workerScript Optional URL to a script to invoke a web - * worker with to run IndexedDB queries on the web worker. The IndexedDbStoreWorker - * class is provided for this purpose and requires the application to provide a - * trivial wrapper script around it. - * @param {Object=} opts.workerApi The webWorker API object. If omitted, the global Worker - * object will be used if it exists. - * @prop {IndexedDBStoreBackend} backend The backend instance. Call through to - * this API if you need to perform specific indexeddb actions like deleting the - * database. + * @param opts - Options object. */ public constructor(opts: IOpts) { super(opts); @@ -126,7 +117,7 @@ export class IndexedDBStore extends MemoryStore { public on = this.emitter.on.bind(this.emitter); /** - * @return {Promise} Resolved when loaded from indexed db. + * @returns Resolved when loaded from indexed db. */ public startup(): Promise { if (this.startedUp) { @@ -152,7 +143,7 @@ export class IndexedDBStore extends MemoryStore { } /** - * @return {Promise} Resolves with a sync response to restore the + * @returns Promise which resolves with a sync response to restore the * client state to where it was at the last save, or null if there * is no saved sync data. */ @@ -160,13 +151,13 @@ export class IndexedDBStore extends MemoryStore { return this.backend.getSavedSync(); }, "getSavedSync"); - /** @return {Promise} whether or not the database was newly created in this session. */ + /** @returns whether or not the database was newly created in this session. */ public isNewlyCreated = this.degradable((): Promise => { return this.backend.isNewlyCreated(); }, "isNewlyCreated"); /** - * @return {Promise} If there is a saved sync, the nextBatch token + * @returns If there is a saved sync, the nextBatch token * for this sync, otherwise null. */ public getSavedSyncToken = this.degradable((): Promise => { @@ -175,7 +166,7 @@ export class IndexedDBStore extends MemoryStore { /** * Delete all data from this store. - * @return {Promise} Resolves if the data was deleted from the database. + * @returns Promise which resolves if the data was deleted from the database. */ public deleteAllData = this.degradable((): Promise => { super.deleteAllData(); @@ -193,7 +184,7 @@ export class IndexedDBStore extends MemoryStore { * not could change between calling this function and calling * save(). * - * @return {boolean} True if calling save() will actually save + * @returns True if calling save() will actually save * (at the time this function is called). */ public wantsSave(): boolean { @@ -204,8 +195,8 @@ export class IndexedDBStore extends MemoryStore { /** * Possibly write data to the database. * - * @param {boolean} force True to force a save to happen - * @return {Promise} Promise resolves after the write completes + * @param force - True to force a save to happen + * @returns Promise resolves after the write completes * (or immediately if no write is performed) */ public save(force = false): Promise { @@ -241,9 +232,8 @@ export class IndexedDBStore extends MemoryStore { /** * Returns the out-of-band membership events for this room that * were previously loaded. - * @param {string} roomId - * @returns {event[]} the events, potentially an empty array if OOB loading didn't yield any new members - * @returns {null} in case the members for this room haven't been stored yet + * @returns the events, potentially an empty array if OOB loading didn't yield any new members + * @returns in case the members for this room haven't been stored yet */ public getOutOfBandMembers = this.degradable((roomId: string): Promise => { return this.backend.getOutOfBandMembers(roomId); @@ -253,9 +243,8 @@ export class IndexedDBStore extends MemoryStore { * Stores the out-of-band membership events for this room. Note that * it still makes sense to store an empty array as the OOB status for the room is * marked as fetched, and getOutOfBandMembers will return an empty array instead of null - * @param {string} roomId - * @param {event[]} membershipEvents the membership events to store - * @returns {Promise} when all members have been stored + * @param membershipEvents - the membership events to store + * @returns when all members have been stored */ public setOutOfBandMembers = this.degradable( (roomId: string, membershipEvents: IStateEventWithRoomId[]): Promise => { @@ -287,9 +276,9 @@ export class IndexedDBStore extends MemoryStore { * When IndexedDB fails via any of these paths, we degrade this back to a `MemoryStore` * in place so that the current operation and all future ones are in-memory only. * - * @param {Function} func The degradable work to do. - * @param {String} fallback The method name for fallback. - * @returns {Function} A wrapped member function. + * @param func - The degradable work to do. + * @param fallback - The method name for fallback. + * @returns A wrapped member function. */ private degradable, R = void>( func: DegradableFn, @@ -368,8 +357,8 @@ export class IndexedDBStore extends MemoryStore { } /** - * @param {string} roomId ID of the current room - * @returns {string} Storage key to retrieve pending events + * @param roomId - ID of the current room + * @returns Storage key to retrieve pending events */ function pendingEventsKey(roomId: string): string { return `mx_pending_events_${roomId}`; diff --git a/src/store/memory.ts b/src/store/memory.ts index 1fcb6b0c8..c698b9395 100644 --- a/src/store/memory.ts +++ b/src/store/memory.ts @@ -16,7 +16,6 @@ limitations under the License. /** * This is an internal module. See {@link MemoryStore} for the public class. - * @module store/memory */ import { EventType } from "../@types/event"; @@ -43,16 +42,10 @@ function isValidFilterId(filterId?: string | number | null): boolean { } export interface IOpts { + /** The local storage instance to persist some forms of data such as tokens. Rooms will NOT be stored. */ localStorage?: Storage; } -/** - * Construct a new in-memory data store for the Matrix Client. - * @constructor - * @param {Object=} opts Config options - * @param {Storage} opts.localStorage The local storage instance to persist - * some forms of data such as tokens. Rooms will NOT be stored. - */ export class MemoryStore implements IStore { private rooms: Record = {}; // roomId: Room private users: Record = {}; // userId: User @@ -69,26 +62,30 @@ export class MemoryStore implements IStore { private pendingToDeviceBatches: IndexedToDeviceBatch[] = []; private nextToDeviceBatchId = 0; + /** + * Construct a new in-memory data store for the Matrix Client. + * @param opts - Config options + */ public constructor(opts: IOpts = {}) { this.localStorage = opts.localStorage; } /** * Retrieve the token to stream from. - * @return {string} The token or null. + * @returns The token or null. */ public getSyncToken(): string | null { return this.syncToken; } - /** @return {Promise} whether or not the database was newly created in this session. */ + /** @returns whether or not the database was newly created in this session. */ public isNewlyCreated(): Promise { return Promise.resolve(true); } /** * Set the token to stream from. - * @param {string} token The token to stream from. + * @param token - The token to stream from. */ public setSyncToken(token: string): void { this.syncToken = token; @@ -96,7 +93,7 @@ export class MemoryStore implements IStore { /** * Store the given room. - * @param {Room} room The room to be stored. All properties must be stored. + * @param room - The room to be stored. All properties must be stored. */ public storeRoom(room: Room): void { this.rooms[room.roomId] = room; @@ -112,9 +109,6 @@ export class MemoryStore implements IStore { /** * Called when a room member in a room being tracked by this store has been * updated. - * @param {MatrixEvent} event - * @param {RoomState} state - * @param {RoomMember} member */ private onRoomMember = (event: MatrixEvent | null, state: RoomState, member: RoomMember): void => { if (member.membership === "invite") { @@ -138,8 +132,8 @@ export class MemoryStore implements IStore { /** * Retrieve a room by its' room ID. - * @param {string} roomId The room ID. - * @return {Room} The room or null. + * @param roomId - The room ID. + * @returns The room or null. */ public getRoom(roomId: string): Room | null { return this.rooms[roomId] || null; @@ -147,7 +141,7 @@ export class MemoryStore implements IStore { /** * Retrieve all known rooms. - * @return {Room[]} A list of rooms, which may be empty. + * @returns A list of rooms, which may be empty. */ public getRooms(): Room[] { return Object.values(this.rooms); @@ -155,7 +149,6 @@ export class MemoryStore implements IStore { /** * Permanently delete a room. - * @param {string} roomId */ public removeRoom(roomId: string): void { if (this.rooms[roomId]) { @@ -166,7 +159,7 @@ export class MemoryStore implements IStore { /** * Retrieve a summary of all the rooms. - * @return {RoomSummary[]} A summary of each room. + * @returns A summary of each room. */ public getRoomSummaries(): RoomSummary[] { return Object.values(this.rooms).map(function(room) { @@ -176,7 +169,7 @@ export class MemoryStore implements IStore { /** * Store a User. - * @param {User} user The user to store. + * @param user - The user to store. */ public storeUser(user: User): void { this.users[user.userId] = user; @@ -184,8 +177,8 @@ export class MemoryStore implements IStore { /** * Retrieve a User by its' user ID. - * @param {string} userId The user ID. - * @return {User} The user or null. + * @param userId - The user ID. + * @returns The user or null. */ public getUser(userId: string): User | null { return this.users[userId] || null; @@ -193,7 +186,7 @@ export class MemoryStore implements IStore { /** * Retrieve all known users. - * @return {User[]} A list of users, which may be empty. + * @returns A list of users, which may be empty. */ public getUsers(): User[] { return Object.values(this.users); @@ -201,9 +194,9 @@ export class MemoryStore implements IStore { /** * Retrieve scrollback for this room. - * @param {Room} room The matrix room - * @param {number} limit The max number of old events to retrieve. - * @return {Array} An array of objects which will be at most 'limit' + * @param room - The matrix room + * @param limit - The max number of old events to retrieve. + * @returns An array of objects which will be at most 'limit' * length and at least 0. The objects are the raw event JSON. */ public scrollback(room: Room, limit: number): MatrixEvent[] { @@ -212,10 +205,10 @@ export class MemoryStore implements IStore { /** * Store events for a room. The events have already been added to the timeline - * @param {Room} room The room to store events for. - * @param {Array} events The events to store. - * @param {string} token The token associated with these events. - * @param {boolean} toStart True if these are paginated results. + * @param room - The room to store events for. + * @param events - The events to store. + * @param token - The token associated with these events. + * @param toStart - True if these are paginated results. */ public storeEvents(room: Room, events: MatrixEvent[], token: string | null, toStart: boolean): void { // no-op because they've already been added to the room instance. @@ -223,7 +216,6 @@ export class MemoryStore implements IStore { /** * Store a filter. - * @param {Filter} filter */ public storeFilter(filter: Filter): void { if (!filter?.userId || !filter?.filterId) return; @@ -235,9 +227,7 @@ export class MemoryStore implements IStore { /** * Retrieve a filter. - * @param {string} userId - * @param {string} filterId - * @return {?Filter} A filter or null. + * @returns A filter or null. */ public getFilter(userId: string, filterId: string): Filter | null { if (!this.filters[userId] || !this.filters[userId][filterId]) { @@ -248,8 +238,8 @@ export class MemoryStore implements IStore { /** * Retrieve a filter ID with the given name. - * @param {string} filterName The filter name. - * @return {?string} The filter ID or null. + * @param filterName - The filter name. + * @returns The filter ID or null. */ public getFilterIdByName(filterName: string): string | null { if (!this.localStorage) { @@ -272,8 +262,6 @@ export class MemoryStore implements IStore { /** * Set a filter name to ID mapping. - * @param {string} filterName - * @param {string} filterId */ public setFilterIdByName(filterName: string, filterId?: string): void { if (!this.localStorage) { @@ -293,7 +281,7 @@ export class MemoryStore implements IStore { * Store user-scoped account data events. * N.B. that account data only allows a single event per type, so multiple * events with the same type will replace each other. - * @param {Array} events The events to store. + * @param events - The events to store. */ public storeAccountDataEvents(events: MatrixEvent[]): void { events.forEach((event) => { @@ -303,8 +291,8 @@ export class MemoryStore implements IStore { /** * Get account data event by event type - * @param {string} eventType The event type being queried - * @return {?MatrixEvent} the user account_data event of given type, if any + * @param eventType - The event type being queried + * @returns the user account_data event of given type, if any */ public getAccountData(eventType: EventType | string): MatrixEvent | undefined { return this.accountData[eventType]; @@ -313,8 +301,8 @@ export class MemoryStore implements IStore { /** * setSyncData does nothing as there is no backing data store. * - * @param {Object} syncData The sync data - * @return {Promise} An immediately resolved promise. + * @param syncData - The sync data + * @returns An immediately resolved promise. */ public setSyncData(syncData: ISyncResponse): Promise { return Promise.resolve(); @@ -323,7 +311,7 @@ export class MemoryStore implements IStore { /** * We never want to save becase we have nothing to save to. * - * @return {boolean} If the store wants to save + * @returns If the store wants to save */ public wantsSave(): boolean { return false; @@ -331,21 +319,21 @@ export class MemoryStore implements IStore { /** * Save does nothing as there is no backing data store. - * @param {bool} force True to force a save (but the memory + * @param force - True to force a save (but the memory * store still can't save anything) */ public save(force: boolean): void {} /** * Startup does nothing as this store doesn't require starting up. - * @return {Promise} An immediately resolved promise. + * @returns An immediately resolved promise. */ public startup(): Promise { return Promise.resolve(); } /** - * @return {Promise} Resolves with a sync response to restore the + * @returns Promise which resolves with a sync response to restore the * client state to where it was at the last save, or null if there * is no saved sync data. */ @@ -354,7 +342,7 @@ export class MemoryStore implements IStore { } /** - * @return {Promise} If there is a saved sync, the nextBatch token + * @returns If there is a saved sync, the nextBatch token * for this sync, otherwise null. */ public getSavedSyncToken(): Promise { @@ -363,7 +351,7 @@ export class MemoryStore implements IStore { /** * Delete all data from this store. - * @return {Promise} An immediately resolved promise. + * @returns An immediately resolved promise. */ public deleteAllData(): Promise { this.rooms = { @@ -387,9 +375,8 @@ export class MemoryStore implements IStore { /** * Returns the out-of-band membership events for this room that * were previously loaded. - * @param {string} roomId - * @returns {event[]} the events, potentially an empty array if OOB loading didn't yield any new members - * @returns {null} in case the members for this room haven't been stored yet + * @returns the events, potentially an empty array if OOB loading didn't yield any new members + * @returns in case the members for this room haven't been stored yet */ public getOutOfBandMembers(roomId: string): Promise { return Promise.resolve(this.oobMembers[roomId] || null); @@ -399,9 +386,8 @@ export class MemoryStore implements IStore { * Stores the out-of-band membership events for this room. Note that * it still makes sense to store an empty array as the OOB status for the room is * marked as fetched, and getOutOfBandMembers will return an empty array instead of null - * @param {string} roomId - * @param {event[]} membershipEvents the membership events to store - * @returns {Promise} when all members have been stored + * @param membershipEvents - the membership events to store + * @returns when all members have been stored */ public setOutOfBandMembers(roomId: string, membershipEvents: IStateEventWithRoomId[]): Promise { this.oobMembers[roomId] = membershipEvents; diff --git a/src/store/stub.ts b/src/store/stub.ts index 742343938..445f9e8ff 100644 --- a/src/store/stub.ts +++ b/src/store/stub.ts @@ -16,7 +16,6 @@ limitations under the License. /** * This is an internal module. - * @module store/stub */ import { EventType } from "../@types/event"; @@ -33,20 +32,18 @@ import { IStoredClientOpts } from "../client"; /** * Construct a stub store. This does no-ops on most store methods. - * @constructor */ export class StubStore implements IStore { public readonly accountData = {}; // stub private fromToken: string | null = null; - /** @return {Promise} whether or not the database was newly created in this session. */ + /** @returns whether or not the database was newly created in this session. */ public isNewlyCreated(): Promise { return Promise.resolve(true); } /** * Get the sync token. - * @return {string} */ public getSyncToken(): string | null { return this.fromToken; @@ -54,7 +51,6 @@ export class StubStore implements IStore { /** * Set the sync token. - * @param {string} token */ public setSyncToken(token: string): void { this.fromToken = token; @@ -62,14 +58,11 @@ export class StubStore implements IStore { /** * No-op. - * @param {Room} room */ public storeRoom(room: Room): void {} /** * No-op. - * @param {string} roomId - * @return {null} */ public getRoom(roomId: string): Room | null { return null; @@ -77,7 +70,7 @@ export class StubStore implements IStore { /** * No-op. - * @return {Array} An empty array. + * @returns An empty array. */ public getRooms(): Room[] { return []; @@ -85,7 +78,6 @@ export class StubStore implements IStore { /** * Permanently delete a room. - * @param {string} roomId */ public removeRoom(roomId: string): void { return; @@ -93,7 +85,7 @@ export class StubStore implements IStore { /** * No-op. - * @return {Array} An empty array. + * @returns An empty array. */ public getRoomSummaries(): RoomSummary[] { return []; @@ -101,14 +93,11 @@ export class StubStore implements IStore { /** * No-op. - * @param {User} user */ public storeUser(user: User): void {} /** * No-op. - * @param {string} userId - * @return {null} */ public getUser(userId: string): User | null { return null; @@ -116,7 +105,6 @@ export class StubStore implements IStore { /** * No-op. - * @return {User[]} */ public getUsers(): User[] { return []; @@ -124,9 +112,6 @@ export class StubStore implements IStore { /** * No-op. - * @param {Room} room - * @param {number} limit - * @return {Array} */ public scrollback(room: Room, limit: number): MatrixEvent[] { return []; @@ -134,24 +119,21 @@ export class StubStore implements IStore { /** * Store events for a room. - * @param {Room} room The room to store events for. - * @param {Array} events The events to store. - * @param {string} token The token associated with these events. - * @param {boolean} toStart True if these are paginated results. + * @param room - The room to store events for. + * @param events - The events to store. + * @param token - The token associated with these events. + * @param toStart - True if these are paginated results. */ public storeEvents(room: Room, events: MatrixEvent[], token: string | null, toStart: boolean): void {} /** * Store a filter. - * @param {Filter} filter */ public storeFilter(filter: Filter): void {} /** * Retrieve a filter. - * @param {string} userId - * @param {string} filterId - * @return {?Filter} A filter or null. + * @returns A filter or null. */ public getFilter(userId: string, filterId: string): Filter | null { return null; @@ -159,8 +141,8 @@ export class StubStore implements IStore { /** * Retrieve a filter ID with the given name. - * @param {string} filterName The filter name. - * @return {?string} The filter ID or null. + * @param filterName - The filter name. + * @returns The filter ID or null. */ public getFilterIdByName(filterName: string): string | null { return null; @@ -168,20 +150,18 @@ export class StubStore implements IStore { /** * Set a filter name to ID mapping. - * @param {string} filterName - * @param {string} filterId */ public setFilterIdByName(filterName: string, filterId?: string): void {} /** * Store user-scoped account data events - * @param {Array} events The events to store. + * @param events - The events to store. */ public storeAccountDataEvents(events: MatrixEvent[]): void {} /** * Get account data event by event type - * @param {string} eventType The event type being queried + * @param eventType - The event type being queried */ public getAccountData(eventType: EventType | string): MatrixEvent | undefined { return undefined; @@ -190,8 +170,8 @@ export class StubStore implements IStore { /** * setSyncData does nothing as there is no backing data store. * - * @param {Object} syncData The sync data - * @return {Promise} An immediately resolved promise. + * @param syncData - The sync data + * @returns An immediately resolved promise. */ public setSyncData(syncData: ISyncResponse): Promise { return Promise.resolve(); @@ -200,7 +180,7 @@ export class StubStore implements IStore { /** * We never want to save because we have nothing to save to. * - * @return {boolean} If the store wants to save + * @returns If the store wants to save */ public wantsSave(): boolean { return false; @@ -213,14 +193,14 @@ export class StubStore implements IStore { /** * Startup does nothing. - * @return {Promise} An immediately resolved promise. + * @returns An immediately resolved promise. */ public startup(): Promise { return Promise.resolve(); } /** - * @return {Promise} Resolves with a sync response to restore the + * @returns Promise which resolves with a sync response to restore the * client state to where it was at the last save, or null if there * is no saved sync data. */ @@ -229,7 +209,7 @@ export class StubStore implements IStore { } /** - * @return {Promise} If there is a saved sync, the nextBatch token + * @returns If there is a saved sync, the nextBatch token * for this sync, otherwise null. */ public getSavedSyncToken(): Promise { @@ -239,7 +219,7 @@ export class StubStore implements IStore { /** * Delete all data from this store. Does nothing since this store * doesn't store anything. - * @return {Promise} An immediately resolved promise. + * @returns An immediately resolved promise. */ public deleteAllData(): Promise { return Promise.resolve(); diff --git a/src/sync-accumulator.ts b/src/sync-accumulator.ts index f383cb98a..13f87ecc0 100644 --- a/src/sync-accumulator.ts +++ b/src/sync-accumulator.ts @@ -16,7 +16,6 @@ limitations under the License. /** * This is an internal module. See {@link SyncAccumulator} for the public class. - * @module sync-accumulator */ import { logger } from './logger'; @@ -28,6 +27,13 @@ import { MAIN_ROOM_TIMELINE, ReceiptContent, ReceiptType } from "./@types/read_r import { UNREAD_THREAD_NOTIFICATIONS } from './@types/sync'; interface IOpts { + /** + * The ideal maximum number of timeline entries to keep in the sync response. + * This is best-effort, as clients do not always have a back-pagination token for each event, + * so it's possible there may be slightly *less* than this value. There will never be more. + * This cannot be 0 or else it makes it impossible to scroll back in a room. + * Default: 50. + */ maxTimelineEntries?: number; } @@ -211,15 +217,6 @@ export class SyncAccumulator { // streaming from without losing events. private nextBatch: string | null = null; - /** - * @param {Object} opts - * @param {Number=} opts.maxTimelineEntries The ideal maximum number of - * timeline entries to keep in the sync response. This is best-effort, as - * clients do not always have a back-pagination token for each event, so - * it's possible there may be slightly *less* than this value. There will - * never be more. This cannot be 0 or else it makes it impossible to scroll - * back in a room. Default: 50. - */ public constructor(private readonly opts: IOpts = {}) { this.opts.maxTimelineEntries = this.opts.maxTimelineEntries || 50; } @@ -242,8 +239,8 @@ export class SyncAccumulator { /** * Accumulate incremental /sync room data. - * @param {Object} syncResponse the complete /sync JSON - * @param {boolean} fromDatabase True if the sync response is one saved to the database + * @param syncResponse - the complete /sync JSON + * @param fromDatabase - True if the sync response is one saved to the database */ private accumulateRooms(syncResponse: ISyncResponse, fromDatabase = false): void { if (!syncResponse.rooms) { @@ -531,8 +528,8 @@ export class SyncAccumulator { * represents all room data that should be stored. This should be paired * with the sync token which represents the most recent /sync response * provided to accumulate(). - * @param {boolean} forDatabase True to generate a sync to be saved to storage - * @return {Object} An object with a "nextBatch", "roomsData" and "accountData" + * @param forDatabase - True to generate a sync to be saved to storage + * @returns An object with a "nextBatch", "roomsData" and "accountData" * keys. * The "nextBatch" key is a string which represents at what point in the * /sync stream the accumulator reached. This token should be used when diff --git a/src/sync.ts b/src/sync.ts index c97ba3540..38325ca83 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -106,6 +106,7 @@ function getFilterName(userId: string, suffix?: string): string { return `FILTER_SYNC_${userId}` + (suffix ? "_" + suffix : ""); } +/* istanbul ignore next */ function debuglog(...params: any[]): void { if (!DEBUG) return; logger.log(...params); @@ -117,9 +118,27 @@ interface ISyncOptions { } export interface ISyncStateData { + /** + * The matrix error if `state=ERROR`. + */ error?: Error; + /** + * The 'since' token passed to /sync. + * `null` for the first successful sync since this client was + * started. Only present if `state=PREPARED` or + * `state=SYNCING`. + */ oldSyncToken?: string; + /** + * The 'next_batch' result from /sync, which + * will become the 'since' token for the next call to /sync. Only present if + * `state=PREPARED or state=SYNCING`. + */ nextSyncToken?: string; + /** + * True if we are working our way through a + * backlog of events after connecting. Only present if `state=SYNCING`. + */ catchingUp?: boolean; fromCache?: boolean; } @@ -146,21 +165,6 @@ type WrappedRoom = T & { isBrandNewRoom: boolean; }; -/** - * Internal class - unstable. - * Construct an entity which is able to sync with a homeserver. - * @constructor - * @param {MatrixClient} client The matrix client instance to use. - * @param {Object} opts Config options - * @param {module:crypto=} opts.crypto Crypto manager - * @param {Function=} opts.canResetEntireTimeline A function which is called - * with a room ID and returns a boolean. It should return 'true' if the SDK can - * SAFELY remove events from this room. It may not be safe to remove events if - * there are other references to the timelines for this room. - * Default: returns false. - * @param {Boolean=} opts.disablePresence True to perform syncing without automatically - * updating presence. - */ export class SyncApi { private _peekRoom: Optional = null; private currentSyncRequest?: Promise; @@ -175,6 +179,12 @@ export class SyncApi { private failedSyncCount = 0; // Number of consecutive failed /sync requests private storeIsInvalid = false; // flag set if the store needs to be cleared before we can start + /** + * Construct an entity which is able to sync with a homeserver. + * @param client - The matrix client instance to use. + * @param opts - Config options + * @internal + */ public constructor(private readonly client: MatrixClient, private readonly opts: Partial = {}) { this.opts.initialSyncLimit = this.opts.initialSyncLimit ?? 8; this.opts.resolveInvitesToProfiles = this.opts.resolveInvitesToProfiles || false; @@ -196,10 +206,6 @@ export class SyncApi { } } - /** - * @param {string} roomId - * @return {Room} - */ public createRoom(roomId: string): Room { const room = _createAndReEmitRoom(this.client, roomId, this.opts); @@ -214,9 +220,9 @@ export class SyncApi { * new historical messages imported by MSC2716 `/batch_send` somewhere in * the room and we need to throw away the timeline to make sure the * historical messages are shown when we paginate `/messages` again. - * @param {Room} room The room where the marker event was sent - * @param {MatrixEvent} markerEvent The new marker event - * @param {IMarkerFoundOptions} setStateOptions When `timelineWasEmpty` is set + * @param room - The room where the marker event was sent + * @param markerEvent - The new marker event + * @param setStateOptions - When `timelineWasEmpty` is set * as `true`, the given marker event will be ignored */ private onMarkerStateEvent( @@ -279,7 +285,7 @@ export class SyncApi { /** * Sync rooms the user has left. - * @return {Promise} Resolved when they've been added to the store. + * @returns Resolved when they've been added to the store. */ public async syncLeftRooms(): Promise { const client = this.client; @@ -350,8 +356,8 @@ export class SyncApi { /** * Peek into a room. This will result in the room in question being synced so it * is accessible via getRooms(). Live updates for the room will be provided. - * @param {string} roomId The room ID to peek into. - * @return {Promise} A promise which resolves once the room has been added to the + * @param roomId - The room ID to peek into. + * @returns A promise which resolves once the room has been added to the * store. */ public peek(roomId: string): Promise { @@ -430,8 +436,7 @@ export class SyncApi { /** * Do a peek room poll. - * @param {Room} peekRoom - * @param {string?} token from= token + * @param token - from= token */ private peekPoll(peekRoom: Room, token?: string): void { if (this._peekRoom !== peekRoom) { @@ -494,8 +499,7 @@ export class SyncApi { /** * Returns the current state of this sync object - * @see module:client~MatrixClient#event:"sync" - * @return {?String} + * @see MatrixClient#event:"sync" */ public getSyncState(): SyncState | null { return this.syncState; @@ -507,7 +511,6 @@ export class SyncApi { * such data. * Sync errors, if available, are put in the 'error' key of * this object. - * @return {?Object} */ public getSyncStateData(): ISyncStateData | null { return this.syncStateData ?? null; @@ -526,8 +529,8 @@ export class SyncApi { /** * Is the lazy loading option different than in previous session? - * @param {boolean} lazyLoadMembers current options for lazy loading - * @return {boolean} whether or not the option has changed compared to the previous session */ + * @param lazyLoadMembers - current options for lazy loading + * @returns whether or not the option has changed compared to the previous session */ private async wasLazyLoadingToggled(lazyLoadMembers = false): Promise { // assume it was turned off before // if we don't know any better @@ -758,7 +761,7 @@ export class SyncApi { /** * Retry a backed off syncing request immediately. This should only be used when * the user explicitly attempts to retry their lost connection. - * @return {boolean} True if this resulted in a request being retried. + * @returns True if this resulted in a request being retried. */ public retryImmediately(): boolean { if (!this.connectionReturnedDefer) { @@ -769,7 +772,7 @@ export class SyncApi { } /** * Process a single set of cached sync data. - * @param {Object} savedSync a saved sync that was persisted by a store. This + * @param savedSync - a saved sync that was persisted by a store. This * should have been acquired via client.store.getSavedSync(). */ private async syncFromCache(savedSync: ISavedSync): Promise { @@ -811,9 +814,6 @@ export class SyncApi { /** * Invoke me to do /sync calls - * @param {Object} syncOptions - * @param {string} syncOptions.filterId - * @param {boolean} syncOptions.hasSyncedBefore */ private async doSync(syncOptions: ISyncOptions): Promise { while (this.running) { @@ -1023,8 +1023,8 @@ export class SyncApi { * Process data returned from a sync response and propagate it * into the model objects * - * @param {Object} syncEventData Object containing sync tokens associated with this sync - * @param {Object} data The response from /sync + * @param syncEventData - Object containing sync tokens associated with this sync + * @param data - The response from /sync */ private async processSyncResponse(syncEventData: ISyncStateData, data: ISyncResponse): Promise { const client = this.client; @@ -1490,10 +1490,10 @@ export class SyncApi { /** * Starts polling the connectivity check endpoint - * @param {number} delay How long to delay until the first poll. + * @param delay - How long to delay until the first poll. * defaults to a short, randomised interval (to prevent * tight-looping if /versions succeeds but /sync etc. fail). - * @return {promise} which resolves once the connection returns + * @returns which resolves once the connection returns */ private startKeepAlives(delay?: number): Promise { if (delay === undefined) { @@ -1521,7 +1521,7 @@ export class SyncApi { * On failure, schedules a call back to itself. On success, resolves * this.connectionReturnedDefer. * - * @param {boolean} connDidFail True if a connectivity failure has been detected. Optional. + * @param connDidFail - True if a connectivity failure has been detected. Optional. */ private pokeKeepAlive(connDidFail = false): void { const success = (): void => { @@ -1568,10 +1568,6 @@ export class SyncApi { }); } - /** - * @param {Object} obj - * @return {Object[]} - */ private mapSyncResponseToRoomArray( obj: Record, ): Array> { @@ -1593,12 +1589,6 @@ export class SyncApi { }); } - /** - * @param {Object} obj - * @param {Room} room - * @param {boolean} decrypt - * @return {MatrixEvent[]} - */ private mapSyncEventsFormat( obj: IInviteState | ITimeline | IEphemeral, room?: Room, @@ -1618,7 +1608,6 @@ export class SyncApi { } /** - * @param {Room} room */ private resolveInvites(room: Room): void { if (!room || !this.opts.resolveInvitesToProfiles) { @@ -1662,12 +1651,11 @@ export class SyncApi { /** * Injects events into a room's model. - * @param {Room} room - * @param {MatrixEvent[]} stateEventList A list of state events. This is the state + * @param stateEventList - A list of state events. This is the state * at the *START* of the timeline list if it is supplied. - * @param {MatrixEvent[]} [timelineEventList] A list of timeline events, including threaded. Lower index + * @param timelineEventList - A list of timeline events, including threaded. Lower index * is earlier in time. Higher index is later. - * @param {boolean} fromCache whether the sync response came from cache + * @param fromCache - whether the sync response came from cache */ public async injectRoomEvents( room: Room, @@ -1743,8 +1731,7 @@ export class SyncApi { * as appropriate. * This must be called after the room the events belong to has been stored. * - * @param {Room} room - * @param {MatrixEvent[]} [timelineEventList] A list of timeline events. Lower index + * @param timelineEventList - A list of timeline events. Lower index * is earlier in time. Higher index is later. */ private processEventsForNotifs(room: Room, timelineEventList: MatrixEvent[]): void { @@ -1759,9 +1746,6 @@ export class SyncApi { } } - /** - * @return {string} - */ private getGuestFilter(): string { // Dev note: This used to be conditional to return a filter of 20 events maximum, but // the condition never went to the other branch. This is now hardcoded. @@ -1770,8 +1754,8 @@ export class SyncApi { /** * Sets the sync state and emits an event to say so - * @param {String} newState The new state string - * @param {Object} data Object of additional data to emit in the event + * @param newState - The new state string + * @param data - Object of additional data to emit in the event */ private updateSyncState(newState: SyncState, data?: ISyncStateData): void { const old = this.syncState; diff --git a/src/timeline-window.ts b/src/timeline-window.ts index 5498600a9..2d0c9da15 100644 --- a/src/timeline-window.ts +++ b/src/timeline-window.ts @@ -14,8 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/** @module timeline-window */ - import { Optional } from "matrix-events-sdk"; import { Direction, EventTimeline } from './models/event-timeline'; @@ -25,23 +23,28 @@ import { EventTimelineSet } from "./models/event-timeline-set"; import { MatrixEvent } from "./models/event"; /** - * @private + * @internal */ const DEBUG = false; /** - * @private + * @internal */ +/* istanbul ignore next */ const debuglog = DEBUG ? logger.log.bind(logger) : function(): void {}; /** * the number of times we ask the server for more events before giving up * - * @private + * @internal */ const DEFAULT_PAGINATE_LOOP_LIMIT = 5; interface IOpts { + /** + * Maximum number of events to keep in the window. If more events are retrieved via pagination requests, + * excess events will be dropped from the other end of the window. + */ windowLimit?: number; } @@ -58,31 +61,22 @@ export class TimelineWindow { /** * Construct a TimelineWindow. * - *

This abstracts the separate timelines in a Matrix {@link - * module:models/room|Room} into a single iterable thing. It keeps track of - * the start and endpoints of the window, which can be advanced with the help + *

This abstracts the separate timelines in a Matrix {@link Room} into a single iterable thing. + * It keeps track of the start and endpoints of the window, which can be advanced with the help * of pagination requests. * - *

Before the window is useful, it must be initialised by calling {@link - * module:timeline-window~TimelineWindow#load|load}. + *

Before the window is useful, it must be initialised by calling {@link TimelineWindow#load}. * *

Note that the window will not automatically extend itself when new events - * are received from /sync; you should arrange to call {@link - * module:timeline-window~TimelineWindow#paginate|paginate} on {@link - * module:client~MatrixClient.event:"Room.timeline"|Room.timeline} events. + * are received from /sync; you should arrange to call {@link TimelineWindow#paginate} + * on {@link RoomEvent.Timeline} events. * - * @param {MatrixClient} client MatrixClient to be used for context/pagination + * @param client - MatrixClient to be used for context/pagination * requests. * - * @param {EventTimelineSet} timelineSet The timelineSet to track + * @param timelineSet - The timelineSet to track * - * @param {Object} [opts] Configuration options for this window - * - * @param {number} [opts.windowLimit = 1000] maximum number of events to keep - * in the window. If more events are retrieved via pagination requests, - * excess events will be dropped from the other end of the window. - * - * @constructor + * @param opts - Configuration options for this window */ public constructor( private readonly client: MatrixClient, @@ -95,11 +89,9 @@ export class TimelineWindow { /** * Initialise the window to point at a given event, or the live timeline * - * @param {string} [initialEventId] If given, the window will contain the + * @param initialEventId - If given, the window will contain the * given event - * @param {number} [initialWindowSize = 20] Size of the initial window - * - * @return {Promise} + * @param initialWindowSize - Size of the initial window */ public load(initialEventId?: string, initialWindowSize = 20): Promise { // given an EventTimeline, find the event we were looking for, and initialise our @@ -148,11 +140,11 @@ export class TimelineWindow { /** * Get the TimelineIndex of the window in the given direction. * - * @param {string} direction EventTimeline.BACKWARDS to get the TimelineIndex + * @param direction - EventTimeline.BACKWARDS to get the TimelineIndex * at the start of the window; EventTimeline.FORWARDS to get the TimelineIndex at * the end. * - * @return {TimelineIndex} The requested timeline index if one exists, null + * @returns The requested timeline index if one exists, null * otherwise. */ public getTimelineIndex(direction: Direction): TimelineIndex | null { @@ -169,11 +161,11 @@ export class TimelineWindow { * Try to extend the window using events that are already in the underlying * TimelineIndex. * - * @param {string} direction EventTimeline.BACKWARDS to try extending it + * @param direction - EventTimeline.BACKWARDS to try extending it * backwards; EventTimeline.FORWARDS to try extending it forwards. - * @param {number} size number of events to try to extend by. + * @param size - number of events to try to extend by. * - * @return {boolean} true if the window was extended, false otherwise. + * @returns true if the window was extended, false otherwise. */ public extend(direction: Direction, size: number): boolean { const tl = this.getTimelineIndex(direction); @@ -209,10 +201,10 @@ export class TimelineWindow { * necessarily mean that there are more events available in that direction at * this time. * - * @param {string} direction EventTimeline.BACKWARDS to check if we can + * @param direction - EventTimeline.BACKWARDS to check if we can * paginate backwards; EventTimeline.FORWARDS to check if we can go forwards * - * @return {boolean} true if we can paginate in the given direction + * @returns true if we can paginate in the given direction */ public canPaginate(direction: Direction): boolean { const tl = this.getTimelineIndex(direction); @@ -240,23 +232,23 @@ export class TimelineWindow { /** * Attempt to extend the window * - * @param {string} direction EventTimeline.BACKWARDS to extend the window + * @param direction - EventTimeline.BACKWARDS to extend the window * backwards (towards older events); EventTimeline.FORWARDS to go forwards. * - * @param {number} size number of events to try to extend by. If fewer than this + * @param size - number of events to try to extend by. If fewer than this * number are immediately available, then we return immediately rather than * making an API call. * - * @param {boolean} [makeRequest = true] whether we should make API calls to + * @param makeRequest - whether we should make API calls to * fetch further events if we don't have any at all. (This has no effect if * the room already knows about additional events in the relevant direction, * even if there are fewer than 'size' of them, as we will just return those * we already know about.) * - * @param {number} [requestLimit = 5] limit for the number of API requests we + * @param requestLimit - limit for the number of API requests we * should make. * - * @return {Promise} Resolves to a boolean which is true if more events + * @returns Promise which resolves to a boolean which is true if more events * were successfully retrieved. */ public async paginate( @@ -330,8 +322,8 @@ export class TimelineWindow { /** * Remove `delta` events from the start or end of the timeline. * - * @param {number} delta number of events to remove from the timeline - * @param {boolean} startOfTimeline if events should be removed from the start + * @param delta - number of events to remove from the timeline + * @param startOfTimeline - if events should be removed from the start * of the timeline. */ public unpaginate(delta: number, startOfTimeline: boolean): void { @@ -368,7 +360,7 @@ export class TimelineWindow { /** * Get a list of the events currently in the window * - * @return {MatrixEvent[]} the events in the window + * @returns the events in the window */ public getEvents(): MatrixEvent[] { if (!this.start) { @@ -419,12 +411,8 @@ export class TimelineWindow { } /** - * a thing which contains a timeline reference, and an index into it. - * - * @constructor - * @param {EventTimeline} timeline - * @param {number} index - * @private + * A thing which contains a timeline reference, and an index into it. + * @internal */ export class TimelineIndex { public pendingPaginate?: Promise; @@ -433,7 +421,7 @@ export class TimelineIndex { public constructor(public timeline: EventTimeline, public index: number) {} /** - * @return {number} the minimum possible value for the index in the current + * @returns the minimum possible value for the index in the current * timeline */ public minIndex(): number { @@ -441,7 +429,7 @@ export class TimelineIndex { } /** - * @return {number} the maximum possible value for the index in the current + * @returns the maximum possible value for the index in the current * timeline (exclusive - ie, it actually returns one more than the index * of the last element). */ @@ -452,8 +440,8 @@ export class TimelineIndex { /** * Try move the index forward, or into the neighbouring timeline * - * @param {number} delta number of events to advance by - * @return {number} number of events successfully advanced by + * @param delta - number of events to advance by + * @returns number of events successfully advanced by */ public advance(delta: number): number { if (!delta) { @@ -512,8 +500,8 @@ export class TimelineIndex { /** * Try move the index backwards, or into the neighbouring timeline * - * @param {number} delta number of events to retreat by - * @return {number} number of events successfully retreated by + * @param delta - number of events to retreat by + * @returns number of events successfully retreated by */ public retreat(delta: number): number { return this.advance(delta * -1) * -1; diff --git a/src/utils.ts b/src/utils.ts index ef6af6b06..8cf248c78 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -17,7 +17,6 @@ limitations under the License. /** * This is an internal module. - * @module utils */ import unhomoglyph from "unhomoglyph"; @@ -33,7 +32,7 @@ const interns = new Map(); /** * Internalises a string, reusing a known pointer or storing the pointer * if needed for future strings. - * @param str The string to internalise. + * @param str - The string to internalise. * @returns The internalised string. */ export function internaliseString(str: string): string { @@ -55,9 +54,9 @@ export function internaliseString(str: string): string { /** * Encode a dictionary of query parameters. * Omits any undefined/null values. - * @param {Object} params A dict of key/values to encode e.g. - * {"foo": "bar", "baz": "taz"} - * @return {string} The encoded string e.g. foo=bar&baz=taz + * @param params - A dict of key/values to encode e.g. + * `{"foo": "bar", "baz": "taz"}` + * @returns The encoded string e.g. foo=bar&baz=taz */ export function encodeParams(params: QueryDict, urlSearchParams?: URLSearchParams): URLSearchParams { const searchParams = urlSearchParams ?? new URLSearchParams(); @@ -79,9 +78,6 @@ export type QueryDict = Record { /** * Encodes a URI according to a set of template variables. Variables will be * passed through encodeURIComponent. - * @param {string} pathTemplate The path with template variables e.g. '/foo/$bar'. - * @param {Object} variables The key/value pairs to replace the template - * variables with. E.g. { "$bar": "baz" }. - * @return {string} The result of replacing all template variables e.g. '/foo/baz'. + * @param pathTemplate - The path with template variables e.g. '/foo/$bar'. + * @param variables - The key/value pairs to replace the template + * variables with. E.g. `{ "$bar": "baz" }`. + * @returns The result of replacing all template variables e.g. '/foo/baz'. */ export function encodeUri(pathTemplate: string, variables: Record>): string { for (const key in variables) { @@ -142,12 +138,12 @@ export function encodeUri(pathTemplate: string, variables: Recordfn(element, index, array). Return true to + * @param array - The array. + * @param fn - Function to execute on each value in the array, with the + * function signature `fn(element, index, array)`. Return true to * remove this element and break. - * @param {boolean} reverse True to search in reverse order. - * @return {boolean} True if an element was removed. + * @param reverse - True to search in reverse order. + * @returns True if an element was removed. */ export function removeElement( array: T[], @@ -175,8 +171,8 @@ export function removeElement( /** * Checks if the given thing is a function. - * @param {*} value The thing to check. - * @return {boolean} True if it is a function. + * @param value - The thing to check. + * @returns True if it is a function. */ export function isFunction(value: any): boolean { return Object.prototype.toString.call(value) === "[object Function]"; @@ -184,8 +180,8 @@ export function isFunction(value: any): boolean { /** * Checks that the given object has the specified keys. - * @param {Object} obj The object to check. - * @param {string[]} keys The list of keys that 'obj' must have. + * @param obj - The object to check. + * @param keys - The list of keys that 'obj' must have. * @throws If the object is missing keys. */ // note using 'keys' here would shadow the 'keys' function defined above @@ -200,8 +196,8 @@ export function checkObjectHasKeys(obj: object, keys: string[]): void { /** * Deep copy the given object. The object MUST NOT have circular references and * MUST NOT have functions. - * @param {Object} obj The object to deep copy. - * @return {Object} A copy of the object without any references to the original. + * @param obj - The object to deep copy. + * @returns A copy of the object without any references to the original. */ export function deepCopy(obj: T): T { return JSON.parse(JSON.stringify(obj)); @@ -210,10 +206,10 @@ export function deepCopy(obj: T): T { /** * Compare two objects for equality. The objects MUST NOT have circular references. * - * @param {Object} x The first object to compare. - * @param {Object} y The second object to compare. + * @param x - The first object to compare. + * @param y - The second object to compare. * - * @return {boolean} true if the two objects are equal + * @returns true if the two objects are equal */ export function deepCompare(x: any, y: any): boolean { // Inspired by @@ -290,8 +286,8 @@ export function deepCompare(x: any, y: any): boolean { * sorts the result by key, recursively. The input object must * ensure it does not have loops. If the input is not an object * then it will be returned as-is. - * @param {*} obj The object to get entries of - * @returns {Array} The entries, sorted by key. + * @param obj - The object to get entries of + * @returns The entries, sorted by key. */ export function deepSortedObjectEntries(obj: any): [string, any][] { if (typeof(obj) !== "object") return obj; @@ -313,8 +309,8 @@ export function deepSortedObjectEntries(obj: any): [string, any][] { /** * Returns whether the given value is a finite number without type-coercion * - * @param {*} value the value to test - * @return {boolean} whether or not value is a finite number without type-coercion + * @param value - the value to test + * @returns whether or not value is a finite number without type-coercion */ export function isNumber(value: any): value is number { return typeof value === 'number' && isFinite(value); @@ -323,8 +319,8 @@ export function isNumber(value: any): value is number { /** * Removes zero width chars, diacritics and whitespace from the string * Also applies an unhomoglyph on the string, to prevent similar looking chars - * @param {string} str the string to remove hidden characters from - * @return {string} a string with the hidden characters removed + * @param str - the string to remove hidden characters from + * @returns a string with the hidden characters removed */ export function removeHiddenChars(str: string): string { if (typeof str === "string") { @@ -335,7 +331,6 @@ export function removeHiddenChars(str: string): string { /** * Removes the direction override characters from a string - * @param {string} input * @returns string with chars removed */ export function removeDirectionOverrideChars(str: string): string { @@ -466,9 +461,9 @@ export async function chunkPromises(fns: (() => Promise)[], chunkSize: num * a promise which throws/rejects on error, otherwise the retry will assume the request * succeeded. The promise chain returned will contain the successful promise. The given function * should always return a new promise. - * @param {Function} promiseFn The function to call to get a fresh promise instance. Takes an + * @param promiseFn - The function to call to get a fresh promise instance. Takes an * attempt count as an argument, for logging/debugging purposes. - * @returns {Promise} The promise for the retried operation. + * @returns The promise for the retried operation. */ export function simpleRetryOperation(promiseFn: (attempt: number) => Promise): Promise { return promiseRetry((attempt: number) => { @@ -503,10 +498,10 @@ export const DEFAULT_ALPHABET = ((): string => { * padded at the end with the first character in the alphabet. * * This is intended for use with string averaging. - * @param {string} s The string to pad. - * @param {number} n The length to pad to. - * @param {string} alphabet The alphabet to use as a single string. - * @returns {string} The padded string. + * @param s - The string to pad. + * @param n - The length to pad to. + * @param alphabet - The alphabet to use as a single string. + * @returns The padded string. */ export function alphabetPad(s: string, n: number, alphabet = DEFAULT_ALPHABET): string { return s.padEnd(n, alphabet[0]); @@ -516,9 +511,9 @@ export function alphabetPad(s: string, n: number, alphabet = DEFAULT_ALPHABET): * Converts a baseN number to a string, where N is the alphabet's length. * * This is intended for use with string averaging. - * @param {bigint} n The baseN number. - * @param {string} alphabet The alphabet to use as a single string. - * @returns {string} The baseN number encoded as a string from the alphabet. + * @param n - The baseN number. + * @param alphabet - The alphabet to use as a single string. + * @returns The baseN number encoded as a string from the alphabet. */ export function baseToString(n: bigint, alphabet = DEFAULT_ALPHABET): string { // Developer note: the stringToBase() function offsets the character set by 1 so that repeated @@ -550,9 +545,9 @@ export function baseToString(n: bigint, alphabet = DEFAULT_ALPHABET): string { * Converts a string to a baseN number, where N is the alphabet's length. * * This is intended for use with string averaging. - * @param {string} s The string to convert to a number. - * @param {string} alphabet The alphabet to use as a single string. - * @returns {bigint} The baseN number. + * @param s - The string to convert to a number. + * @param alphabet - The alphabet to use as a single string. + * @returns The baseN number. */ export function stringToBase(s: string, alphabet = DEFAULT_ALPHABET): bigint { const len = BigInt(alphabet.length); @@ -584,10 +579,10 @@ export function stringToBase(s: string, alphabet = DEFAULT_ALPHABET): bigint { * Averages two strings, returning the midpoint between them. This is accomplished by * converting both to baseN numbers (where N is the alphabet's length) then averaging * those before re-encoding as a string. - * @param {string} a The first string. - * @param {string} b The second string. - * @param {string} alphabet The alphabet to use as a single string. - * @returns {string} The midpoint between the strings, as a string. + * @param a - The first string. + * @param b - The second string. + * @param alphabet - The alphabet to use as a single string. + * @returns The midpoint between the strings, as a string. */ export function averageBetweenStrings(a: string, b: string, alphabet = DEFAULT_ALPHABET): string { const padN = Math.max(a.length, b.length); @@ -608,9 +603,9 @@ export function averageBetweenStrings(a: string, b: string, alphabet = DEFAULT_A * Finds the next string using the alphabet provided. This is done by converting the * string to a baseN number, where N is the alphabet's length, then adding 1 before * converting back to a string. - * @param {string} s The string to start at. - * @param {string} alphabet The alphabet to use as a single string. - * @returns {string} The string which follows the input string. + * @param s - The string to start at. + * @param alphabet - The alphabet to use as a single string. + * @returns The string which follows the input string. */ export function nextString(s: string, alphabet = DEFAULT_ALPHABET): string { return baseToString(stringToBase(s, alphabet) + BigInt(1), alphabet); @@ -620,9 +615,9 @@ export function nextString(s: string, alphabet = DEFAULT_ALPHABET): string { * Finds the previous string using the alphabet provided. This is done by converting the * string to a baseN number, where N is the alphabet's length, then subtracting 1 before * converting back to a string. - * @param {string} s The string to start at. - * @param {string} alphabet The alphabet to use as a single string. - * @returns {string} The string which precedes the input string. + * @param s - The string to start at. + * @param alphabet - The alphabet to use as a single string. + * @returns The string which precedes the input string. */ export function prevString(s: string, alphabet = DEFAULT_ALPHABET): string { return baseToString(stringToBase(s, alphabet) - BigInt(1), alphabet); @@ -630,9 +625,9 @@ export function prevString(s: string, alphabet = DEFAULT_ALPHABET): string { /** * Compares strings lexicographically as a sort-safe function. - * @param {string} a The first (reference) string. - * @param {string} b The second (compare) string. - * @returns {number} Negative if the reference string is before the compare string; + * @param a - The first (reference) string. + * @param b - The second (compare) string. + * @returns Negative if the reference string is before the compare string; * positive if the reference string is after; and zero if equal. */ export function lexicographicCompare(a: string, b: string): number { @@ -650,8 +645,8 @@ export function lexicographicCompare(a: string, b: string): number { const collator = new Intl.Collator(); /** * Performant language-sensitive string comparison - * @param a the first string to compare - * @param b the second string to compare + * @param a - the first string to compare + * @param b - the second string to compare */ export function compare(a: string, b: string): number { return collator.compare(a, b); @@ -661,8 +656,6 @@ export function compare(a: string, b: string): number { * This function is similar to Object.assign() but it assigns recursively and * allows you to ignore nullish values from the source * - * @param {Object} target - * @param {Object} source * @returns the target object */ export function recursivelyAssign>( @@ -701,7 +694,7 @@ export function isSupportedReceiptType(receiptType: string): boolean { /** * Determines whether two maps are equal. - * @param eq The equivalence relation to compare values by. Defaults to strict equality. + * @param eq - The equivalence relation to compare values by. Defaults to strict equality. */ export function mapsEqual(x: Map, y: Map, eq = (v1: V, v2: V): boolean => v1 === v2): boolean { if (x.size !== y.size) return false; diff --git a/src/webrtc/audioContext.ts b/src/webrtc/audioContext.ts index 0e08574b8..7cf3ed3f6 100644 --- a/src/webrtc/audioContext.ts +++ b/src/webrtc/audioContext.ts @@ -22,7 +22,7 @@ let refCount = 0; * It's highly recommended to reuse this AudioContext rather than creating your * own, because multiple AudioContexts can be problematic in some browsers. * Make sure to call releaseContext when you're done using it. - * @returns {AudioContext} The shared AudioContext + * @returns The shared AudioContext */ export const acquireContext = (): AudioContext => { if (audioContext === null) audioContext = new AudioContext(); diff --git a/src/webrtc/call.ts b/src/webrtc/call.ts index 7d303af4a..c9bcac112 100644 --- a/src/webrtc/call.ts +++ b/src/webrtc/call.ts @@ -19,7 +19,6 @@ limitations under the License. /** * This is an internal module. See {@link createNewMatrixCall} for the public API. - * @module webrtc/call */ import { v4 as uuidv4 } from "uuid"; @@ -54,29 +53,19 @@ import { GroupCallUnknownDeviceError } from './groupCall'; import { IScreensharingOpts } from "./mediaHandler"; import { MatrixError } from "../http-api"; -// events: hangup, error(err), replaced(call), state(state, oldState) - -/** - * Fires whenever an error occurs when call.js encounters an issue with setting up the call. - *

- * The error given will have a code equal to either `MatrixCall.ERR_LOCAL_OFFER_FAILED` or - * `MatrixCall.ERR_NO_USER_MEDIA`. `ERR_LOCAL_OFFER_FAILED` is emitted when the local client - * fails to create an offer. `ERR_NO_USER_MEDIA` is emitted when the user has denied access - * to their audio/video hardware. - * - * @event module:webrtc/call~MatrixCall#"error" - * @param {Error} err The error raised by MatrixCall. - * @example - * matrixCall.on("error", function(err){ - * console.error(err.code, err); - * }); - */ - interface CallOpts { + // The room ID for this call. roomId?: string; invitee?: string; + // The Matrix Client instance to send events to. client: MatrixClient; + /** + * Whether relay through TURN should be forced. + * @deprecated use opts.forceTURN when creating the matrix client + * since it's only possible to set this option on outbound calls. + */ forceTURN?: boolean; + // A list of TURN servers. turnServers?: Array; opponentDeviceId?: string; opponentSessionId?: string; @@ -320,17 +309,6 @@ function getTransceiverKey(purpose: SDPStreamMetadataPurpose, kind: TransceiverK return purpose + ':' + kind; } -/** - * Construct a new Matrix Call. - * @constructor - * @param {Object} opts Config options. - * @param {string} opts.roomId The room ID for this call. - * @param {Object} opts.webRtc The WebRTC globals from the browser. - * @param {boolean} opts.forceTURN whether relay through TURN should be forced. - * @param {Object} opts.URL The URL global. - * @param {Array} opts.turnServers Optional. A list of TURN servers. - * @param {MatrixClient} opts.client The Matrix Client instance to send events to. - */ export class MatrixCall extends TypedEventEmitter { public roomId?: string; public callId: string; @@ -405,6 +383,10 @@ export class MatrixCall extends TypedEventEmitter} CallFeeds + * @returns CallFeeds */ public getFeeds(): Array { return this.feeds; @@ -565,7 +547,7 @@ export class MatrixCall extends TypedEventEmitter} local CallFeeds + * @returns local CallFeeds */ public getLocalFeeds(): Array { return this.feeds.filter((feed) => feed.isLocal()); @@ -573,7 +555,7 @@ export class MatrixCall extends TypedEventEmitter} remote CallFeeds + * @returns remote CallFeeds */ public getRemoteFeeds(): Array { return this.feeds.filter((feed) => !feed.isLocal()); @@ -605,7 +587,7 @@ export class MatrixCall extends TypedEventEmitter !feed.isLocal()); @@ -747,8 +729,8 @@ export class MatrixCall extends TypedEventEmitter callFeed.stream.id === feed.stream.id)) { @@ -820,7 +802,7 @@ export class MatrixCall extends TypedEventEmitter { const invite = event.getContent(); @@ -970,7 +952,7 @@ export class MatrixCall extends TypedEventEmitter { // Skip if there is nothing to do @@ -1233,9 +1215,9 @@ export class MatrixCall extends TypedEventEmitter { @@ -1371,7 +1353,7 @@ export class MatrixCall extends TypedEventEmitterall of the tracks need to be muted * for this to return true. This means if there are no video tracks, this will * return true. - * @return {Boolean} True if the local preview video is muted, else false + * @returns True if the local preview video is muted, else false * (including if the call is not set up yet). */ public isLocalVideoMuted(): boolean { @@ -1380,7 +1362,7 @@ export class MatrixCall extends TypedEventEmitter { @@ -1405,7 +1387,7 @@ export class MatrixCall extends TypedEventEmitterall of the tracks need to be muted * for this to return true. This means if there are no audio tracks, this will * return true. - * @return {Boolean} True if the mic is muted, else false (including if the call + * @returns True if the mic is muted, else false (including if the call * is not set up yet). */ public isMicrophoneMuted(): boolean { @@ -1459,7 +1441,7 @@ export class MatrixCall extends TypedEventEmitter { if (event.candidate) { @@ -1752,7 +1733,6 @@ export class MatrixCall extends TypedEventEmitter { const content = event.getContent(); @@ -2258,10 +2238,7 @@ export class MatrixCall extends TypedEventEmitter { const realContent = Object.assign({}, content, { @@ -2321,7 +2298,7 @@ export class MatrixCall extends TypedEventEmitter void; }; diff --git a/src/webrtc/callFeed.ts b/src/webrtc/callFeed.ts index 14abc30d2..3ed84a586 100644 --- a/src/webrtc/callFeed.ts +++ b/src/webrtc/callFeed.ts @@ -189,7 +189,7 @@ export class CallFeed extends TypedEventEmitter /** * Returns true if CallFeed is local, otherwise returns false - * @returns {boolean} is local? + * @returns is local? */ public isLocal(): boolean { return this.userId === this.client.getUserId() @@ -199,7 +199,7 @@ export class CallFeed extends TypedEventEmitter /** * Returns true if audio is muted or if there are no audio * tracks, otherwise returns false - * @returns {boolean} is audio muted? + * @returns is audio muted? */ public isAudioMuted(): boolean { return this.stream.getAudioTracks().length === 0 || this.audioMuted; @@ -208,7 +208,7 @@ export class CallFeed extends TypedEventEmitter /** * Returns true video is muted or if there are no video * tracks, otherwise returns false - * @returns {boolean} is video muted? + * @returns is video muted? */ public isVideoMuted(): boolean { // We assume only one video track @@ -224,7 +224,7 @@ export class CallFeed extends TypedEventEmitter * The stream will be different and new stream as remore parties are * concerned, but this can be used for convenience locally to set up * volume listeners automatically on the new stream etc. - * @param newStream new stream with which to replace the current one + * @param newStream - new stream with which to replace the current one */ public setNewStream(newStream: MediaStream): void { this.updateStream(this.stream, newStream); @@ -233,8 +233,8 @@ export class CallFeed extends TypedEventEmitter /** * Set one or both of feed's internal audio and video video mute state * Either value may be null to leave it as-is - * @param audioMuted is the feed's audio muted? - * @param videoMuted is the feed's video muted? + * @param audioMuted - is the feed's audio muted? + * @param videoMuted - is the feed's video muted? */ public setAudioVideoMuted(audioMuted: boolean | null, videoMuted: boolean | null): void { if (audioMuted !== null) { @@ -249,7 +249,7 @@ export class CallFeed extends TypedEventEmitter /** * Starts emitting volume_changed events where the emitter value is in decibels - * @param enabled emit volume changes + * @param enabled - emit volume changes */ public measureVolumeActivity(enabled: boolean): void { if (enabled) { diff --git a/src/webrtc/groupCall.ts b/src/webrtc/groupCall.ts index 5941b6a37..51e1a0a78 100644 --- a/src/webrtc/groupCall.ts +++ b/src/webrtc/groupCall.ts @@ -63,6 +63,21 @@ export type GroupCallEventHandlerMap = { ) => void; [GroupCallEvent.LocalMuteStateChanged]: (audioMuted: boolean, videoMuted: boolean) => void; [GroupCallEvent.ParticipantsChanged]: (participants: Map>) => void; + /** + * Fires whenever an error occurs when call.js encounters an issue with setting up the call. + *

+ * The error given will have a code equal to either `MatrixCall.ERR_LOCAL_OFFER_FAILED` or + * `MatrixCall.ERR_NO_USER_MEDIA`. `ERR_LOCAL_OFFER_FAILED` is emitted when the local client + * fails to create an offer. `ERR_NO_USER_MEDIA` is emitted when the user has denied access + * to their audio/video hardware. + * @param err - The error raised by MatrixCall. + * @example + * ``` + * matrixCall.on("error", function(err){ + * console.error(err.code, err); + * }); + * ``` + */ [GroupCallEvent.Error]: (error: GroupCallError) => void; }; @@ -302,7 +317,7 @@ export class GroupCall extends TypedEventEmitter< /** * Executes the given callback on all calls in this group call. - * @param f The callback. + * @param f - The callback. */ public forEachCall(f: (call: MatrixCall) => void): void { for (const deviceMap of this.calls.values()) { @@ -512,8 +527,8 @@ export class GroupCall extends TypedEventEmitter< /** * Sets the mute state of the local participants's microphone. - * @param {boolean} muted Whether to mute the microphone - * @returns {Promise} Whether muting/unmuting was successful + * @param muted - Whether to mute the microphone + * @returns Whether muting/unmuting was successful */ public async setMicrophoneMuted(muted: boolean): Promise { // hasAudioDevice can block indefinitely if the window has lost focus, @@ -575,8 +590,8 @@ export class GroupCall extends TypedEventEmitter< /** * Sets the mute state of the local participants's video. - * @param {boolean} muted Whether to mute the video - * @returns {Promise} Whether muting/unmuting was successful + * @param muted - Whether to mute the video + * @returns Whether muting/unmuting was successful */ public async setLocalVideoMuted(muted: boolean): Promise { // hasAudioDevice can block indefinitely if the window has lost focus, @@ -733,8 +748,8 @@ export class GroupCall extends TypedEventEmitter< /** * Determines whether a given participant expects us to call them (versus * them calling us). - * @param userId The participant's user ID. - * @param deviceId The participant's device ID. + * @param userId - The participant's user ID. + * @param deviceId - The participant's device ID. * @returns Whether we need to place an outgoing call to the participant. */ private wantsOutgoingCall(userId: string, deviceId: string): boolean { @@ -1249,9 +1264,9 @@ export class GroupCall extends TypedEventEmitter< /** * Updates the local user's member state with the devices returned by the given function. - * @param fn A function from the current devices to the new devices. If it + * @param fn - A function from the current devices to the new devices. If it * returns null, the update will be skipped. - * @param keepAlive Whether the request should outlive the window. + * @param keepAlive - Whether the request should outlive the window. */ private async updateDevices( fn: (devices: IGroupCallRoomMemberDevice[]) => IGroupCallRoomMemberDevice[] | null, diff --git a/src/webrtc/mediaHandler.ts b/src/webrtc/mediaHandler.ts index c7c84876b..46943ae38 100644 --- a/src/webrtc/mediaHandler.ts +++ b/src/webrtc/mediaHandler.ts @@ -67,7 +67,7 @@ export class MediaHandler extends TypedEventEmitter< /** * Set an audio input device to use for MatrixCalls - * @param {string} deviceId the identifier for the device + * @param deviceId - the identifier for the device * undefined treated as unset */ public async setAudioInput(deviceId: string): Promise { @@ -81,7 +81,7 @@ export class MediaHandler extends TypedEventEmitter< /** * Set audio settings for MatrixCalls - * @param {AudioSettings} opts audio options to set + * @param opts - audio options to set */ public async setAudioSettings(opts: AudioSettings): Promise { logger.info("Setting audio settings to", opts); @@ -92,7 +92,7 @@ export class MediaHandler extends TypedEventEmitter< /** * Set a video input device to use for MatrixCalls - * @param {string} deviceId the identifier for the device + * @param deviceId - the identifier for the device * undefined treated as unset */ public async setVideoInput(deviceId: string): Promise { @@ -106,8 +106,8 @@ export class MediaHandler extends TypedEventEmitter< /** * Set media input devices to use for MatrixCalls - * @param {string} audioInput the identifier for the audio device - * @param {string} videoInput the identifier for the video device + * @param audioInput - the identifier for the audio device + * @param videoInput - the identifier for the video device * undefined treated as unset */ public async setMediaInputs(audioInput: string, videoInput: string): Promise { @@ -191,10 +191,10 @@ export class MediaHandler extends TypedEventEmitter< } /** - * @param audio should have an audio track - * @param video should have a video track - * @param reusable is allowed to be reused by the MediaHandler - * @returns {MediaStream} based on passed parameters + * @param audio - should have an audio track + * @param video - should have a video track + * @param reusable - is allowed to be reused by the MediaHandler + * @returns based on passed parameters */ public async getUserMediaStream(audio: boolean, video: boolean, reusable = true): Promise { const shouldRequestAudio = audio && await this.hasAudioDevice(); @@ -296,9 +296,9 @@ export class MediaHandler extends TypedEventEmitter< } /** - * @param desktopCapturerSourceId sourceId for Electron DesktopCapturer - * @param reusable is allowed to be reused by the MediaHandler - * @returns {MediaStream} based on passed parameters + * @param desktopCapturerSourceId - sourceId for Electron DesktopCapturer + * @param reusable - is allowed to be reused by the MediaHandler + * @returns based on passed parameters */ public async getScreensharingStream(opts: IScreensharingOpts = {}, reusable = true): Promise { let stream: MediaStream; diff --git a/yarn.lock b/yarn.lock index b96adf0ef..9a2f14794 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1093,6 +1093,15 @@ uuid "8.3.2" xml "1.0.1" +"@es-joy/jsdoccomment@~0.36.1": + version "0.36.1" + resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.36.1.tgz#c37db40da36e4b848da5fd427a74bae3b004a30f" + integrity sha512-922xqFsTpHs6D0BUiG4toiyPOMc8/jafnWKxz1KWgS4XzKPy2qXf1Pe6UFuNSCQqt6tOuhAWXBNuuyUhJmw9Vg== + dependencies: + comment-parser "1.3.1" + esquery "^1.4.0" + jsdoc-type-pratt-parser "~3.1.0" + "@eslint-community/eslint-utils@^4.1.0": version "4.1.2" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.1.2.tgz#14ca568ddaa291dd19a4a54498badc18c6cfab78" @@ -1427,6 +1436,21 @@ version "3.2.14" resolved "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz#acd96c00a881d0f462e1f97a56c73742c8dbc984" +"@microsoft/tsdoc-config@0.16.2": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz#b786bb4ead00d54f53839a458ce626c8548d3adf" + integrity sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw== + dependencies: + "@microsoft/tsdoc" "0.14.2" + ajv "~6.12.6" + jju "~1.4.0" + resolve "~1.19.0" + +"@microsoft/tsdoc@0.14.2": + version "0.14.2" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz#c3ec604a0b54b9a9b87e9735dfc59e1a5da6a5fb" + integrity sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug== + "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": version "2.1.8-no-fsevents.3" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" @@ -1781,7 +1805,7 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.6.0": +"@typescript-eslint/eslint-plugin@^5.45.0": version "5.45.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz#ffa505cf961d4844d38cfa19dcec4973a6039e41" integrity sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA== @@ -1796,7 +1820,7 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.6.0": +"@typescript-eslint/parser@^5.45.0": version "5.45.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.45.0.tgz#b18a5f6b3cf1c2b3e399e9d2df4be40d6b0ddd0e" integrity sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ== @@ -1948,7 +1972,7 @@ agent-base@6: dependencies: debug "4" -ajv@^6.10.0, ajv@^6.12.4: +ajv@^6.10.0, ajv@^6.12.4, ajv@~6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2757,6 +2781,11 @@ commander@^4.0.1: resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== +comment-parser@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.3.1.tgz#3d7ea3adaf9345594aedee6563f422348f165c1b" + integrity sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -3338,11 +3367,32 @@ eslint-plugin-import@^2.26.0: resolve "^1.22.0" tsconfig-paths "^3.14.1" +eslint-plugin-jsdoc@^39.6.4: + version "39.6.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.6.4.tgz#b940aebd3eea26884a0d341785d2dc3aba6a38a7" + integrity sha512-fskvdLCfwmPjHb6e+xNGDtGgbF8X7cDwMtVLAP2WwSf9Htrx68OAx31BESBM1FAwsN2HTQyYQq7m4aW4Q4Nlag== + dependencies: + "@es-joy/jsdoccomment" "~0.36.1" + comment-parser "1.3.1" + debug "^4.3.4" + escape-string-regexp "^4.0.0" + esquery "^1.4.0" + semver "^7.3.8" + spdx-expression-parse "^3.0.1" + eslint-plugin-matrix-org@^0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-0.8.0.tgz#daa1396900a8cb1c1d88f1a370e45fc32482cd9e" integrity sha512-/Poz/F8lXYDsmQa29iPSt+kO+Jn7ArvRdq10g0CCk8wbRS0sb2zb6fvd9xL1BgR5UDQL771V0l8X32etvY5yKA== +eslint-plugin-tsdoc@^0.2.17: + version "0.2.17" + resolved "https://registry.yarnpkg.com/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.17.tgz#27789495bbd8778abbf92db1707fec2ed3dfe281" + integrity sha512-xRmVi7Zx44lOBuYqG8vzTXuL6IdGOeF9nHX17bjJ8+VE6fsxpdGem0/SBTmAwgYMKYB1WBkqRJVQ+n8GK041pA== + dependencies: + "@microsoft/tsdoc" "0.14.2" + "@microsoft/tsdoc-config" "0.16.2" + eslint-plugin-unicorn@^45.0.0: version "45.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-45.0.1.tgz#2307f4620502fd955c819733ce1276bed705b736" @@ -4156,7 +4206,7 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.10.0, is-core-module@^2.8.1, is-core-module@^2.9.0: +is-core-module@^2.1.0, is-core-module@^2.10.0, is-core-module@^2.8.1, is-core-module@^2.9.0: version "2.11.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== @@ -4809,6 +4859,11 @@ jest@^29.0.0: import-local "^3.0.2" jest-cli "^29.3.1" +jju@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" + integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA== + js-sdsl@^4.1.4: version "4.1.5" resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.1.5.tgz#1ff1645e6b4d1b028cd3f862db88c9d887f26e2a" @@ -4839,6 +4894,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsdoc-type-pratt-parser@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz#a4a56bdc6e82e5865ffd9febc5b1a227ff28e67e" + integrity sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw== + jsdom@^20.0.0: version "20.0.2" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-20.0.2.tgz#65ccbed81d5e877c433f353c58bb91ff374127db" @@ -5568,7 +5628,7 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.7: +path-parse@^1.0.6, path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -6119,6 +6179,14 @@ resolve@^1.1.4, resolve@^1.1.6, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.17. path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@~1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" + integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== + dependencies: + is-core-module "^2.1.0" + path-parse "^1.0.6" + retry@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" @@ -6344,7 +6412,7 @@ spdx-exceptions@^2.1.0: resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== -spdx-expression-parse@^3.0.0: +spdx-expression-parse@^3.0.0, spdx-expression-parse@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==