diff --git a/README.md b/README.md index 455b2fa897..86a30425de 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,20 @@ Test credentials: Installation and usage documentation could be found here [EmbeddedChat installation and usage](https://rocketchat.github.io/EmbeddedChat/docs/docs/Usage/embeddedchat_setup) +### Matrix Support (Experimental) + +EmbeddedChat now supports connecting to a Matrix homeserver. + +To use Matrix mode, set the `mode` prop to `'matrix'` and provide the `host` and `roomId`. + +```jsx + +``` + ## Development ### Local Setup diff --git a/packages/api/package.json b/packages/api/package.json index a05ca8e630..6d18201304 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -24,6 +24,7 @@ }, "dependencies": { "@embeddedchat/auth": "workspace:^", - "@rocket.chat/sdk": "^1.0.0-alpha.42" + "@rocket.chat/sdk": "^1.0.0-alpha.42", + "matrix-js-sdk": "^39.3.0-rc.0" } } diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts index 46690e24e6..1995d6fb49 100644 --- a/packages/api/src/EmbeddedChatApi.ts +++ b/packages/api/src/EmbeddedChatApi.ts @@ -6,10 +6,11 @@ import { RocketChatAuth, ApiError, } from "@embeddedchat/auth"; +import { IChatProvider } from "./IChatProvider"; // mutliple typing status can come at the same time they should be processed in order. let typingHandlerLock = 0; -export default class EmbeddedChatApi { +export default class EmbeddedChatApi implements IChatProvider { host: string; rid: string; rcClient: Rocketchat; diff --git a/packages/api/src/IChatProvider.ts b/packages/api/src/IChatProvider.ts new file mode 100644 index 0000000000..5b86764564 --- /dev/null +++ b/packages/api/src/IChatProvider.ts @@ -0,0 +1,34 @@ +import { RocketChatAuth } from "@embeddedchat/auth"; + +export interface IChatProvider { + sendTypingStatus(username: string, typing: boolean): Promise; + + addMessageListener(callback: (message: any) => void): void; + removeMessageListener(callback: (message: any) => void): void; + addMessageDeleteListener(callback: (messageId: string) => void): void; + removeMessageDeleteListener(callback: (messageId: string) => void): void; + addTypingStatusListener(callback: (users: string[]) => void): void; + removeTypingStatusListener(callback: (users: string[]) => void): void; + addActionTriggeredListener(callback: (data: any) => void): void; + removeActionTriggeredListener(callback: (data: any) => void): void; + addUiInteractionListener(callback: (data: any) => void): void; + removeUiInteractionListener(callback: (data: any) => void): void; + + login(userOrEmail: string, password: string, code?: string): Promise; + logout(): Promise; + autoLogin(auth: { + flow: "PASSWORD" | "OAUTH" | "TOKEN"; + credentials: any; + }): Promise; + googleSSOLogin(signIn: Function, acsCode: string): Promise; + + getRCAppInfo(): Promise; + updateUserUsername(userid: string, username: string): Promise; + channelInfo(): Promise; + getRoomInfo(): Promise; + permissionInfo(): Promise; + + setAuth(auth: RocketChatAuth): void; + getAuth(): RocketChatAuth; + getHost(): string; +} diff --git a/packages/api/src/MatrixProvider.ts b/packages/api/src/MatrixProvider.ts new file mode 100644 index 0000000000..3da5eaca30 --- /dev/null +++ b/packages/api/src/MatrixProvider.ts @@ -0,0 +1,569 @@ +import * as sdk from "matrix-js-sdk"; +import { IChatProvider } from "./IChatProvider"; +import { RocketChatAuth } from "@embeddedchat/auth"; + +class MatrixAuth extends RocketChatAuth { + private onAuthChangeCb: ((user: any) => void) | null = null; + currentUser: any | null = null; + + constructor(config: any) { + super(config); + } + + async onAuthChange(cb: (user: any) => void): Promise { + this.onAuthChangeCb = cb; + if (this.currentUser) { + cb(this.currentUser); + } + } + + notifyAuthChange(user: any) { + this.currentUser = user; + if (this.onAuthChangeCb) { + this.onAuthChangeCb(user); + } + } +} + +export default class MatrixProvider implements IChatProvider { + private client: any; + private host: string; + private roomId: string; + private auth: MatrixAuth; + private onMessageCallbacks: ((message: any) => void)[] = []; + + constructor(host: string, roomId: string) { + this.host = host; + this.roomId = roomId; + this.auth = new MatrixAuth({ + host: this.host, + deleteToken: async () => {}, + getToken: async () => "", + saveToken: async () => {}, + }); + } + + async connect(): Promise { + if (!this.client) { + this.client = sdk.createClient({ + baseUrl: this.host, + }); + } + + // Map Matrix events to EmbeddedChat callbacks + this.client.removeAllListeners("Room.timeline"); + this.client.on( + "Room.timeline", + (event: any, room: any, toStartOfTimeline: boolean) => { + // Ignore historical messages to prevent duplicates + if (toStartOfTimeline) { + return; + } + if ( + event.getType() !== "m.room.message" && + event.getType() !== "m.room.encrypted" + ) { + return; + } + if (room.roomId !== this.roomId) { + return; + } + + const isEncrypted = event.getType() === "m.room.encrypted"; + const text = isEncrypted + ? "⚠️ [Encrypted Message]" + : event.getContent().body; + + // Get display name from room member + const senderId = event.getSender(); + const member = room.getMember(senderId); + const displayName = member?.name || senderId; + + // Convert Matrix event to RC message format + const message = { + _id: event.getId(), + msg: text, + md: [ + { + type: "PARAGRAPH", + value: [ + { + type: "PLAIN_TEXT", + value: text, + }, + ], + }, + ], + ts: new Date(event.getTs()).toISOString(), + u: { + _id: senderId, + username: displayName, + name: displayName, + }, + rid: room.roomId, + }; + + this.onMessageCallbacks.forEach((cb) => cb(message)); + } + ); + + if (!this.client.clientRunning) { + await this.client.startClient({ initialSyncLimit: 10 }); + } + + await new Promise((resolve) => { + if (!this.client) { + resolve(); + return; + } + const state = this.client.getSyncState(); + if (state === "PREPARED" || state === "SYNCING") { + resolve(); + } else { + const checkSync = (state: any) => { + if (state === "PREPARED" || state === "SYNCING") { + if (this.client) { + this.client.removeListener("Sync", checkSync); + } + resolve(); + } + }; + this.client.on("Sync", checkSync); + + // Timeout after 5 seconds to prevent hanging + setTimeout(() => { + if (this.client) { + this.client.removeListener("Sync", checkSync); + } + resolve(); + }, 5000); + } + }); + + if (!this.client) { + console.log("Matrix: client became null during sync wait"); + return; + } + + let room = this.client.getRoom(this.roomId); + if (!room) { + try { + await this.client.joinRoom(this.roomId); + + // Wait for room to appear in store + let retries = 0; + while (!room && retries < 20 && this.client) { + await new Promise((r) => setTimeout(r, 1000)); + room = this.client?.getRoom(this.roomId); + retries++; + } + } catch (error) { + console.error( + `MatrixProvider: Failed to join room ${this.roomId}`, + error + ); + } + } + } + + async login( + userOrEmail: string, + password: string, + code?: string + ): Promise { + if (!this.client) { + this.client = sdk.createClient({ + baseUrl: this.host, + }); + } + + try { + const response = await this.client.login("m.login.password", { + identifier: { + type: "m.id.user", + user: userOrEmail, + }, + password: password, + }); + + // Ensure we connect (start client and sync) after login + await this.connect(); + + const user = { + username: response.user_id, + _id: response.user_id, + name: response.user_id, + avatarUrl: "", // Placeholder + roles: [], + }; + + // Notify auth change to update UI + this.auth.notifyAuthChange({ me: user }); + + return { status: "success", me: user }; + } catch (error: any) { + // Return error in Rocket.Chat format for toast notifications + console.error("Matrix login failed:", error); + return { + error: error.httpStatus === 403 ? 403 : "Unauthorized", + message: error.message || "Invalid username or password", + }; + } + } + + async close(): Promise { + if (this.client) { + this.client.stopClient(); + } + this.auth.notifyAuthChange(null); + } + + async getStarredMessages(): Promise { + return { messages: [] }; + } + + async getAllFiles(): Promise { + return { files: [] }; + } + + async getMessages( + anonymousMode: boolean, + options?: any, + isChannelPrivate?: boolean + ): Promise { + if (!this.client) return { messages: [], count: 0 }; + const room = this.client.getRoom(this.roomId); + if (!room) { + return { messages: [], count: 0 }; + } + + const events = room.getLiveTimeline().getEvents(); + + // Reverse events to match Rocket.Chat's newest-first expectation + const messages = events + .slice() // Create a copy before reversing + .reverse() + .filter( + (event: any) => + event.getType() === "m.room.message" || + event.getType() === "m.room.encrypted" + ) + .map((event: any) => { + const isEncrypted = event.getType() === "m.room.encrypted"; + const text = isEncrypted + ? "⚠️ [Encrypted Message]" + : event.getContent().body; + + // Get display name from room member + const senderId = event.getSender(); + const member = room.getMember(senderId); + const displayName = member?.name || senderId; + + return { + _id: event.getId(), + msg: text, + md: [ + { + type: "PARAGRAPH", + value: [ + { + type: "PLAIN_TEXT", + value: text, + }, + ], + }, + ], + ts: new Date(event.getTs()).toISOString(), + u: { + _id: senderId, + username: displayName, + name: displayName, + }, + rid: room.roomId, + }; + }); + + return { messages, count: messages.length, success: true }; + } + + async channelInfo(): Promise { + if (!this.client) { + return { + success: false, + errorType: "error-room-not-found", + error: "Not connected to Matrix server", + }; + } + const room = this.client.getRoom(this.roomId); + if (!room) { + return { + success: false, + errorType: "error-room-not-found", + error: `Room ${this.roomId} not found`, + }; + } + return { + success: true, + room: { + _id: room.roomId, + name: room.name || "Matrix Room", + t: "c", + }, + }; + } + + async getRoomInfo(): Promise { + if (!this.client) { + return { + success: false, + errorType: "error-room-not-found", + error: "Not connected to Matrix server", + }; + } + const room = this.client.getRoom(this.roomId); + if (!room) { + return { + success: false, + errorType: "error-room-not-found", + error: `Room ${this.roomId} not found`, + }; + } + return { + success: true, + room: { + _id: room.roomId, + name: room.name, + t: "c", + }, + }; + } + + async sendMessage(message: any, threadId?: string): Promise { + const content = { + msgtype: "m.text", + body: typeof message === "string" ? message : message.msg, + }; + try { + const response = await this.client.sendEvent( + this.roomId, + "m.room.message", + content + ); + return { success: true, message: { _id: response.event_id } }; + } catch (error: any) { + console.error("Matrix sendMessage failed:", error); + return { success: false, error: error.message }; + } + } + + async getOlderMessages( + anonymousMode: boolean, + options?: any, + isChannelPrivate?: boolean + ): Promise { + return { messages: [] }; + } + + async getThreadMessages( + tmid: string, + isChannelPrivate?: boolean + ): Promise { + return { messages: [] }; + } + + async deleteMessage(msgId: string): Promise { + // Matrix message deletion not implemented + return { + success: false, + error: "Message deletion not supported in Matrix mode", + }; + } + + async updateMessage(msgId: string, text: string): Promise { + // Matrix message editing not implemented + return { + success: false, + error: "Message editing not supported in Matrix mode", + }; + } + + async starMessage(msgId: string): Promise { + // Matrix doesn't have native starring - could use room account data + return { success: true }; // Silently succeed for now + } + + async unstarMessage(msgId: string): Promise { + return { success: true }; + } + + async pinMessage(msgId: string): Promise { + // Matrix has m.room.pinned_events state event + return { success: true }; // Stub for now + } + + async unpinMessage(msgId: string): Promise { + return { success: true }; + } + + async reactToMessage( + emoji: string, + msgId: string, + shouldReact: boolean + ): Promise { + // Matrix supports reactions via m.reaction + return { success: true }; // Stub for now + } + + async getChannelRoles(isChannelPrivate?: boolean): Promise { + return []; + } + + async getUsersInRole(role: string): Promise { + return []; + } + + async getUserRoles(): Promise { + return []; + } + + async sendTypingStatus(username: string, typing: boolean): Promise { + await this.client.sendTyping(this.roomId, typing, 3000); + } + + addMessageListener(callback: (message: any) => void): void { + this.onMessageCallbacks.push(callback); + } + + removeMessageListener(callback: (message: any) => void): void { + this.onMessageCallbacks = this.onMessageCallbacks.filter( + (c) => c !== callback + ); + } + + addMessageDeleteListener(callback: (messageId: string) => void): void {} + + removeMessageDeleteListener(callback: (messageId: string) => void): void {} + + addTypingStatusListener(callback: (users: string[]) => void): void {} + + removeTypingStatusListener(callback: (users: string[]) => void): void {} + + addActionTriggeredListener(callback: (data: any) => void): void {} + + removeActionTriggeredListener(callback: (data: any) => void): void {} + + addUiInteractionListener(callback: (data: any) => void): void {} + + removeUiInteractionListener(callback: (data: any) => void): void {} + + async logout(): Promise { + if (this.client) { + await this.client.logout(); + } + this.auth.notifyAuthChange(null); + } + + async autoLogin(auth: { + flow: "PASSWORD" | "OAUTH" | "TOKEN"; + credentials: any; + }): Promise {} + + async googleSSOLogin(signIn: Function, acsCode: string): Promise {} + + async getRCAppInfo(): Promise { + return null; + } + + async updateUserUsername(userid: string, username: string): Promise { + return {}; + } + + async permissionInfo(): Promise { + return []; + } + + setAuth(auth: RocketChatAuth): void { + // We ignore external auth setting for now as we manage our own MatrixAuth + } + + getAuth(): RocketChatAuth { + return this.auth; + } + + getHost(): string { + return this.host; + } + + async getMessageLimit(): Promise { + return { value: 5000 }; // Default limit + } + + // Additional methods for toast compatibility + async reportMessage(messageId: string, description: string): Promise { + // Matrix doesn't have built-in message reporting + return { + success: false, + error: "Message reporting not supported in Matrix mode", + }; + } + + async getSearchMessages(text: string): Promise { + // Matrix search would require server-side search API + return { messages: [] }; + } + + async me(): Promise { + if (!this.client) return {}; + const userId = this.client.getUserId(); + if (!userId) return {}; + return { + _id: userId, + username: userId, + name: userId, + }; + } + + async userData(username: string): Promise { + // Matrix user profile lookup + return { user: null }; + } + + async getUserStatus(userId: string): Promise { + // Matrix presence API + return { status: "online" }; + } + + async findOrCreateInvite(): Promise { + // Matrix room invite link + return { url: "", expires: new Date().toISOString() }; + } + + async getAllImages(): Promise { + return { files: [] }; + } + + async execCommand(command: { + command: string; + params: string; + }): Promise { + // Matrix doesn't have slash commands in the same way + return { success: false, error: "Commands not supported in Matrix mode" }; + } + + async getChannelMembers(isChannelPrivate?: boolean): Promise { + if (!this.client) return { members: [] }; + const room = this.client.getRoom(this.roomId); + if (!room) return { members: [] }; + + const members = room.getJoinedMembers().map((member: any) => ({ + _id: member.userId, + username: member.name || member.userId, + name: member.name || member.userId, + })); + return { members }; + } + + async getCommandsList(): Promise { + return { commands: [] }; + } +} diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index b4ff83a1c6..046d30f34d 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -1 +1,3 @@ export { default as EmbeddedChatApi } from "./EmbeddedChatApi"; +export { default as MatrixProvider } from "./MatrixProvider"; +export * from "./IChatProvider"; diff --git a/packages/react/src/stories/MatrixMode.stories.js b/packages/react/src/stories/MatrixMode.stories.js new file mode 100644 index 0000000000..598d2a645c --- /dev/null +++ b/packages/react/src/stories/MatrixMode.stories.js @@ -0,0 +1,21 @@ +import { EmbeddedChat } from '..'; + +export default { + title: 'EmbeddedChat/Matrix', + component: EmbeddedChat, +}; + +export const MatrixMode = { + args: { + mode: 'matrix', + host: 'https://matrix.org', // Replace with your Matrix homeserver URL + roomId: '', // Replace with a public room ID (e.g., Matrix HQ) + channelName: 'Matrix Room', + headerColor: 'white', + toastBarPosition: 'bottom right', + showRoles: true, + enableThreads: true, + hideHeader: false, + dark: false, + }, +}; diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js index 998e9007cd..fa5b5e1e70 100644 --- a/packages/react/src/views/ChatInput/ChatInput.js +++ b/packages/react/src/views/ChatInput/ChatInput.js @@ -321,7 +321,10 @@ const ChatInput = ({ scrollToBottom }) => { pendingMessage.tmid = threadId; } - upsertMessage(pendingMessage, ECOptions.enableThreads); + // Skip optimistic rendering for Matrix - it provides real-time updates via Room.timeline + if (ECOptions.mode !== 'matrix') { + upsertMessage(pendingMessage, ECOptions.enableThreads); + } const res = await RCInstance.sendMessage( { @@ -333,7 +336,10 @@ const ChatInput = ({ scrollToBottom }) => { if (res.success) { clearQuoteMessages(); - replaceMessage(pendingMessage, res.message); + // In Matrix mode, don't replace - the message will come via Room.timeline + if (ECOptions.mode !== 'matrix') { + replaceMessage(pendingMessage, res.message); + } } }; @@ -348,7 +354,10 @@ const ChatInput = ({ scrollToBottom }) => { message.replace(/\n/g, '\\n') ); if (!res.success) { - handleSendError('Error editing message, login again'); + dispatchToastMessage({ + type: 'error', + message: res.error || 'Message editing not supported', + }); } }; diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js index 5d8c20a600..a930009255 100644 --- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js +++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js @@ -116,6 +116,7 @@ const ChatInputFormattingToolbar = ({ audio: ( formatter.find((item) => item.name === name)) .map((item) => isPopoverOpen && popOverItems.includes('formatter') ? ( - <> + {item.name} - + ) : ( { secure = false, dark = false, remoteOpt = false, + mode = 'rocketchat', // 'rocketchat' or 'matrix' } = config; const hasMounted = useRef(false); @@ -90,6 +91,9 @@ const EmbeddedChat = (props) => { } const initializeRCInstance = useCallback(() => { + if (mode === 'matrix') { + return new MatrixProvider(host, roomId); + } const newRCInstance = new EmbeddedChatApi(host, roomId, { getToken, deleteToken, @@ -97,7 +101,7 @@ const EmbeddedChat = (props) => { }); return newRCInstance; - }, [host, roomId, getToken, deleteToken, saveToken]); + }, [host, roomId, getToken, deleteToken, saveToken, mode]); const [RCInstance, setRCInstance] = useState(() => initializeRCInstance()); @@ -138,7 +142,7 @@ const EmbeddedChat = (props) => { if (user) { RCInstance.connect() .then(() => { - console.log(`Connected to RocketChat ${RCInstance.host}`); + console.log(`Connected to chat provider ${RCInstance.host}`); const { me } = user; setAuthenticatedAvatarUrl(me.avatarUrl); setAuthenticatedUsername(me.username); @@ -198,6 +202,7 @@ const EmbeddedChat = (props) => { showUsername, hideHeader, anonymousMode, + mode, }), [ enableThreads, @@ -214,6 +219,7 @@ const EmbeddedChat = (props) => { showUsername, hideHeader, anonymousMode, + mode, ] ); @@ -288,6 +294,7 @@ EmbeddedChat.propTypes = { style: PropTypes.object, hideHeader: PropTypes.bool, dark: PropTypes.bool, + mode: PropTypes.oneOf(['rocketchat', 'matrix']), }; export default memo(EmbeddedChat); diff --git a/yarn.lock b/yarn.lock index 23b67cfd11..c0d992066c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2293,6 +2293,7 @@ __metadata: dependencies: "@embeddedchat/auth": "workspace:^" "@rocket.chat/sdk": ^1.0.0-alpha.42 + matrix-js-sdk: ^39.3.0-rc.0 parcel: ^2.10.3 rollup: ^3.23.0 rollup-plugin-dts: ^6.0.1 @@ -4600,6 +4601,13 @@ __metadata: languageName: node linkType: hard +"@matrix-org/matrix-sdk-crypto-wasm@npm:^15.3.0": + version: 15.3.0 + resolution: "@matrix-org/matrix-sdk-crypto-wasm@npm:15.3.0" + checksum: 1c84eefd49ccb2e76b3163846409d314a12986e8bc8d42b6342021904b6831efe455925bbc1d8e46c36a1baaf848a0b1763b65cd31cf18d9315e3828a6a8a938 + languageName: node + linkType: hard + "@mdx-js/react@npm:^2.1.5": version: 2.3.0 resolution: "@mdx-js/react@npm:2.3.0" @@ -9482,6 +9490,13 @@ __metadata: languageName: node linkType: hard +"@types/events@npm:^3.0.0": + version: 3.0.3 + resolution: "@types/events@npm:3.0.3" + checksum: 50af9312fab001fd6bd4bb3ff65830f940877e6778de140a92481a0d9bf5f4853d44ec758a8800ef60e0598ac43ed1b5688116a3c65906ae54e989278d6c7c82 + languageName: node + linkType: hard + "@types/express-serve-static-core@npm:^4.17.33": version: 4.17.41 resolution: "@types/express-serve-static-core@npm:4.17.41" @@ -11013,6 +11028,13 @@ __metadata: languageName: node linkType: hard +"another-json@npm:^0.2.0": + version: 0.2.0 + resolution: "another-json@npm:0.2.0" + checksum: b1d27bd5d7a35364ff2e8eb66e65ef9a53f3ab84f7a4ae38495bf14ba0b346654f107487b4f2f247dbe6a22a8fb4ca2a94330738176516b78494e641fce05178 + languageName: node + linkType: hard + "anser@npm:^1.4.9": version: 1.4.10 resolution: "anser@npm:1.4.10" @@ -12096,6 +12118,13 @@ __metadata: languageName: node linkType: hard +"base-x@npm:^5.0.0": + version: 5.0.1 + resolution: "base-x@npm:5.0.1" + checksum: 6e4f847ef842e0a71c6b6020a6ec482a2a5e727f5a98534dbfd5d5a4e8afbc0d1bdf1fd57174b3f0455d107f10a932c3c7710bec07e2878f80178607f8f605c8 + languageName: node + linkType: hard + "base64-js@npm:^1.0.2, base64-js@npm:^1.1.2, base64-js@npm:^1.2.3, base64-js@npm:^1.3.1, base64-js@npm:^1.5.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" @@ -12523,6 +12552,15 @@ __metadata: languageName: node linkType: hard +"bs58@npm:^6.0.0": + version: 6.0.0 + resolution: "bs58@npm:6.0.0" + dependencies: + base-x: ^5.0.0 + checksum: 820334f9513bba6195136dfc9dfbd1f5aded6c7864639f3ee7b63c2d9d6f9f2813b9949b1f6beb9c161237be2a461097444c2ff587c8c3b824fe18878fa22448 + languageName: node + linkType: hard + "bser@npm:2.1.1": version: 2.1.1 resolution: "bser@npm:2.1.1" @@ -13739,7 +13777,7 @@ __metadata: languageName: node linkType: hard -"content-type@npm:~1.0.4, content-type@npm:~1.0.5": +"content-type@npm:^1.0.4, content-type@npm:~1.0.4, content-type@npm:~1.0.5": version: 1.0.5 resolution: "content-type@npm:1.0.5" checksum: 566271e0a251642254cde0f845f9dd4f9856e52d988f4eb0d0dcffbb7a1f8ec98de7a5215fc628f3bce30fe2fb6fd2bc064b562d721658c59b544e2d34ea2766 @@ -19930,6 +19968,13 @@ __metadata: languageName: node linkType: hard +"is-network-error@npm:^1.1.0": + version: 1.3.0 + resolution: "is-network-error@npm:1.3.0" + checksum: 56dc0b8ed9c0bb72202058f172ad0c3121cf68772e8cbba343d3775f6e2ec7877d423cbcea45f4cedcd345de8693de1b52dfe0c6fc15d652c4aa98c2abf0185a + languageName: node + linkType: hard + "is-number-object@npm:^1.0.4": version: 1.0.7 resolution: "is-number-object@npm:1.0.7" @@ -21419,6 +21464,13 @@ __metadata: languageName: node linkType: hard +"jwt-decode@npm:^4.0.0": + version: 4.0.0 + resolution: "jwt-decode@npm:4.0.0" + checksum: 390e2edcb31a92e86c8cbdd1edeea4c0d62acd371f8a8f0a8878e499390c0ecf4c658b365c4e941e4ef37d0170e4ca650aaa49f99a45c0b9695a235b210154b0 + languageName: node + linkType: hard + "keyv@npm:^4.5.3": version: 4.5.4 resolution: "keyv@npm:4.5.4" @@ -22164,6 +22216,13 @@ __metadata: languageName: node linkType: hard +"loglevel@npm:^1.9.2": + version: 1.9.2 + resolution: "loglevel@npm:1.9.2" + checksum: 896c67b90a507bfcfc1e9a4daa7bf789a441dd70d95cd13b998d6dd46233a3bfadfb8fadb07250432bbfb53bf61e95f2520f9b11f9d3175cc460e5c251eca0af + languageName: node + linkType: hard + "loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" @@ -22453,6 +22512,45 @@ __metadata: languageName: node linkType: hard +"matrix-events-sdk@npm:0.0.1": + version: 0.0.1 + resolution: "matrix-events-sdk@npm:0.0.1" + checksum: 18b61a1a2cd9947e5cec4f9332186f5609e3a47c6c6e775b306e9af0e12babcdb2f68459133c4d44ebc5a7e5ee60e7528813dfccb80d8a8b55668338cd81ee49 + languageName: node + linkType: hard + +"matrix-js-sdk@npm:^39.3.0-rc.0": + version: 39.3.0-rc.0 + resolution: "matrix-js-sdk@npm:39.3.0-rc.0" + dependencies: + "@babel/runtime": ^7.12.5 + "@matrix-org/matrix-sdk-crypto-wasm": ^15.3.0 + another-json: ^0.2.0 + bs58: ^6.0.0 + content-type: ^1.0.4 + jwt-decode: ^4.0.0 + loglevel: ^1.9.2 + matrix-events-sdk: 0.0.1 + matrix-widget-api: ^1.14.0 + oidc-client-ts: ^3.0.1 + p-retry: 7 + sdp-transform: ^3.0.0 + unhomoglyph: ^1.0.6 + uuid: 13 + checksum: c3279836d0d30c9ea174140979dabc36ba0772023ee156e138a042e940b33f692738a32ca265f235bd2fb1095746f1b8a635e7eb3234c59de023a6f8b66a3c65 + languageName: node + linkType: hard + +"matrix-widget-api@npm:^1.14.0": + version: 1.15.0 + resolution: "matrix-widget-api@npm:1.15.0" + dependencies: + "@types/events": ^3.0.0 + events: ^3.2.0 + checksum: bd77ade78987ebfd202bae45204f3b43f8d7baa53b7df3910843dfecf8c5d66eada2a644a1a5b0ab5d4307847815b69d9d6c27981c97a0d82417d88ec8df1b8f + languageName: node + linkType: hard + "maxmin@npm:^2.1.0": version: 2.1.0 resolution: "maxmin@npm:2.1.0" @@ -24711,6 +24809,15 @@ __metadata: languageName: node linkType: hard +"oidc-client-ts@npm:^3.0.1": + version: 3.4.1 + resolution: "oidc-client-ts@npm:3.4.1" + dependencies: + jwt-decode: ^4.0.0 + checksum: 3c0298e11a5ae89131c4a0a77699dabc7470e68a7128d19a30321a629e0fb0a777138eb14c0c68e01fd645b56b19b55f26cb2f6a6de2b832e79bdc0eb764a1e1 + languageName: node + linkType: hard + "on-finished@npm:2.4.1": version: 2.4.1 resolution: "on-finished@npm:2.4.1" @@ -25085,6 +25192,15 @@ __metadata: languageName: node linkType: hard +"p-retry@npm:7": + version: 7.1.0 + resolution: "p-retry@npm:7.1.0" + dependencies: + is-network-error: ^1.1.0 + checksum: 5f8b34218d0041adac2d9133e116d18a9ff6e61f55390910cb63dbc9bfb4088de8ce36a6da3dad48878ef1bf9b565b883a2ef5ff4733cb8cc3c8eab82d9b2e6d + languageName: node + linkType: hard + "p-timeout@npm:^3.2.0": version: 3.2.0 resolution: "p-timeout@npm:3.2.0" @@ -28530,6 +28646,15 @@ __metadata: languageName: node linkType: hard +"sdp-transform@npm:^3.0.0": + version: 3.0.0 + resolution: "sdp-transform@npm:3.0.0" + bin: + sdp-verify: checker.js + checksum: a9bd43d7135ec3b0db36cf3a7896abd18ffe19811dd59d4ca271c4ba8ebb679c2fc930708d4b3e8f0a08dbc513d1e888e6971b51ab04cfec5c4c58d6ec895bc6 + languageName: node + linkType: hard + "semver@npm:2 || 3 || 4 || 5, semver@npm:^5.3.0, semver@npm:^5.5.0, semver@npm:^5.6.0, semver@npm:^5.7.1": version: 5.7.2 resolution: "semver@npm:5.7.2" @@ -31110,6 +31235,13 @@ __metadata: languageName: node linkType: hard +"unhomoglyph@npm:^1.0.6": + version: 1.0.6 + resolution: "unhomoglyph@npm:1.0.6" + checksum: 2401fa3f8129fb1093d9ae59680b1dc8e395016e48401f9e706861a6edd28cafc60b0ac7e001cc127ee544942ed16236881b969afd856c28ebfe5d77afa1f0c2 + languageName: node + linkType: hard + "unicode-canonical-property-names-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0" @@ -31545,6 +31677,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:13": + version: 13.0.0 + resolution: "uuid@npm:13.0.0" + bin: + uuid: dist-node/bin/uuid + checksum: 7510ee1ab371be5339ef26ff8cabc2f4a2c60640ff880652968f758072f53bd4f4af1c8b0e671a8c9bb29ef926a24dec3ef0e3861d78183b39291a85743a9f96 + languageName: node + linkType: hard + "uuid@npm:8.3.2, uuid@npm:^8.0.0, uuid@npm:^8.3.2, uuid@npm:~8.3.2": version: 8.3.2 resolution: "uuid@npm:8.3.2"