Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Please see LICENSE in the repository root for full details.
`;

module.exports = {
plugins: ["matrix-org", "rxjs"],
plugins: ["matrix-org", "rxjs", "jsdoc"],
extends: [
"plugin:matrix-org/react",
"plugin:matrix-org/a11y",
Expand All @@ -26,6 +26,13 @@ module.exports = {
node: true,
},
rules: {
"jsdoc/no-types": "error",
"jsdoc/empty-tags": "error",
"jsdoc/check-property-names": "error",
"jsdoc/check-values": "error",
"jsdoc/check-param-names": "warn",
// "jsdoc/require-param": "warn",
"jsdoc/require-param-description": "warn",
"matrix-org/require-copyright-header": ["error", COPYRIGHT_HEADER],
"jsx-a11y/media-has-caption": "off",
"react/display-name": "error",
Expand Down Expand Up @@ -75,6 +82,23 @@ module.exports = {
"no-console": ["error"],
},
},
{
files: [
"**/*.test.ts",
"**/*.test.tsx",
"**/test.ts",
"**/test.tsx",
"**/test-**",
],
rules: {
"jsdoc/no-types": "off",
"jsdoc/empty-tags": "off",
"jsdoc/check-property-names": "off",
"jsdoc/check-values": "off",
"jsdoc/check-param-names": "off",
"jsdoc/require-param-description": "off",
},
},
],
settings: {
react: {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
"eslint-config-prettier": "^10.0.0",
"eslint-plugin-deprecate": "^0.8.2",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsdoc": "^61.5.0",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-matrix-org": "2.1.0",
"eslint-plugin-react": "^7.29.4",
Expand Down
1 change: 0 additions & 1 deletion playwright/fixtures/widget-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ const CONFIG_JSON = {

/**
* Set the Element Call URL in the dev tool settings using `window.mxSettingsStore` via `page.evaluate`.
* @param page
*/
const setDevToolElementCallDevUrl = process.env.USE_DOCKER
? async (page: Page): Promise<void> => {
Expand Down
4 changes: 2 additions & 2 deletions src/e2ee/sharedKeyManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ const getRoomSharedKeyLocalStorageKey = (roomId: string): string =>
`room-shared-key-${roomId}`;

/**
* An upto-date shared key for the room. Either from local storage or the value from `setInitialValue`.
* @param roomId
* An up-to-date shared key for the room. Either from local storage or the value from `setInitialValue`.
* @param roomId The room ID we want the shared key for.
* @param setInitialValue The value we get from the URL. The hook will overwrite the local storage value with this.
* @returns [roomSharedKey, setRoomSharedKey] like a react useState hook.
*/
Expand Down
6 changes: 5 additions & 1 deletion src/livekit/MatrixAudioRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,11 @@ interface StereoPanAudioTrackProps {
* It main purpose is to remount the AudioTrack component when switching from
* audioContext to normal audio playback.
* As of now the AudioTrack component does not support adding audio nodes while being mounted.
* @param param0
* @param props The component props
* @param props.trackRef The track reference
* @param props.muted If the track should be muted
* @param props.audioContext The audio context to use
* @param props.audioNodes The audio nodes to use
* @returns
*/
function AudioTrackWithAudioNodes({
Expand Down
6 changes: 3 additions & 3 deletions src/livekit/openIDSFU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ export type OpenIDClientParts = Pick<
* Gets a bearer token from the homeserver and then use it to authenticate
* to the matrix RTC backend in order to get acces to the SFU.
* It has built-in retry for calls to the homeserver with a backoff policy.
* @param client
* @param serviceUrl
* @param matrixRoomId
* @param client The Matrix client
* @param serviceUrl The URL of the livekit SFU service
* @param matrixRoomId The Matrix room ID for which to get the SFU config
* @returns Object containing the token information
* @throws FailToGetOpenIdToken
*/
Expand Down
6 changes: 3 additions & 3 deletions src/reactions/ReactionsReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,10 @@ export class ReactionsReader {
}

/**
* Fetchest any hand wave reactions by the given sender on the given
* Fetches any hand wave reactions by the given sender on the given
* membership event.
* @param membershipEventId
* @param expectedSender
* @param membershipEventId - The user membership event id.
* @param expectedSender - The expected sender of the reaction.
* @returns A MatrixEvent if one was found.
*/
private getLastReactionEvent(
Expand Down
16 changes: 6 additions & 10 deletions src/room/useLoadGroupCall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,22 +106,18 @@ async function joinRoomAfterInvite(

export class CallTerminatedMessage extends Error {
/**
* Creates a new CallTerminatedMessage.
*
* @param icon The icon to display with the message
* @param messageTitle The title of the call ended screen message (translated)
* @param messageBody The message explaining the kind of termination
* (kick, ban, knock reject, etc.) (translated)
* @param reason The user-provided reason for the termination (kick/ban)
*/
public constructor(
/**
* The icon to display with the message.
*/
public readonly icon: ComponentType<SVGAttributes<SVGElement>>,
messageTitle: string,
/**
* The message explaining the kind of termination (kick, ban, knock reject,
* etc.) (translated)
*/
public readonly messageBody: string,
/**
* The user-provided reason for the termination (kick/ban)
*/
public readonly reason?: string,
) {
super(messageTitle);
Expand Down
26 changes: 12 additions & 14 deletions src/settings/rageshake.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class ConsoleLogger extends EventEmitter {

/**
* Returns the log lines to flush to disk and empties the internal log buffer
* @return {string} \n delimited log lines
* @return \n delimited log lines
*/
public popLogs(): string {
const logsToFlush = this.logs;
Expand All @@ -109,7 +109,7 @@ class ConsoleLogger extends EventEmitter {

/**
* Returns lines currently in the log buffer without removing them
* @return {string} \n delimited log lines
* @return \n delimited log lines
*/
public peekLogs(): string {
return this.logs;
Expand Down Expand Up @@ -139,7 +139,7 @@ class IndexedDBLogStore {
}

/**
* @return {Promise} Resolves when the store is ready.
* @return Resolves when the store is ready.
*/
public async connect(): Promise<void> {
const req = this.indexedDB.open("logs");
Expand Down Expand Up @@ -219,7 +219,7 @@ class IndexedDBLogStore {
* This guarantees that we will always eventually do a flush when flush() is
* called.
*
* @return {Promise} Resolved when the logs have been flushed.
* @return Resolved when the logs have been flushed.
*/
public flush = async (): Promise<void> => {
// check if a flush() operation is ongoing
Expand Down Expand Up @@ -270,7 +270,7 @@ class IndexedDBLogStore {
* returned are deleted at the same time, so this can be called at startup
* to do house-keeping to keep the logs from growing too large.
*
* @return {Promise<Object[]>} Resolves to an array of objects. The array is
* @return Resolves to an array of objects. The array is
* sorted in time (oldest first) based on when the log file was created (the
* log ID). The objects have said log ID in an "id" field and "lines" which
* is a big string with all the new-line delimited logs.
Expand Down Expand Up @@ -421,12 +421,12 @@ class IndexedDBLogStore {

/**
* 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<T[]>} Resolves to an array of whatever you returned from
* @return Resolves to an array of whatever you returned from
* resultMapper.
*/
async function selectQuery<T>(
Expand Down Expand Up @@ -464,9 +464,7 @@ declare global {
/**
* Configure rage shaking support for sending bug reports.
* Modifies globals.
* @param {boolean} setUpPersistence When true (default), the persistence will
* be set up immediately for the logs.
* @return {Promise} Resolves when set up.
* @return Resolves when set up.
*/
export async function init(): Promise<void> {
global.mx_rage_logger = new ConsoleLogger();
Expand Down Expand Up @@ -503,7 +501,7 @@ export async function init(): Promise<void> {
/**
* Try to start up the rageshake storage for logs. If not possible (client unsupported)
* then this no-ops.
* @return {Promise} Resolves when complete.
* @return Resolves when complete.
*/
async function tryInitStorage(): Promise<void> {
if (global.mx_rage_initStoragePromise) {
Expand Down Expand Up @@ -536,7 +534,7 @@ async function tryInitStorage(): Promise<void> {
/**
* Get a recent snapshot of the logs, ready for attaching to a bug report
*
* @return {LogEntry[]} list of log data
* @return list of log data
*/
export async function getLogsForReport(): Promise<LogEntry[]> {
if (!global.mx_rage_logger) {
Expand Down
2 changes: 1 addition & 1 deletion src/state/CallViewModel/CallNotificationLifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export interface Props {
localUser: { deviceId: string; userId: string };
}
/**
* @returns {callPickupState$, autoLeave$}
* @returns two observables:
* `callPickupState$` The current call pickup state of the call.
* - "unknown": The client has not yet sent the notification event. We don't know if it will because it first needs to send its own membership.
* Then we can conclude if we were the first one to join or not.
Expand Down
19 changes: 15 additions & 4 deletions src/state/CallViewModel/localMember/LocalMember.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,16 @@ interface Props {
* We want
* - a publisher
* -
* @param param0
* @param props The properties required to create the local membership.
* @param props.scope The observable scope to use.
* @param props.connectionManager The connection manager to get connections from.
* @param props.createPublisherFactory Factory to create a publisher once we have a connection.
* @param props.joinMatrixRTC Callback to join the matrix RTC session once we have a transport.
* @param props.homeserverConnected The homeserver connected state.
* @param props.localTransport$ The local transport to use for publishing.
* @param props.logger The logger to use.
* @param props.muteStates The mute states for video and audio.
* @param props.matrixRTCSession The matrix RTC session to join.
Comment on lines +141 to +150
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For what it's worth I think we should stick to putting these kinds of comments in the interface definition rather than on the function, generally. It's a little easier to pull up the docs for each property while writing a function call that way.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it feels a bit strange to me also, but I am not familiar with js doc.
It looks like lint requires them because we are doing destructuring/unpacking of the arguments in the signature.

* @returns
* - publisher: The handle to create tracks and publish them to the room.
* - connected$: the current connection state. Including matrix server and livekit server connection. (only considering the livekit server we are using for our own media publication)
Expand Down Expand Up @@ -676,9 +685,11 @@ interface EnterRTCSessionOptions {
* - Delay events management
* - Handles retries (fails only after several attempts)
*
* @param rtcSession
* @param transport
* @param options
* @param rtcSession - The MatrixRTCSession to join.
* @param transport - The LivekitTransport to use for this session.
* @param options - Options for entering the RTC session.
* @param options.encryptMedia - Whether to encrypt media.
* @param options.matrixRTCMode - The Matrix RTC mode to use.
* @throws If the widget could not send ElementWidgetActions.JoinCall action.
*/
// Exported for unit testing
Expand Down
5 changes: 2 additions & 3 deletions src/state/CallViewModel/localMember/Publisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export class Publisher {
this.logger.debug("createAndSetupTracks called");
const lkRoom = this.connection.livekitRoom;
// Observe mute state changes and update LiveKit microphone/camera states accordingly
this.observeMuteStates(this.scope);
this.observeMuteStates();

// Check if audio and/or video is enabled. We only create tracks if enabled,
// because it could prompt for permission, and we don't want to do that unnecessarily.
Expand Down Expand Up @@ -356,10 +356,9 @@ export class Publisher {

/**
* Observe changes in the mute states and update the LiveKit room accordingly.
* @param scope
* @private
*/
private observeMuteStates(scope: ObservableScope): void {
private observeMuteStates(): void {
const lkRoom = this.connection.livekitRoom;
this.muteStates.audio.setHandler(async (enable) => {
try {
Expand Down
2 changes: 1 addition & 1 deletion src/state/CallViewModel/remoteMembers/Connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ export class Connection {
*
* @param opts - Connection options {@link ConnectionOpts}.
*
* @param logger
* @param logger - The logger to use.
*/
public constructor(opts: ConnectionOpts, logger: Logger) {
this.logger = logger.getChild("[Connection]");
Expand Down
4 changes: 2 additions & 2 deletions src/state/CallViewModel/remoteMembers/ConnectionFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ export class ECConnectionFactory implements ConnectionFactory {
* @param client - The OpenID client parts for authentication, needed to get openID and JWT tokens.
* @param devices - Used for video/audio out/in capture options.
* @param processorState$ - Effects like background blur (only for publishing connection?)
* @param livekitKeyProvider
* @param livekitKeyProvider - Optional key provider for end-to-end encryption.
* @param controlledAudioDevices - Option to indicate whether audio output device is controlled externally (native mobile app).
* @param livekitRoomFactory - Optional factory function (for testing) to create LivekitRoom instances. If not provided, a default factory is used.
* @param echoCancellation - Whether to enable echo cancellation for audio capture.
* @param noiseSuppression - Whether to enable noise suppression for audio capture.
* @param livekitRoomFactory - Optional factory function (for testing) to create LivekitRoom instances. If not provided, a default factory is used.
*/
public constructor(
private client: OpenIDClientParts,
Expand Down
8 changes: 5 additions & 3 deletions src/state/CallViewModel/remoteMembers/ConnectionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ export interface IConnectionManager {

/**
* Crete a `ConnectionManager`
* @param scope the observable scope used by this object.
* @param connectionFactory used to create new connections.
* @param _transportsSubscriptions$ A list of Behaviors each containing a LIST of LivekitTransport.
* @param props - Configuration object
* @param props.scope - The observable scope used by this object
* @param props.connectionFactory - Used to create new connections
* @param props.inputTransports$ - A list of Behaviors each containing a LIST of LivekitTransport.
* @param props.logger - The logger to use
* Each of these behaviors can be interpreted as subscribed list of transports.
*
* Using `registerTransports` independent external modules can control what connections
Expand Down
11 changes: 8 additions & 3 deletions src/useAudioContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ import * as controls from "./controls";
* Play a sound though a given AudioContext. Will take
* care of connecting the correct buffer and gating
* through gain.
* @param volume The volume to play at.
* @param ctx The context to play through.
* @param buffer The buffer to play.
* @param volume The volume to play at.
* @param stereoPan The stereo pan to apply.
* @param delayS Delay in seconds before starting playing.
* @param abort Optional AbortController that can be used to stop playback.
* @returns A promise that resolves when the sound has finished playing.
*/
async function playSound(
Expand Down Expand Up @@ -55,9 +58,11 @@ async function playSound(
* Play a sound though a given AudioContext, looping until stopped. Will take
* care of connecting the correct buffer and gating
* through gain.
* @param volume The volume to play at.
* @param ctx The context to play through.
* @param buffer The buffer to play.
* @param volume The volume to play at.
* @param stereoPan The stereo pan to apply.
* @param delayS Delay in seconds between each loop.
* @returns A function used to end the sound. This function will return a promise when the sound has stopped.
*/
function playSoundLooping(
Expand Down Expand Up @@ -120,7 +125,7 @@ interface UseAudioContext<S extends string> {
/**
* Add an audio context which can be used to play
* a set of preloaded sounds.
* @param props
* @param props The properties for the audio context.
* @returns Either an instance that can be used to play sounds, or null if not ready.
*/
export function useAudioContext<S extends string>(
Expand Down
7 changes: 7 additions & 0 deletions src/utils/displayname.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ export function shouldDisambiguate(
);
}

/**
* Calculates a display name for a member, optionally disambiguating it.
* @param member - The member to calculate the display name for.
* @param member.rawDisplayName - The raw display name of the member
* @param member.userId - The user ID of the member
* @param disambiguate - Whether to disambiguate the display name.
*/
export function calculateDisplayName(
member: { rawDisplayName?: string; userId: string },
disambiguate: boolean,
Expand Down
Loading