Merge pull request #358 from vector-im/dbkr/matrix-utils-ts
Convert matrix-utils to typescript
This commit is contained in:
commit
65804cd962
6 changed files with 113 additions and 66 deletions
7
src/@types/global.d.ts
vendored
7
src/@types/global.d.ts
vendored
|
@ -15,3 +15,10 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "matrix-js-sdk/src/@types/global";
|
import "matrix-js-sdk/src/@types/global";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
// TODO: https://gitlab.matrix.org/matrix-org/olm/-/issues/10
|
||||||
|
OLM_OPTIONS: Record<string, string>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,40 +16,50 @@ limitations under the License.
|
||||||
|
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import matrix, { InteractiveAuth } from "matrix-js-sdk/src/browser-index";
|
import matrix, { InteractiveAuth } from "matrix-js-sdk/src/browser-index";
|
||||||
|
import { MatrixClient } from "matrix-js-sdk";
|
||||||
|
|
||||||
import { initClient, defaultHomeserver } from "../matrix-utils";
|
import { initClient, defaultHomeserver } from "../matrix-utils";
|
||||||
|
import { Session } from "../ClientContext";
|
||||||
|
|
||||||
export const useInteractiveLogin = () =>
|
export const useInteractiveLogin = () =>
|
||||||
useCallback(
|
useCallback<
|
||||||
async (homeserver: string, username: string, password: string) => {
|
(
|
||||||
const authClient = matrix.createClient(homeserver);
|
homeserver: string,
|
||||||
|
username: string,
|
||||||
|
password: string
|
||||||
|
) => Promise<[MatrixClient, Session]>
|
||||||
|
>(async (homeserver: string, username: string, password: string) => {
|
||||||
|
const authClient = matrix.createClient(homeserver);
|
||||||
|
|
||||||
const interactiveAuth = new InteractiveAuth({
|
const interactiveAuth = new InteractiveAuth({
|
||||||
matrixClient: authClient,
|
matrixClient: authClient,
|
||||||
doRequest: () =>
|
doRequest: () =>
|
||||||
authClient.login("m.login.password", {
|
authClient.login("m.login.password", {
|
||||||
identifier: {
|
identifier: {
|
||||||
type: "m.id.user",
|
type: "m.id.user",
|
||||||
user: username,
|
user: username,
|
||||||
},
|
},
|
||||||
password,
|
password,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
const { user_id, access_token, device_id } =
|
const { user_id, access_token, device_id } =
|
||||||
await interactiveAuth.attemptAuth();
|
await interactiveAuth.attemptAuth();
|
||||||
const session = { user_id, access_token, device_id };
|
const session = {
|
||||||
|
user_id,
|
||||||
|
access_token,
|
||||||
|
device_id,
|
||||||
|
passwordlessUser: false,
|
||||||
|
};
|
||||||
|
|
||||||
const client = await initClient({
|
const client = await initClient({
|
||||||
baseUrl: defaultHomeserver,
|
baseUrl: defaultHomeserver,
|
||||||
accessToken: access_token,
|
accessToken: access_token,
|
||||||
userId: user_id,
|
userId: user_id,
|
||||||
deviceId: device_id,
|
deviceId: device_id,
|
||||||
});
|
});
|
||||||
/* eslint-enable camelcase */
|
/* eslint-enable camelcase */
|
||||||
|
|
||||||
return [client, session];
|
return [client, session];
|
||||||
},
|
}, []);
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useCallback } from "react";
|
import React, { useState, useCallback } from "react";
|
||||||
import { createRoom, roomAliasFromRoomName } from "../matrix-utils";
|
import { createRoom, roomAliasLocalpartFromRoomName } from "../matrix-utils";
|
||||||
import { useGroupCallRooms } from "./useGroupCallRooms";
|
import { useGroupCallRooms } from "./useGroupCallRooms";
|
||||||
import { Header, HeaderLogo, LeftNav, RightNav } from "../Header";
|
import { Header, HeaderLogo, LeftNav, RightNav } from "../Header";
|
||||||
import commonStyles from "./common.module.css";
|
import commonStyles from "./common.module.css";
|
||||||
|
@ -56,7 +56,7 @@ export function RegisteredView({ client }) {
|
||||||
|
|
||||||
submit().catch((error) => {
|
submit().catch((error) => {
|
||||||
if (error.errcode === "M_ROOM_IN_USE") {
|
if (error.errcode === "M_ROOM_IN_USE") {
|
||||||
setExistingRoomId(roomAliasFromRoomName(roomName));
|
setExistingRoomId(roomAliasLocalpartFromRoomName(roomName));
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setError(undefined);
|
setError(undefined);
|
||||||
modalState.open();
|
modalState.open();
|
||||||
|
|
|
@ -22,7 +22,7 @@ import { useHistory } from "react-router-dom";
|
||||||
import { FieldRow, InputField, ErrorMessage } from "../input/Input";
|
import { FieldRow, InputField, ErrorMessage } from "../input/Input";
|
||||||
import { Button } from "../button";
|
import { Button } from "../button";
|
||||||
import { randomString } from "matrix-js-sdk/src/randomstring";
|
import { randomString } from "matrix-js-sdk/src/randomstring";
|
||||||
import { createRoom, roomAliasFromRoomName } from "../matrix-utils";
|
import { createRoom, roomAliasLocalpartFromRoomName } from "../matrix-utils";
|
||||||
import { useInteractiveRegistration } from "../auth/useInteractiveRegistration";
|
import { useInteractiveRegistration } from "../auth/useInteractiveRegistration";
|
||||||
import { useModalTriggerState } from "../Modal";
|
import { useModalTriggerState } from "../Modal";
|
||||||
import { JoinExistingCallModal } from "./JoinExistingCallModal";
|
import { JoinExistingCallModal } from "./JoinExistingCallModal";
|
||||||
|
@ -75,7 +75,7 @@ export function UnauthenticatedView() {
|
||||||
if (error.errcode === "M_ROOM_IN_USE") {
|
if (error.errcode === "M_ROOM_IN_USE") {
|
||||||
setOnFinished(() => () => {
|
setOnFinished(() => () => {
|
||||||
setClient(client, session);
|
setClient(client, session);
|
||||||
const aliasLocalpart = roomAliasFromRoomName(roomName);
|
const aliasLocalpart = roomAliasLocalpartFromRoomName(roomName);
|
||||||
const [, serverName] = client.getUserId().split(":");
|
const [, serverName] = client.getUserId().split(":");
|
||||||
history.push(`/room/#${aliasLocalpart}:${serverName}`);
|
history.push(`/room/#${aliasLocalpart}:${serverName}`);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,48 +1,63 @@
|
||||||
import matrix from "matrix-js-sdk/src/browser-index";
|
import Olm from "@matrix-org/olm";
|
||||||
|
import olmWasmPath from "@matrix-org/olm/olm.wasm?url";
|
||||||
|
import { IndexedDBStore } from "matrix-js-sdk/src/store/indexeddb";
|
||||||
|
import { WebStorageSessionStore } from "matrix-js-sdk/src/store/session/webstorage";
|
||||||
|
import { MemoryStore } from "matrix-js-sdk/src/store/memory";
|
||||||
|
import { IndexedDBCryptoStore } from "matrix-js-sdk/src/crypto/store/indexeddb-crypto-store";
|
||||||
|
import { createClient, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
|
import { ICreateClientOpts } from "matrix-js-sdk/src/matrix";
|
||||||
|
import { ClientEvent } from "matrix-js-sdk/src/client";
|
||||||
|
import { Visibility, Preset } from "matrix-js-sdk/src/@types/partials";
|
||||||
import {
|
import {
|
||||||
GroupCallIntent,
|
GroupCallIntent,
|
||||||
GroupCallType,
|
GroupCallType,
|
||||||
} from "matrix-js-sdk/src/browser-index";
|
} from "matrix-js-sdk/src/webrtc/groupCall";
|
||||||
|
import { ISyncStateData, SyncState } from "matrix-js-sdk/src/sync";
|
||||||
|
|
||||||
import IndexedDBWorker from "./IndexedDBWorker?worker";
|
import IndexedDBWorker from "./IndexedDBWorker?worker";
|
||||||
import Olm from "@matrix-org/olm";
|
|
||||||
import olmWasmPath from "@matrix-org/olm/olm.wasm?url";
|
|
||||||
|
|
||||||
export const defaultHomeserver =
|
export const defaultHomeserver =
|
||||||
import.meta.env.VITE_DEFAULT_HOMESERVER ||
|
(import.meta.env.VITE_DEFAULT_HOMESERVER as string) ??
|
||||||
`${window.location.protocol}//${window.location.host}`;
|
`${window.location.protocol}//${window.location.host}`;
|
||||||
|
|
||||||
export const defaultHomeserverHost = new URL(defaultHomeserver).host;
|
export const defaultHomeserverHost = new URL(defaultHomeserver).host;
|
||||||
|
|
||||||
function waitForSync(client) {
|
function waitForSync(client: MatrixClient) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
const onSync = (state, _old, data) => {
|
const onSync = (
|
||||||
|
state: SyncState,
|
||||||
|
_old: SyncState,
|
||||||
|
data: ISyncStateData
|
||||||
|
) => {
|
||||||
if (state === "PREPARED") {
|
if (state === "PREPARED") {
|
||||||
resolve();
|
resolve();
|
||||||
client.removeListener("sync", onSync);
|
client.removeListener(ClientEvent.Sync, onSync);
|
||||||
} else if (state === "ERROR") {
|
} else if (state === "ERROR") {
|
||||||
reject(data?.error);
|
reject(data?.error);
|
||||||
client.removeListener("sync", onSync);
|
client.removeListener(ClientEvent.Sync, onSync);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
client.on("sync", onSync);
|
client.on(ClientEvent.Sync, onSync);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function initClient(clientOptions) {
|
export async function initClient(
|
||||||
|
clientOptions: ICreateClientOpts
|
||||||
|
): Promise<MatrixClient> {
|
||||||
// TODO: https://gitlab.matrix.org/matrix-org/olm/-/issues/10
|
// TODO: https://gitlab.matrix.org/matrix-org/olm/-/issues/10
|
||||||
window.OLM_OPTIONS = {};
|
window.OLM_OPTIONS = {};
|
||||||
await Olm.init({ locateFile: () => olmWasmPath });
|
await Olm.init({ locateFile: () => olmWasmPath });
|
||||||
|
|
||||||
let indexedDB;
|
let indexedDB: IDBFactory;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
indexedDB = window.indexedDB;
|
indexedDB = window.indexedDB;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
const storeOpts = {};
|
const storeOpts = {} as ICreateClientOpts;
|
||||||
|
|
||||||
if (indexedDB && localStorage && !import.meta.env.DEV) {
|
if (indexedDB && localStorage && !import.meta.env.DEV) {
|
||||||
storeOpts.store = new matrix.IndexedDBStore({
|
storeOpts.store = new IndexedDBStore({
|
||||||
indexedDB: window.indexedDB,
|
indexedDB: window.indexedDB,
|
||||||
localStorage: window.localStorage,
|
localStorage: window.localStorage,
|
||||||
dbName: "element-call-sync",
|
dbName: "element-call-sync",
|
||||||
|
@ -51,17 +66,17 @@ export async function initClient(clientOptions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (localStorage) {
|
if (localStorage) {
|
||||||
storeOpts.sessionStore = new matrix.WebStorageSessionStore(localStorage);
|
storeOpts.sessionStore = new WebStorageSessionStore(localStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (indexedDB) {
|
if (indexedDB) {
|
||||||
storeOpts.cryptoStore = new matrix.IndexedDBCryptoStore(
|
storeOpts.cryptoStore = new IndexedDBCryptoStore(
|
||||||
indexedDB,
|
indexedDB,
|
||||||
"matrix-js-sdk:crypto"
|
"matrix-js-sdk:crypto"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = matrix.createClient({
|
const client = createClient({
|
||||||
...storeOpts,
|
...storeOpts,
|
||||||
...clientOptions,
|
...clientOptions,
|
||||||
useAuthorizationHeader: true,
|
useAuthorizationHeader: true,
|
||||||
|
@ -74,7 +89,7 @@ export async function initClient(clientOptions) {
|
||||||
"Error starting matrix client store. Falling back to memory store.",
|
"Error starting matrix client store. Falling back to memory store.",
|
||||||
error
|
error
|
||||||
);
|
);
|
||||||
client.store = new matrix.MemoryStore({ localStorage });
|
client.store = new MemoryStore({ localStorage });
|
||||||
await client.store.startup();
|
await client.store.startup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +108,7 @@ export async function initClient(clientOptions) {
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function roomAliasFromRoomName(roomName) {
|
export function roomAliasLocalpartFromRoomName(roomName: string): string {
|
||||||
return roomName
|
return roomName
|
||||||
.trim()
|
.trim()
|
||||||
.replace(/\s/g, "-")
|
.replace(/\s/g, "-")
|
||||||
|
@ -101,7 +116,14 @@ export function roomAliasFromRoomName(roomName) {
|
||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function roomNameFromRoomId(roomId) {
|
export function fullAliasFromRoomName(
|
||||||
|
roomName: string,
|
||||||
|
client: MatrixClient
|
||||||
|
): string {
|
||||||
|
return `#${roomAliasLocalpartFromRoomName(roomName)}:${client.getDomain()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function roomNameFromRoomId(roomId: string): string {
|
||||||
return roomId
|
return roomId
|
||||||
.match(/([^:]+):.*$/)[1]
|
.match(/([^:]+):.*$/)[1]
|
||||||
.substring(1)
|
.substring(1)
|
||||||
|
@ -113,7 +135,7 @@ export function roomNameFromRoomId(roomId) {
|
||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isLocalRoomId(roomId) {
|
export function isLocalRoomId(roomId: string): boolean {
|
||||||
if (!roomId) {
|
if (!roomId) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -127,12 +149,16 @@ export function isLocalRoomId(roomId) {
|
||||||
return parts[1] === defaultHomeserverHost;
|
return parts[1] === defaultHomeserverHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createRoom(client, name, isPtt = false) {
|
export async function createRoom(
|
||||||
const { room_id, room_alias } = await client.createRoom({
|
client: MatrixClient,
|
||||||
visibility: "private",
|
name: string,
|
||||||
preset: "public_chat",
|
isPtt = false
|
||||||
|
): Promise<string> {
|
||||||
|
const createRoomResult = await client.createRoom({
|
||||||
|
visibility: Visibility.Private,
|
||||||
|
preset: Preset.PublicChat,
|
||||||
name,
|
name,
|
||||||
room_alias_name: roomAliasFromRoomName(name),
|
room_alias_name: roomAliasLocalpartFromRoomName(name),
|
||||||
power_level_content_override: {
|
power_level_content_override: {
|
||||||
invite: 100,
|
invite: 100,
|
||||||
kick: 100,
|
kick: 100,
|
||||||
|
@ -158,19 +184,19 @@ export async function createRoom(client, name, isPtt = false) {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log({ isPtt });
|
console.log(`Creating ${isPtt ? "PTT" : "video"} group call room`);
|
||||||
|
|
||||||
await client.createGroupCall(
|
await client.createGroupCall(
|
||||||
room_id,
|
createRoomResult.room_id,
|
||||||
isPtt ? GroupCallType.Voice : GroupCallType.Video,
|
isPtt ? GroupCallType.Voice : GroupCallType.Video,
|
||||||
isPtt,
|
isPtt,
|
||||||
GroupCallIntent.Prompt
|
GroupCallIntent.Prompt
|
||||||
);
|
);
|
||||||
|
|
||||||
return room_alias || room_id;
|
return fullAliasFromRoomName(name, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRoomUrl(roomId) {
|
export function getRoomUrl(roomId: string): string {
|
||||||
if (roomId.startsWith("#")) {
|
if (roomId.startsWith("#")) {
|
||||||
const [localPart, host] = roomId.replace("#", "").split(":");
|
const [localPart, host] = roomId.replace("#", "").split(":");
|
||||||
|
|
||||||
|
@ -184,7 +210,11 @@ export function getRoomUrl(roomId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAvatarUrl(client, mxcUrl, avatarSize = 96) {
|
export function getAvatarUrl(
|
||||||
|
client: MatrixClient,
|
||||||
|
mxcUrl: string,
|
||||||
|
avatarSize = 96
|
||||||
|
): string {
|
||||||
const width = Math.floor(avatarSize * window.devicePixelRatio);
|
const width = Math.floor(avatarSize * window.devicePixelRatio);
|
||||||
const height = Math.floor(avatarSize * window.devicePixelRatio);
|
const height = Math.floor(avatarSize * window.devicePixelRatio);
|
||||||
return mxcUrl && client.mxcUrlToHttp(mxcUrl, width, height, "crop");
|
return mxcUrl && client.mxcUrlToHttp(mxcUrl, width, height, "crop");
|
|
@ -2,7 +2,7 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es2016",
|
"target": "es2016",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"module": "commonjs",
|
"module": "es2020",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
|
|
Loading…
Reference in a new issue