Compare commits

...

10 Commits

Author SHA1 Message Date
David Baker
69b1b3076c Update js-sdk 2023-01-17 11:15:39 +00:00
David Baker
4ec7749631 Add units to constant 2023-01-17 11:15:12 +00:00
David Baker
3340ba96dc Change rageshake persistence to throttled flushing
Rather than every 30 seconds. This way we'll save logs for sessions
lasting less than 30 seconds which we previously didn't. Also save
on window unload just in case that doesn't catch everything.

Plus remove some more unused params.
2023-01-17 11:15:00 +00:00
David Baker
756e03758f Mostly cosmetic fixes to rageshake
* Remove duplicate copyright header
 * Remove ts-ignores by just using the objects directly rather than via
   event.target
 * Use error.message rather than errorCode which TS doesn't know about
   and may or may not exist.
 * Remove some unused things like the skip rageshake function and
   the option to init rageshakes without storage.
 * Turn single function with a boolean param to make it take two entirely
   separate code paths into two functions.
2023-01-17 11:13:40 +00:00
David Baker
ec4e50693f Log undecryptable to-device events
Listen for the new undecryptable to-device event event and log
events for it in Posthog & Sentry, and make it visible in the
call flow diagram.
2023-01-17 11:11:39 +00:00
David Baker
fe575990f5 Rename to useCallViewKeyboardShortcuts 2023-01-17 11:11:13 +00:00
David Baker
c9baa2d9dc Prevent mute event spam from key repeats 2023-01-17 11:10:55 +00:00
David Baker
9b3a7cd219 Disable keyboard shortcuts when feedback modal is open 2023-01-17 11:10:45 +00:00
David Baker
f58590fc70 Fix caching headers on Docker image 2023-01-17 11:10:37 +00:00
David Baker
71a1c5d24b Use IndexedDB storage in dev mode, just without the worker
As per comment, we can't use workers in Vite dev mode. We previously
fell back to the memory store but this ends up with it working significantly
differently in dev mode to production, eg. dev mode would always start
by doing an initial sync, so old to-device messages would arrive again.

There's no need to fall all the way back to the memory store though,
we can use the IndexedDB store without the worker.
2023-01-17 11:10:01 +00:00
12 changed files with 403 additions and 180 deletions

View File

@@ -2,9 +2,24 @@ server {
listen 8080; listen 8080;
server_name localhost; server_name localhost;
root /app;
location / { location / {
root /app; # disable cache entriely by default (apart from Etag which is accurate enough)
add_header Cache-Control 'private no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
if_modified_since off;
expires off;
# also turn off last-modified since they are just the timestamps of the file in the docker image
# and may or may not bear any resemblance to when the resource changed
add_header Last-Modified "";
try_files $uri /$uri /index.html; try_files $uri /$uri /index.html;
} }
# assets can be cached because they have hashed filenames
location /assets {
expires 1w;
add_header Cache-Control "public, no-transform";
}
} }

View File

@@ -45,7 +45,8 @@
"i18next": "^21.10.0", "i18next": "^21.10.0",
"i18next-browser-languagedetector": "^6.1.8", "i18next-browser-languagedetector": "^6.1.8",
"i18next-http-backend": "^1.4.4", "i18next-http-backend": "^1.4.4",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#2c8eece5ca5333c6e6a14e8ed53f359ed0e9e9bf", "lodash": "^4.17.21",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#a34d06c7c24c3523a77f70c01d4e31c45e92aa6b",
"matrix-widget-api": "^1.0.0", "matrix-widget-api": "^1.0.0",
"mermaid": "^8.13.8", "mermaid": "^8.13.8",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",

View File

@@ -28,6 +28,7 @@ import {
SignupTracker, SignupTracker,
MuteCameraTracker, MuteCameraTracker,
MuteMicrophoneTracker, MuteMicrophoneTracker,
UndecryptableToDeviceEventTracker,
} from "./PosthogEvents"; } from "./PosthogEvents";
import { Config } from "./config/Config"; import { Config } from "./config/Config";
import { getUrlParams } from "./UrlParams"; import { getUrlParams } from "./UrlParams";
@@ -415,4 +416,5 @@ export class PosthogAnalytics {
public eventLogin = new LoginTracker(); public eventLogin = new LoginTracker();
public eventMuteMicrophone = new MuteMicrophoneTracker(); public eventMuteMicrophone = new MuteMicrophoneTracker();
public eventMuteCamera = new MuteCameraTracker(); public eventMuteCamera = new MuteCameraTracker();
public eventUndecryptableToDevice = new UndecryptableToDeviceEventTracker();
} }

View File

@@ -149,3 +149,17 @@ export class MuteCameraTracker {
}); });
} }
} }
interface UndecryptableToDeviceEvent {
eventName: "UndecryptableToDeviceEvent";
callId: string;
}
export class UndecryptableToDeviceEventTracker {
track(callId: string) {
PosthogAnalytics.instance.trackEvent<UndecryptableToDeviceEvent>({
eventName: "UndecryptableToDeviceEvent",
callId,
});
}
}

View File

@@ -94,12 +94,17 @@ export async function initClient(
const storeOpts = {} as ICreateClientOpts; const storeOpts = {} as ICreateClientOpts;
if (indexedDB && localStorage && !import.meta.env.DEV) { if (indexedDB && localStorage) {
storeOpts.store = new IndexedDBStore({ storeOpts.store = new IndexedDBStore({
indexedDB: window.indexedDB, indexedDB: window.indexedDB,
localStorage, localStorage,
dbName: SYNC_STORE_NAME, dbName: SYNC_STORE_NAME,
workerFactory: () => new IndexedDBWorker(), // We can't use the worker in dev mode because Vite simply doesn't bundle workers
// in dev mode: it expects them to use native modules. Ours don't, and even then only
// Chrome supports it. (It bundles them fine in production mode.)
workerFactory: import.meta.env.DEV
? undefined
: () => new IndexedDBWorker(),
}); });
} else if (localStorage) { } else if (localStorage) {
storeOpts.store = new MemoryStore({ localStorage }); storeOpts.store = new MemoryStore({ localStorage });

View File

@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import * as Sentry from "@sentry/react";
import { Resizable } from "re-resizable"; import { Resizable } from "re-resizable";
import React, { import React, {
useEffect, useEffect,
@@ -34,6 +35,7 @@ import { CallEvent } from "matrix-js-sdk/src/webrtc/call";
import styles from "./GroupCallInspector.module.css"; import styles from "./GroupCallInspector.module.css";
import { SelectInput } from "../input/SelectInput"; import { SelectInput } from "../input/SelectInput";
import { PosthogAnalytics } from "../PosthogAnalytics";
interface InspectorContextState { interface InspectorContextState {
eventsByUserId?: { [userId: string]: SequenceDiagramMatrixEvent[] }; eventsByUserId?: { [userId: string]: SequenceDiagramMatrixEvent[] };
@@ -108,6 +110,19 @@ function formatTimestamp(timestamp: number | Date) {
return dateFormatter.format(timestamp); return dateFormatter.format(timestamp);
} }
function formatType(event: SequenceDiagramMatrixEvent): string {
if (event.content.msgtype === "m.bad.encrypted") return "Undecryptable";
return event.type;
}
function lineForEvent(event: SequenceDiagramMatrixEvent): string {
return `${getUserName(event.from)} ${
event.ignored ? "-x" : "->>"
} ${getUserName(event.to)}: ${formatTimestamp(event.timestamp)} ${formatType(
event
)} ${formatContent(event.type, event.content)}`;
}
export const InspectorContext = export const InspectorContext =
createContext< createContext<
[ [
@@ -187,21 +202,7 @@ export function SequenceDiagramViewer({
participant ${getUserName(localUserId)} participant ${getUserName(localUserId)}
participant Room participant Room
participant ${selectedUserId ? getUserName(selectedUserId) : "unknown"} participant ${selectedUserId ? getUserName(selectedUserId) : "unknown"}
${ ${events ? events.map(lineForEvent).join("\n ") : ""}
events
? events
.map(
({ to, from, timestamp, type, content, ignored }) =>
`${getUserName(from)} ${ignored ? "-x" : "->>"} ${getUserName(
to
)}: ${formatTimestamp(timestamp)} ${type} ${formatContent(
type,
content
)}`
)
.join("\n ")
: ""
}
`; `;
mermaid.mermaidAPI.render("mermaid", graphDefinition, (svgCode: string) => { mermaid.mermaidAPI.render("mermaid", graphDefinition, (svgCode: string) => {
@@ -389,12 +390,23 @@ function useGroupCallState(
function onSendVoipEvent(event: Record<string, unknown>) { function onSendVoipEvent(event: Record<string, unknown>) {
dispatch({ type: CallEvent.SendVoipEvent, rawEvent: event }); dispatch({ type: CallEvent.SendVoipEvent, rawEvent: event });
} }
function onUndecryptableToDevice(event: MatrixEvent) {
dispatch({ type: ClientEvent.ReceivedVoipEvent, event });
Sentry.captureMessage("Undecryptable to-device Event");
PosthogAnalytics.instance.eventUndecryptableToDevice.track(
groupCall.groupCallId
);
}
client.on(RoomStateEvent.Events, onUpdateRoomState); client.on(RoomStateEvent.Events, onUpdateRoomState);
//groupCall.on("calls_changed", onCallsChanged); //groupCall.on("calls_changed", onCallsChanged);
groupCall.on(CallEvent.SendVoipEvent, onSendVoipEvent); groupCall.on(CallEvent.SendVoipEvent, onSendVoipEvent);
//client.on("state", onCallsChanged); //client.on("state", onCallsChanged);
//client.on("hangup", onCallHangup); //client.on("hangup", onCallHangup);
client.on(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent); client.on(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent);
client.on(ClientEvent.UndecryptableToDeviceEvent, onUndecryptableToDevice);
onUpdateRoomState(); onUpdateRoomState();
@@ -405,6 +417,10 @@ function useGroupCallState(
//client.removeListener("state", onCallsChanged); //client.removeListener("state", onCallsChanged);
//client.removeListener("hangup", onCallHangup); //client.removeListener("hangup", onCallHangup);
client.removeListener(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent); client.removeListener(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent);
client.removeListener(
ClientEvent.UndecryptableToDeviceEvent,
onUndecryptableToDevice
);
}; };
}, [client, groupCall]); }, [client, groupCall]);

View File

@@ -75,6 +75,7 @@ export function GroupCallView({
toggleLocalVideoMuted, toggleLocalVideoMuted,
toggleMicrophoneMuted, toggleMicrophoneMuted,
toggleScreensharing, toggleScreensharing,
setMicrophoneMuted,
requestingScreenshare, requestingScreenshare,
isScreensharing, isScreensharing,
screenshareFeeds, screenshareFeeds,
@@ -251,6 +252,7 @@ export function GroupCallView({
localVideoMuted={localVideoMuted} localVideoMuted={localVideoMuted}
toggleLocalVideoMuted={toggleLocalVideoMuted} toggleLocalVideoMuted={toggleLocalVideoMuted}
toggleMicrophoneMuted={toggleMicrophoneMuted} toggleMicrophoneMuted={toggleMicrophoneMuted}
setMicrophoneMuted={setMicrophoneMuted}
userMediaFeeds={userMediaFeeds} userMediaFeeds={userMediaFeeds}
activeSpeaker={activeSpeaker} activeSpeaker={activeSpeaker}
onLeave={onLeave} onLeave={onLeave}

View File

@@ -63,6 +63,7 @@ import { usePrefersReducedMotion } from "../usePrefersReducedMotion";
import { ParticipantInfo } from "./useGroupCall"; import { ParticipantInfo } from "./useGroupCall";
import { TileDescriptor } from "../video-grid/TileDescriptor"; import { TileDescriptor } from "../video-grid/TileDescriptor";
import { AudioSink } from "../video-grid/AudioSink"; import { AudioSink } from "../video-grid/AudioSink";
import { useCallViewKeyboardShortcuts } from "../useCallViewKeyboardShortcuts";
const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {}); const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {});
// There is currently a bug in Safari our our code with cloning and sending MediaStreams // There is currently a bug in Safari our our code with cloning and sending MediaStreams
@@ -81,6 +82,7 @@ interface Props {
toggleLocalVideoMuted: () => void; toggleLocalVideoMuted: () => void;
toggleMicrophoneMuted: () => void; toggleMicrophoneMuted: () => void;
toggleScreensharing: () => void; toggleScreensharing: () => void;
setMicrophoneMuted: (muted: boolean) => void;
userMediaFeeds: CallFeed[]; userMediaFeeds: CallFeed[];
activeSpeaker: CallFeed | null; activeSpeaker: CallFeed | null;
onLeave: () => void; onLeave: () => void;
@@ -101,6 +103,7 @@ export function InCallView({
localVideoMuted, localVideoMuted,
toggleLocalVideoMuted, toggleLocalVideoMuted,
toggleMicrophoneMuted, toggleMicrophoneMuted,
setMicrophoneMuted,
userMediaFeeds, userMediaFeeds,
activeSpeaker, activeSpeaker,
onLeave, onLeave,
@@ -141,6 +144,13 @@ export function InCallView({
const { hideScreensharing } = useUrlParams(); const { hideScreensharing } = useUrlParams();
useCallViewKeyboardShortcuts(
!feedbackModalState.isOpen,
toggleMicrophoneMuted,
toggleLocalVideoMuted,
setMicrophoneMuted
);
useEffect(() => { useEffect(() => {
widget?.api.transport.send( widget?.api.transport.send(
layout === "freedom" layout === "freedom"

View File

@@ -32,8 +32,6 @@ import { usePageUnload } from "./usePageUnload";
import { PosthogAnalytics } from "../PosthogAnalytics"; import { PosthogAnalytics } from "../PosthogAnalytics";
import { TranslatedError, translatedError } from "../TranslatedError"; import { TranslatedError, translatedError } from "../TranslatedError";
import { ElementWidgetActions, ScreenshareStartData, widget } from "../widget"; import { ElementWidgetActions, ScreenshareStartData, widget } from "../widget";
import { getSetting } from "../settings/useSetting";
import { useEventTarget } from "../useEvents";
export enum ConnectionState { export enum ConnectionState {
EstablishingCall = "establishing call", // call hasn't been established yet EstablishingCall = "establishing call", // call hasn't been established yet
@@ -60,6 +58,7 @@ export interface UseGroupCallReturnType {
toggleLocalVideoMuted: () => void; toggleLocalVideoMuted: () => void;
toggleMicrophoneMuted: () => void; toggleMicrophoneMuted: () => void;
toggleScreensharing: () => void; toggleScreensharing: () => void;
setMicrophoneMuted: (muted: boolean) => void;
requestingScreenshare: boolean; requestingScreenshare: boolean;
isScreensharing: boolean; isScreensharing: boolean;
screenshareFeeds: CallFeed[]; screenshareFeeds: CallFeed[];
@@ -472,68 +471,6 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType {
} }
}, [t, updateState]); }, [t, updateState]);
const [spacebarHeld, setSpacebarHeld] = useState(false);
useEventTarget(
window,
"keydown",
useCallback(
(event: KeyboardEvent) => {
// Check if keyboard shortcuts are enabled
const keyboardShortcuts = getSetting("keyboard-shortcuts", true);
if (!keyboardShortcuts) {
return;
}
if (event.key === "m") {
toggleMicrophoneMuted();
} else if (event.key == "v") {
toggleLocalVideoMuted();
} else if (event.key === " ") {
setSpacebarHeld(true);
setMicrophoneMuted(false);
}
},
[
toggleLocalVideoMuted,
toggleMicrophoneMuted,
setMicrophoneMuted,
setSpacebarHeld,
]
)
);
useEventTarget(
window,
"keyup",
useCallback(
(event: KeyboardEvent) => {
// Check if keyboard shortcuts are enabled
const keyboardShortcuts = getSetting("keyboard-shortcuts", true);
if (!keyboardShortcuts) {
return;
}
if (event.key === " ") {
setSpacebarHeld(false);
setMicrophoneMuted(true);
}
},
[setMicrophoneMuted, setSpacebarHeld]
)
);
useEventTarget(
window,
"blur",
useCallback(() => {
if (spacebarHeld) {
setSpacebarHeld(false);
setMicrophoneMuted(true);
}
}, [setMicrophoneMuted, setSpacebarHeld, spacebarHeld])
);
return { return {
state, state,
localCallFeed, localCallFeed,
@@ -548,6 +485,7 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType {
toggleLocalVideoMuted, toggleLocalVideoMuted,
toggleMicrophoneMuted, toggleMicrophoneMuted,
toggleScreensharing, toggleScreensharing,
setMicrophoneMuted,
requestingScreenshare, requestingScreenshare,
isScreensharing, isScreensharing,
screenshareFeeds, screenshareFeeds,

View File

@@ -1,21 +1,4 @@
/* /*
Copyright 2022 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.
*/
/* eslint-disable @typescript-eslint/ban-ts-comment */
/*
Copyright 2017 OpenMarket Ltd Copyright 2017 OpenMarket Ltd
Copyright 2018 New Vector Ltd Copyright 2018 New Vector Ltd
Copyright 2019 The New Vector Ltd Copyright 2019 The New Vector Ltd
@@ -54,15 +37,23 @@ limitations under the License.
// actually timestamps. We then purge the remaining logs. We also do this // actually timestamps. We then purge the remaining logs. We also do this
// purge on startup to prevent logs from accumulating. // purge on startup to prevent logs from accumulating.
import EventEmitter from "events";
import { throttle } from "lodash";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { randomString } from "matrix-js-sdk/src/randomstring";
// the frequency with which we flush to indexeddb
const FLUSH_RATE_MS = 30 * 1000;
// the length of log data we keep in indexeddb (and include in the reports) // the length of log data we keep in indexeddb (and include in the reports)
const MAX_LOG_SIZE = 1024 * 1024 * 5; // 5 MB const MAX_LOG_SIZE = 1024 * 1024 * 5; // 5 MB
// Shortest amount of time between flushes. We are just appending to an
// IndexedDB table so we don't expect flushing to be that expensive, but
// we can batch the writes a little.
const MAX_FLUSH_INTERVAL_MS = 2 * 1000;
enum ConsoleLoggerEvent {
Log = "log",
}
type LogFunction = ( type LogFunction = (
...args: (Error | DOMException | object | string)[] ...args: (Error | DOMException | object | string)[]
) => void; ) => void;
@@ -76,7 +67,7 @@ interface LogEntry {
index?: number; index?: number;
} }
export class ConsoleLogger { export class ConsoleLogger extends EventEmitter {
private logs = ""; private logs = "";
private originalFunctions: { [key in LogFunctionName]?: LogFunction } = {}; private originalFunctions: { [key in LogFunctionName]?: LogFunction } = {};
@@ -99,13 +90,6 @@ export class ConsoleLogger {
}); });
} }
public bypassRageshake(
fnName: LogFunctionName,
...args: (Error | DOMException | object | string)[]
): void {
this.originalFunctions[fnName](...args);
}
public log( public log(
level: string, level: string,
...args: (Error | DOMException | object | string)[] ...args: (Error | DOMException | object | string)[]
@@ -137,23 +121,27 @@ export class ConsoleLogger {
// Using + really is the quickest way in JS // Using + really is the quickest way in JS
// http://jsperf.com/concat-vs-plus-vs-join // http://jsperf.com/concat-vs-plus-vs-join
this.logs += line; this.logs += line;
this.emit(ConsoleLoggerEvent.Log);
} }
/** /**
* Retrieve log lines to flush to disk. * Returns the log lines to flush to disk and empties the internal log buffer
* @param {boolean} keepLogs True to not delete logs after flushing. * @return {string} \n delimited log lines
* @return {string} \n delimited log lines to flush.
*/ */
public flush(keepLogs?: boolean): string { public popLogs(): string {
// The ConsoleLogger doesn't care how these end up on disk, it just
// flushes them to the caller.
if (keepLogs) {
return this.logs;
}
const logsToFlush = this.logs; const logsToFlush = this.logs;
this.logs = ""; this.logs = "";
return logsToFlush; return logsToFlush;
} }
/**
* Returns lines currently in the log buffer without removing them
* @return {string} \n delimited log lines
*/
public peekLogs(): string {
return this.logs;
}
} }
// A class which stores log lines in an IndexedDB instance. // A class which stores log lines in an IndexedDB instance.
@@ -164,8 +152,14 @@ export class IndexedDBLogStore {
private flushAgainPromise: Promise<void> = null; private flushAgainPromise: Promise<void> = null;
private id: string; private id: string;
constructor(private indexedDB: IDBFactory, private logger: ConsoleLogger) { constructor(
private indexedDB: IDBFactory,
private loggerInstance: ConsoleLogger
) {
this.id = "instance-" + randomString(16); this.id = "instance-" + randomString(16);
loggerInstance.on(ConsoleLoggerEvent.Log, this.onLoggerLog);
window.addEventListener("beforeunload", this.flush);
} }
/** /**
@@ -174,30 +168,31 @@ export class IndexedDBLogStore {
public connect(): Promise<void> { public connect(): Promise<void> {
const req = this.indexedDB.open("logs"); const req = this.indexedDB.open("logs");
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
req.onsuccess = (event: Event) => { req.onsuccess = () => {
// @ts-ignore this.db = req.result;
this.db = event.target.result;
// Periodically flush logs to local storage / indexeddb
setInterval(this.flush.bind(this), FLUSH_RATE_MS);
resolve(); resolve();
}; };
req.onerror = (event) => { req.onerror = () => {
const err = const err = "Failed to open log database: " + req.error.name;
// @ts-ignore
"Failed to open log database: " + event.target.error.name;
logger.error(err); logger.error(err);
reject(new Error(err)); reject(new Error(err));
}; };
// First time: Setup the object store // First time: Setup the object store
req.onupgradeneeded = (event) => { req.onupgradeneeded = () => {
// @ts-ignore const db = req.result;
const db = event.target.result; // This is the log entries themselves. Each entry is a chunk of
// logs (ie multiple lines). 'id' is the instance ID (so logs with
// the same instance ID are all from the same session) and 'index'
// is a sequence number for the chunk. The log lines live in the
// 'lines' key, which is a chunk of many newline-separated log lines.
const logObjStore = db.createObjectStore("logs", { const logObjStore = db.createObjectStore("logs", {
keyPath: ["id", "index"], keyPath: ["id", "index"],
}); });
// Keys in the database look like: [ "instance-148938490", 0 ] // Keys in the database look like: [ "instance-148938490", 0 ]
// (The instance ID plus the ID of each log chunk).
// Later on we need to query everything based on an instance id. // Later on we need to query everything based on an instance id.
// In order to do this, we need to set up indexes "id". // In order to do this, we need to set up indexes "id".
logObjStore.createIndex("id", "id", { unique: false }); logObjStore.createIndex("id", "id", { unique: false });
@@ -206,6 +201,9 @@ export class IndexedDBLogStore {
this.generateLogEntry(new Date() + " ::: Log database was created.") this.generateLogEntry(new Date() + " ::: Log database was created.")
); );
// This records the last time each instance ID generated a log message, such
// that the logs from each session can be collated in the order they last logged
// something.
const lastModifiedStore = db.createObjectStore("logslastmod", { const lastModifiedStore = db.createObjectStore("logslastmod", {
keyPath: "id", keyPath: "id",
}); });
@@ -214,6 +212,26 @@ export class IndexedDBLogStore {
}); });
} }
private onLoggerLog = () => {
if (!this.db) return;
this.throttledFlush();
};
// Throttled function to flush logs. We use throttle rather
// than debounce as we want logs to be written regularly, otherwise
// if there's a constant stream of logging, we'd never write anything.
private throttledFlush = throttle(
() => {
this.flush();
},
MAX_FLUSH_INTERVAL_MS,
{
leading: false,
trailing: true,
}
);
/** /**
* Flush logs to disk. * Flush logs to disk.
* *
@@ -233,7 +251,7 @@ export class IndexedDBLogStore {
* *
* @return {Promise} Resolved when the logs have been flushed. * @return {Promise} Resolved when the logs have been flushed.
*/ */
public flush(): Promise<void> { public flush = (): Promise<void> => {
// check if a flush() operation is ongoing // check if a flush() operation is ongoing
if (this.flushPromise) { if (this.flushPromise) {
if (this.flushAgainPromise) { if (this.flushAgainPromise) {
@@ -258,20 +276,19 @@ export class IndexedDBLogStore {
reject(new Error("No connected database")); reject(new Error("No connected database"));
return; return;
} }
const lines = this.logger.flush(); const lines = this.loggerInstance.popLogs();
if (lines.length === 0) { if (lines.length === 0) {
resolve(); resolve();
return; return;
} }
const txn = this.db.transaction(["logs", "logslastmod"], "readwrite"); const txn = this.db.transaction(["logs", "logslastmod"], "readwrite");
const objStore = txn.objectStore("logs"); const objStore = txn.objectStore("logs");
txn.oncomplete = (event) => { txn.oncomplete = () => {
resolve(); resolve();
}; };
txn.onerror = (event) => { txn.onerror = (event) => {
logger.error("Failed to flush logs : ", event); logger.error("Failed to flush logs : ", event);
// @ts-ignore reject(new Error("Failed to write logs: " + txn.error.message));
reject(new Error("Failed to write logs: " + event.target.errorCode));
}; };
objStore.add(this.generateLogEntry(lines)); objStore.add(this.generateLogEntry(lines));
const lastModStore = txn.objectStore("logslastmod"); const lastModStore = txn.objectStore("logslastmod");
@@ -280,7 +297,7 @@ export class IndexedDBLogStore {
this.flushPromise = null; this.flushPromise = null;
}); });
return this.flushPromise; return this.flushPromise;
} };
/** /**
* Consume the most recent logs and return them. Older logs which are not * Consume the most recent logs and return them. Older logs which are not
@@ -307,13 +324,11 @@ export class IndexedDBLogStore {
.index("id") .index("id")
.openCursor(IDBKeyRange.only(id), "prev"); .openCursor(IDBKeyRange.only(id), "prev");
let lines = ""; let lines = "";
query.onerror = (event) => { query.onerror = () => {
// @ts-ignore reject(new Error("Query failed: " + query.error.message));
reject(new Error("Query failed: " + event.target.errorCode));
}; };
query.onsuccess = (event) => { query.onsuccess = () => {
// @ts-ignore const cursor = query.result;
const cursor = event.target.result;
if (!cursor) { if (!cursor) {
resolve(lines); resolve(lines);
return; // end of results return; // end of results
@@ -355,9 +370,8 @@ export class IndexedDBLogStore {
const o = txn.objectStore("logs"); const o = txn.objectStore("logs");
// only load the key path, not the data which may be huge // only load the key path, not the data which may be huge
const query = o.index("id").openKeyCursor(IDBKeyRange.only(id)); const query = o.index("id").openKeyCursor(IDBKeyRange.only(id));
query.onsuccess = (event) => { query.onsuccess = () => {
// @ts-ignore const cursor = query.result;
const cursor = event.target.result;
if (!cursor) { if (!cursor) {
return; return;
} }
@@ -367,12 +381,10 @@ export class IndexedDBLogStore {
txn.oncomplete = () => { txn.oncomplete = () => {
resolve(); resolve();
}; };
txn.onerror = (event) => { txn.onerror = () => {
reject( reject(
new Error( new Error(
"Failed to delete logs for " + "Failed to delete logs for " + `'${id}' : ${txn.error.message}`
// @ts-ignore
`'${id}' : ${event.target.errorCode}`
) )
); );
}; };
@@ -456,14 +468,12 @@ function selectQuery<T>(
const query = store.openCursor(keyRange); const query = store.openCursor(keyRange);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const results = []; const results = [];
query.onerror = (event) => { query.onerror = () => {
// @ts-ignore reject(new Error("Query failed: " + query.error.message));
reject(new Error("Query failed: " + event.target.errorCode));
}; };
// collect results // collect results
query.onsuccess = (event) => { query.onsuccess = () => {
// @ts-ignore const cursor = query.result;
const cursor = event.target.result;
if (!cursor) { if (!cursor) {
resolve(results); resolve(results);
return; // end of results return; // end of results
@@ -479,8 +489,6 @@ declare global {
// eslint-disable-next-line no-var, camelcase // eslint-disable-next-line no-var, camelcase
var mx_rage_logger: ConsoleLogger; var mx_rage_logger: ConsoleLogger;
// eslint-disable-next-line no-var, camelcase // eslint-disable-next-line no-var, camelcase
var mx_rage_initPromise: Promise<void>;
// eslint-disable-next-line no-var, camelcase
var mx_rage_initStoragePromise: Promise<void>; var mx_rage_initStoragePromise: Promise<void>;
} }
@@ -491,19 +499,11 @@ declare global {
* be set up immediately for the logs. * be set up immediately for the logs.
* @return {Promise} Resolves when set up. * @return {Promise} Resolves when set up.
*/ */
export function init(setUpPersistence = true): Promise<void> { export function init(): Promise<void> {
if (global.mx_rage_initPromise) {
return global.mx_rage_initPromise;
}
global.mx_rage_logger = new ConsoleLogger(); global.mx_rage_logger = new ConsoleLogger();
global.mx_rage_logger.monkeyPatch(window.console); global.mx_rage_logger.monkeyPatch(window.console);
if (setUpPersistence) { return tryInitStorage();
return tryInitStorage();
}
global.mx_rage_initPromise = Promise.resolve();
return global.mx_rage_initPromise;
} }
/** /**
@@ -573,7 +573,7 @@ export async function getLogsForReport(): Promise<LogEntry[]> {
} else { } else {
return [ return [
{ {
lines: global.mx_rage_logger.flush(true), lines: global.mx_rage_logger.peekLogs(),
id: "-", id: "-",
}, },
]; ];

View File

@@ -0,0 +1,93 @@
/*
Copyright 2022-2023 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.
*/
import { useCallback, useState } from "react";
import { getSetting } from "./settings/useSetting";
import { useEventTarget } from "./useEvents";
export function useCallViewKeyboardShortcuts(
enabled: boolean,
toggleMicrophoneMuted: () => void,
toggleLocalVideoMuted: () => void,
setMicrophoneMuted: (muted: boolean) => void
) {
const [spacebarHeld, setSpacebarHeld] = useState(false);
useEventTarget(
window,
"keydown",
useCallback(
(event: KeyboardEvent) => {
if (!enabled) return;
// Check if keyboard shortcuts are enabled
const keyboardShortcuts = getSetting("keyboard-shortcuts", true);
if (!keyboardShortcuts) {
return;
}
if (event.key === "m") {
toggleMicrophoneMuted();
} else if (event.key == "v") {
toggleLocalVideoMuted();
} else if (event.key === " " && !spacebarHeld) {
setSpacebarHeld(true);
setMicrophoneMuted(false);
}
},
[
enabled,
spacebarHeld,
toggleLocalVideoMuted,
toggleMicrophoneMuted,
setMicrophoneMuted,
setSpacebarHeld,
]
)
);
useEventTarget(
window,
"keyup",
useCallback(
(event: KeyboardEvent) => {
if (!enabled) return;
// Check if keyboard shortcuts are enabled
const keyboardShortcuts = getSetting("keyboard-shortcuts", true);
if (!keyboardShortcuts) {
return;
}
if (event.key === " ") {
setSpacebarHeld(false);
setMicrophoneMuted(true);
}
},
[enabled, setMicrophoneMuted, setSpacebarHeld]
)
);
useEventTarget(
window,
"blur",
useCallback(() => {
if (spacebarHeld) {
setSpacebarHeld(false);
setMicrophoneMuted(true);
}
}, [setMicrophoneMuted, setSpacebarHeld, spacebarHeld])
);
}

145
yarn.lock
View File

@@ -1795,7 +1795,7 @@
"@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/gen-mapping" "^0.3.0"
"@jridgewell/trace-mapping" "^0.3.9" "@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": "@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13":
version "1.4.14" version "1.4.14"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
@@ -1821,6 +1821,11 @@
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.3.1.tgz#b50a781709c81e10701004214340f25475a171a0" resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.3.1.tgz#b50a781709c81e10701004214340f25475a171a0"
integrity sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw== integrity sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw==
"@matrix-org/matrix-sdk-crypto-js@^0.1.0-alpha.2":
version "0.1.0-alpha.2"
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0-alpha.2.tgz#a09d0fea858e817da971a3c9f904632ef7b49eb6"
integrity sha512-oVkBCh9YP7H9i4gAoQbZzswniczfo/aIptNa4dxRi4Ff9lSvUCFv6Hvzi7C+90c0/PWZLXjIDTIAWZYmwyd2fA==
"@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz": "@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz":
version "3.2.8" version "3.2.8"
resolved "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz#8d53636d045e1776e2a2ec6613e57330dd9ce856" resolved "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz#8d53636d045e1776e2a2ec6613e57330dd9ce856"
@@ -2380,6 +2385,28 @@
"@sentry/utils" "6.19.7" "@sentry/utils" "6.19.7"
tslib "^1.9.3" tslib "^1.9.3"
"@sentry/bundler-plugin-core@0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-0.3.0.tgz#de35a908c01a383611274572156845db6e46d30b"
integrity sha512-484beABAjdJa6thVgzOC0hBdgVpC0kg5r3S88U0zx3b/i6CTwUemHwamh6+RZ/gu8ChmooWb6NznaBAlpHgxCA==
dependencies:
"@sentry/cli" "^2.10.0"
"@sentry/node" "^7.19.0"
"@sentry/tracing" "^7.19.0"
magic-string "0.27.0"
unplugin "0.10.1"
"@sentry/cli@^2.10.0":
version "2.11.0"
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.11.0.tgz#a324cd1ae98e7d206f5ed739dc40c9728eb0fce8"
integrity sha512-qfCf/R0VhmlWcdfu2rntejqbIgovx7FQTwFreQpbISlB/JS9xHF8KEEJXZTdDFoPCi2H9KHg4CPUsCNAKbAdMA==
dependencies:
https-proxy-agent "^5.0.0"
node-fetch "^2.6.7"
progress "^2.0.3"
proxy-from-env "^1.1.0"
which "^2.0.2"
"@sentry/core@6.19.7": "@sentry/core@6.19.7":
version "6.19.7" version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.19.7.tgz#156aaa56dd7fad8c89c145be6ad7a4f7209f9785" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.19.7.tgz#156aaa56dd7fad8c89c145be6ad7a4f7209f9785"
@@ -2391,6 +2418,15 @@
"@sentry/utils" "6.19.7" "@sentry/utils" "6.19.7"
tslib "^1.9.3" tslib "^1.9.3"
"@sentry/core@7.31.0":
version "7.31.0"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.31.0.tgz#2c1ec086cd86c097fc5c60703d33c848089597c7"
integrity sha512-IZS1MZznyBOPw7UEpZwq3t3aaaVhFB+r3KM4JYFSJRr7Ky9TjldXA3hadNUTztjYGgEC3u8kB9jXoRvNXM2hqA==
dependencies:
"@sentry/types" "7.31.0"
"@sentry/utils" "7.31.0"
tslib "^1.9.3"
"@sentry/hub@6.19.7": "@sentry/hub@6.19.7":
version "6.19.7" version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.19.7.tgz#58ad7776bbd31e9596a8ec46365b45cd8b9cfd11" resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.19.7.tgz#58ad7776bbd31e9596a8ec46365b45cd8b9cfd11"
@@ -2409,6 +2445,19 @@
"@sentry/types" "6.19.7" "@sentry/types" "6.19.7"
tslib "^1.9.3" tslib "^1.9.3"
"@sentry/node@^7.19.0":
version "7.31.0"
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.31.0.tgz#d6b6776f7c1daee0a41e7f97fc15f058435f1b1c"
integrity sha512-DBjPfThZ5CIC2G9/CVFRlSOP/QqF1IoZXNpTUPZkhQ1cjShJeERT64jMkTdk+RAStSTpEfF6J0rUy1NIyHHEoQ==
dependencies:
"@sentry/core" "7.31.0"
"@sentry/types" "7.31.0"
"@sentry/utils" "7.31.0"
cookie "^0.4.1"
https-proxy-agent "^5.0.0"
lru_map "^0.3.3"
tslib "^1.9.3"
"@sentry/react@^6.13.3": "@sentry/react@^6.13.3":
version "6.19.7" version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-6.19.7.tgz#58cc2d6da20f7d3b0df40638dfbbbc86c9c85caf" resolved "https://registry.yarnpkg.com/@sentry/react/-/react-6.19.7.tgz#58cc2d6da20f7d3b0df40638dfbbbc86c9c85caf"
@@ -2432,11 +2481,26 @@
"@sentry/utils" "6.19.7" "@sentry/utils" "6.19.7"
tslib "^1.9.3" tslib "^1.9.3"
"@sentry/tracing@^7.19.0":
version "7.31.0"
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.31.0.tgz#c37f1930aba05a4c461f655dc258eaa851e9a305"
integrity sha512-p/b9sOw2wwcDLp8p0bJ0oetgeEB1q/ueZaXDeBeSh+3GNKx6J4S3pcFpbMXDK8d2Ayd3P9Gvrm7y9Hc2ueJteg==
dependencies:
"@sentry/core" "7.31.0"
"@sentry/types" "7.31.0"
"@sentry/utils" "7.31.0"
tslib "^1.9.3"
"@sentry/types@6.19.7": "@sentry/types@6.19.7":
version "6.19.7" version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.7.tgz#c6b337912e588083fc2896eb012526cf7cfec7c7" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.7.tgz#c6b337912e588083fc2896eb012526cf7cfec7c7"
integrity sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg== integrity sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==
"@sentry/types@7.31.0":
version "7.31.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.31.0.tgz#c028519a660d76c4e8f18ba9e44ede45d314fcae"
integrity sha512-nFqo7wyMnapdSEdw1MD+cavDtD9x5QQmh/bwLEOb/euM0cHFJHYyD7CveY/mQng4HyEVWY+DCtX/7E3GcQ7Bdw==
"@sentry/types@^7.2.0": "@sentry/types@^7.2.0":
version "7.13.0" version "7.13.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.13.0.tgz#398e33e5c92ea0ce91e2c86e3ab003fe00c471a2" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.13.0.tgz#398e33e5c92ea0ce91e2c86e3ab003fe00c471a2"
@@ -2450,6 +2514,21 @@
"@sentry/types" "6.19.7" "@sentry/types" "6.19.7"
tslib "^1.9.3" tslib "^1.9.3"
"@sentry/utils@7.31.0":
version "7.31.0"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.31.0.tgz#507290984c941fca8f5c2621a4b8b0aca8fbfc10"
integrity sha512-B1KkvdfwlaqM7sDp3/yk2No7WsbMuLEywGRVOLzXeTqTLSBRBWyyYIudqPtx2LDds9anlUHj21zs9FKY+S3eiA==
dependencies:
"@sentry/types" "7.31.0"
tslib "^1.9.3"
"@sentry/vite-plugin@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-0.3.0.tgz#37d6a99ab7bf307b6ac3a5dc85ca16c52c2fff9c"
integrity sha512-clu0yfVk9ejk3l22NHrFUPqHzR9ukYccm7Q5qBKgMyLXnWGLRf4WahmzzuW9XHDu4s3tYVjV/rTTxGxLPT9dMQ==
dependencies:
"@sentry/bundler-plugin-core" "0.3.0"
"@sinclair/typebox@^0.24.1": "@sinclair/typebox@^0.24.1":
version "0.24.51" version "0.24.51"
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f"
@@ -5143,7 +5222,7 @@ cheerio@^1.0.0-rc.2:
parse5 "^7.0.0" parse5 "^7.0.0"
parse5-htmlparser2-tree-adapter "^7.0.0" parse5-htmlparser2-tree-adapter "^7.0.0"
"chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.1, chokidar@^3.4.2: "chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.1, chokidar@^3.4.2, chokidar@^3.5.3:
version "3.5.3" version "3.5.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
@@ -5532,6 +5611,11 @@ cookie@0.5.0:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
cookie@^0.4.1:
version "0.4.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
copy-concurrently@^1.0.0: copy-concurrently@^1.0.0:
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
@@ -8649,7 +8733,7 @@ https-browserify@^1.0.0:
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
integrity sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg== integrity sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==
https-proxy-agent@^5.0.1: https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1:
version "5.0.1" version "5.0.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
@@ -10199,11 +10283,23 @@ lru-cache@^6.0.0:
dependencies: dependencies:
yallist "^4.0.0" yallist "^4.0.0"
lru_map@^0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd"
integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==
lz-string@^1.4.4: lz-string@^1.4.4:
version "1.4.4" version "1.4.4"
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
integrity sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ== integrity sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==
magic-string@0.27.0:
version "0.27.0"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3"
integrity sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==
dependencies:
"@jridgewell/sourcemap-codec" "^1.4.13"
make-dir@^2.0.0, make-dir@^2.1.0: make-dir@^2.0.0, make-dir@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
@@ -10266,11 +10362,12 @@ matrix-events-sdk@0.0.1:
resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd"
integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#2c8eece5ca5333c6e6a14e8ed53f359ed0e9e9bf": "matrix-js-sdk@github:matrix-org/matrix-js-sdk#a34d06c7c24c3523a77f70c01d4e31c45e92aa6b":
version "21.2.0" version "23.0.0"
resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/2c8eece5ca5333c6e6a14e8ed53f359ed0e9e9bf" resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/a34d06c7c24c3523a77f70c01d4e31c45e92aa6b"
dependencies: dependencies:
"@babel/runtime" "^7.12.5" "@babel/runtime" "^7.12.5"
"@matrix-org/matrix-sdk-crypto-js" "^0.1.0-alpha.2"
another-json "^0.2.0" another-json "^0.2.0"
bs58 "^5.0.0" bs58 "^5.0.0"
content-type "^1.0.4" content-type "^1.0.4"
@@ -10278,9 +10375,9 @@ matrix-events-sdk@0.0.1:
matrix-events-sdk "0.0.1" matrix-events-sdk "0.0.1"
matrix-widget-api "^1.0.0" matrix-widget-api "^1.0.0"
p-retry "4" p-retry "4"
qs "^6.9.6"
sdp-transform "^2.14.1" sdp-transform "^2.14.1"
unhomoglyph "^1.0.6" unhomoglyph "^1.0.6"
uuid "9"
matrix-widget-api@^1.0.0: matrix-widget-api@^1.0.0:
version "1.1.1" version "1.1.1"
@@ -11848,6 +11945,11 @@ process@^0.11.10:
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
progress@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
promise-inflight@^1.0.1: promise-inflight@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
@@ -11918,6 +12020,11 @@ proxy-addr@~2.0.7:
forwarded "0.2.0" forwarded "0.2.0"
ipaddr.js "1.9.1" ipaddr.js "1.9.1"
proxy-from-env@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
prr@~1.0.1: prr@~1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@@ -11992,7 +12099,7 @@ qs@6.10.3:
dependencies: dependencies:
side-channel "^1.0.4" side-channel "^1.0.4"
qs@^6.10.0, qs@^6.9.6: qs@^6.10.0:
version "6.11.0" version "6.11.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
@@ -14051,6 +14158,16 @@ unpipe@1.0.0, unpipe@~1.0.0:
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
unplugin@0.10.1:
version "0.10.1"
resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-0.10.1.tgz#e00dc951c1901aef4124121057102a8c290e28b3"
integrity sha512-y1hdBitiLOJvCmer0/IGrMGmHplsm2oFRGWleoAJTRQ8aMHxHOe9gLntYlh1WNLKufBuQ2sOTrHF+KWH4xE8Ag==
dependencies:
acorn "^8.8.0"
chokidar "^3.5.3"
webpack-sources "^3.2.3"
webpack-virtual-modules "^0.4.5"
unset-value@^1.0.0: unset-value@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
@@ -14183,6 +14300,11 @@ utils-merge@1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
uuid@9:
version "9.0.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
uuid@^3.3.2: uuid@^3.3.2:
version "3.4.0" version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
@@ -14487,6 +14609,11 @@ webpack-virtual-modules@^0.2.2:
dependencies: dependencies:
debug "^3.0.0" debug "^3.0.0"
webpack-virtual-modules@^0.4.5:
version "0.4.6"
resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.4.6.tgz#3e4008230731f1db078d9cb6f68baf8571182b45"
integrity sha512-5tyDlKLqPfMqjT3Q9TAqf2YqjwmnUleZwzJi1A5qXnlBCdj2AtOJ6wAWdglTIDOPgOiOrXeBeFcsQ8+aGQ6QbA==
webpack@4: webpack@4:
version "4.46.0" version "4.46.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542"
@@ -14607,7 +14734,7 @@ which-typed-array@^1.1.2:
has-tostringtag "^1.0.0" has-tostringtag "^1.0.0"
is-typed-array "^1.1.9" is-typed-array "^1.1.9"
which@^2.0.1: which@^2.0.1, which@^2.0.2:
version "2.0.2" version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==