mirror of
https://github.com/vector-im/element-call.git
synced 2026-01-18 02:32:27 +00:00
Merge branch 'livekit' into robin/berry
This commit is contained in:
@@ -165,6 +165,10 @@ jobs:
|
||||
- name: Copy files
|
||||
run: rsync -a --delete --exclude .git element-call/embedded/ios/ element-call-swift
|
||||
|
||||
- name: Test build
|
||||
working-directory: element-call-swift
|
||||
run: swift build
|
||||
|
||||
- name: Get artifact version
|
||||
run: echo "ARTIFACT_VERSION=${VERSION:1}" >> "$GITHUB_ENV"
|
||||
|
||||
|
||||
12
README.md
12
README.md
@@ -97,14 +97,14 @@ deployment for three different sites A, B and C is depicted below.
|
||||
|
||||
MatrixRTC backend (according to
|
||||
[MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143))
|
||||
is announced by the homeserver's `.well-known/matrix/client` file and discovered
|
||||
is announced by the Matrix site's `.well-known/matrix/client` file and discovered
|
||||
via the `org.matrix.msc4143.rtc_foci` key, e.g.:
|
||||
|
||||
```json
|
||||
"org.matrix.msc4143.rtc_foci": [
|
||||
{
|
||||
"type": "livekit",
|
||||
"livekit_service_url": "https://someurl.com"
|
||||
"livekit_service_url": "https://matrix-rtc.example.com/livekit/jwt"
|
||||
},
|
||||
]
|
||||
```
|
||||
@@ -232,8 +232,8 @@ The easiest way to develop new test is to use the codegen feature of Playwright:
|
||||
npx playwright codegen
|
||||
```
|
||||
|
||||
This will record your action and write the test code for you. Use the tool bar to test visibility, text content,
|
||||
clicking.
|
||||
This will record your action and write the test code for you. Use the tool bar
|
||||
to test visibility, text content and clicking.
|
||||
|
||||
##### Investigate a failed test from the CI
|
||||
|
||||
@@ -251,8 +251,8 @@ Unzip the report then use this command to open the report in your browser:
|
||||
npx playwright show-report ~/Downloads/playwright-report/
|
||||
```
|
||||
|
||||
Under the failed test there is a small icon looking like "3 columns" (next to test name file name),
|
||||
click on it to see the live screenshots/console output.
|
||||
Under the failed test there is a small icon looking like "3 columns" (next to
|
||||
the test name file name), click on it to see the live screenshots/console output.
|
||||
|
||||
### Test Coverage
|
||||
|
||||
|
||||
@@ -5,12 +5,6 @@
|
||||
"server_name": "call-unstable.ems.host"
|
||||
}
|
||||
},
|
||||
"livekit": {
|
||||
"livekit_service_url": "https://livekit-jwt.call.element.dev"
|
||||
},
|
||||
"features": {
|
||||
"feature_use_device_session_member_events": true
|
||||
},
|
||||
"posthog": {
|
||||
"api_key": "phc_rXGHx9vDmyEvyRxPziYtdVIv0ahEv8A9uLWFcCi1WcU",
|
||||
"api_host": "https://posthog-element-call.element.io"
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 67 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 909 KiB After Width: | Height: | Size: 929 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 868 KiB After Width: | Height: | Size: 886 KiB |
@@ -30,8 +30,9 @@ required for Element Call to work properly:
|
||||
sync v2 API that allows them to correctly track the state of the room. This is
|
||||
required by Element Call to track room state reliably.
|
||||
|
||||
If you're using [Synapse](https://github.com/element-hq/synapse/) as your homeserver, you'll need
|
||||
to additionally add the following config items to `homeserver.yaml` to comply with Element Call:
|
||||
If you're using [Synapse](https://github.com/element-hq/synapse/) as your
|
||||
homeserver, you'll need to additionally add the following config items to
|
||||
`homeserver.yaml` to comply with Element Call:
|
||||
|
||||
```yaml
|
||||
experimental_features:
|
||||
@@ -64,35 +65,88 @@ required for each site deployment.
|
||||
|
||||

|
||||
|
||||
As depicted above, Element Call requires a
|
||||
As depicted above in the `example.com` site deployment, Element Call requires a
|
||||
[Livekit SFU](https://github.com/livekit/livekit) alongside a
|
||||
[Matrix Livekit JWT auth service](https://github.com/element-hq/lk-jwt-service)
|
||||
to implement
|
||||
[MSC4195: MatrixRTC using LiveKit backend](https://github.com/hughns/matrix-spec-proposals/blob/hughns/matrixrtc-livekit/proposals/4195-matrixrtc-livekit.md).
|
||||
|
||||
#### Matrix site endpoint routing
|
||||
|
||||
In the context of MatrixRTC, we suggest using a single hostname for backend
|
||||
communication by implementing endpoint routing within a reverse proxy setup. For
|
||||
the example above, this results in:
|
||||
| Service | Endpoint | Example |
|
||||
| -------- | ------- | ------- |
|
||||
| [Livekit SFU](https://github.com/livekit/livekit) WebSocket signalling connection | `/livekit/sfu` | `matrix-rtc.example.com/livekit/sfu` |
|
||||
| [Matrix Livekit JWT auth service](https://github.com/element-hq/lk-jwt-service) | `/livekit/jwt` | `matrix-rtc.example.com/livekit/jwt` |
|
||||
|
||||
Using Nginx, you can achieve this by:
|
||||
|
||||
```jsonc
|
||||
server {
|
||||
...
|
||||
location ^~ /livekit/jwt/ {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# JWT Service running at port 8080
|
||||
proxy_pass http://localhost:8080/;
|
||||
}
|
||||
|
||||
location ^~ /livekit/sfu/ {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_send_timeout 120;
|
||||
proxy_read_timeout 120;
|
||||
proxy_buffering off;
|
||||
|
||||
proxy_set_header Accept-Encoding gzip;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# LiveKit SFU websocket connection running at port 7880
|
||||
proxy_pass http://localhost:7880/;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### MatrixRTC backend announcement
|
||||
|
||||
> [!IMPORTANT]
|
||||
> As defined in
|
||||
> [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143)
|
||||
> MatrixRTC backend must be announced to the client via your **homeserver's
|
||||
> `.well-known/matrix/client`**. The configuration is a list of Foci configs:
|
||||
> MatrixRTC backend must be announced to the client via your **Matrix site's
|
||||
> `.well-known/matrix/client`** file (e.g.
|
||||
> `example.com/.well-known/matrix/client` matching the site deployment example
|
||||
> from above). The configuration is a list of Foci configs:
|
||||
|
||||
```json
|
||||
"org.matrix.msc4143.rtc_foci": [
|
||||
{
|
||||
"type": "livekit",
|
||||
"livekit_service_url": "https://someurl.com"
|
||||
},
|
||||
{
|
||||
"type": "livekit",
|
||||
"livekit_service_url": "https://livekit2.com"
|
||||
"livekit_service_url": "https://matrix-rtc.example.com"
|
||||
},
|
||||
{
|
||||
"type": "another_foci",
|
||||
"props_for_another_foci": "val"
|
||||
"type": "livekit",
|
||||
"livekit_service_url": "https://matrix-rtc-2.example.com"
|
||||
},
|
||||
{
|
||||
"type": "nextgen_new_foci_type",
|
||||
"props_for_nextgen_foci": "val"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Most `org.matrix.msc4143.rtc_foci` configurations will only have one entry in
|
||||
> the array
|
||||
|
||||
## Building Element Call
|
||||
|
||||
> [!NOTE]
|
||||
|
||||
@@ -5,7 +5,7 @@ import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "EmbeddedElementCall",
|
||||
platforms: [.iOS(.v17_6)],
|
||||
platforms: [.iOS(.v17)],
|
||||
products: [
|
||||
.library(
|
||||
name: "EmbeddedElementCall",
|
||||
|
||||
@@ -50,7 +50,7 @@ export type ValidClientState = {
|
||||
reactions: boolean;
|
||||
thumbnails: boolean;
|
||||
};
|
||||
setClient: (params?: SetClientParams) => void;
|
||||
setClient: (client: MatrixClient, session: Session) => void;
|
||||
};
|
||||
|
||||
export type AuthenticatedClient = {
|
||||
@@ -65,11 +65,6 @@ export type ErrorState = {
|
||||
error: Error;
|
||||
};
|
||||
|
||||
export type SetClientParams = {
|
||||
client: MatrixClient;
|
||||
session: Session;
|
||||
};
|
||||
|
||||
const ClientContext = createContext<ClientState | undefined>(undefined);
|
||||
|
||||
export const ClientContextProvider = ClientContext.Provider;
|
||||
@@ -79,7 +74,7 @@ export const useClientState = (): ClientState | undefined =>
|
||||
|
||||
export function useClient(): {
|
||||
client?: MatrixClient;
|
||||
setClient?: (params?: SetClientParams) => void;
|
||||
setClient?: (client: MatrixClient, session: Session) => void;
|
||||
} {
|
||||
let client;
|
||||
let setClient;
|
||||
@@ -96,7 +91,7 @@ export function useClient(): {
|
||||
// Plain representation of the `ClientContext` as a helper for old components that expected an object with multiple fields.
|
||||
export function useClientLegacy(): {
|
||||
client?: MatrixClient;
|
||||
setClient?: (params?: SetClientParams) => void;
|
||||
setClient?: (client: MatrixClient, session: Session) => void;
|
||||
passwordlessUser: boolean;
|
||||
loading: boolean;
|
||||
authenticated: boolean;
|
||||
@@ -160,7 +155,11 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
initializing.current = true;
|
||||
|
||||
loadClient()
|
||||
.then(setInitClientState)
|
||||
.then((initResult) => {
|
||||
setInitClientState(initResult);
|
||||
if (PosthogAnalytics.instance.isEnabled())
|
||||
PosthogAnalytics.instance.startListeningToSettingsChanges();
|
||||
})
|
||||
.catch((err) => logger.error(err))
|
||||
.finally(() => (initializing.current = false));
|
||||
}, []);
|
||||
@@ -196,24 +195,20 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
);
|
||||
|
||||
const setClient = useCallback(
|
||||
(clientParams?: SetClientParams) => {
|
||||
(client: MatrixClient, session: Session) => {
|
||||
const oldClient = initClientState?.client;
|
||||
const newClient = clientParams?.client;
|
||||
if (oldClient && oldClient !== newClient) {
|
||||
if (oldClient && oldClient !== client) {
|
||||
oldClient.stopClient();
|
||||
}
|
||||
|
||||
if (clientParams) {
|
||||
saveSession(clientParams.session);
|
||||
setInitClientState({
|
||||
widgetApi: null,
|
||||
client: clientParams.client,
|
||||
passwordlessUser: clientParams.session.passwordlessUser,
|
||||
});
|
||||
} else {
|
||||
clearSession();
|
||||
setInitClientState(null);
|
||||
}
|
||||
saveSession(session);
|
||||
setInitClientState({
|
||||
widgetApi: null,
|
||||
client,
|
||||
passwordlessUser: session.passwordlessUser,
|
||||
});
|
||||
if (PosthogAnalytics.instance.isEnabled())
|
||||
PosthogAnalytics.instance.startListeningToSettingsChanges();
|
||||
},
|
||||
[initClientState?.client],
|
||||
);
|
||||
@@ -229,6 +224,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
clearSession();
|
||||
setInitClientState(null);
|
||||
await navigate("/");
|
||||
PosthogAnalytics.instance.logout();
|
||||
PosthogAnalytics.instance.setRegistrationType(RegistrationType.Guest);
|
||||
}, [navigate, initClientState?.client]);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import posthog, {
|
||||
} from "posthog-js";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { type Subscription } from "rxjs";
|
||||
|
||||
import { widget } from "../widget";
|
||||
import {
|
||||
@@ -95,6 +96,7 @@ export class PosthogAnalytics {
|
||||
private anonymity = Anonymity.Disabled;
|
||||
private platformSuperProperties = {};
|
||||
private registrationType: RegistrationType = RegistrationType.Guest;
|
||||
private optInListener: Subscription | null = null;
|
||||
|
||||
public static hasInstance(): boolean {
|
||||
return Boolean(this.internalInstance);
|
||||
@@ -143,7 +145,6 @@ export class PosthogAnalytics {
|
||||
);
|
||||
this.enabled = false;
|
||||
}
|
||||
this.startListeningToSettingsChanges(); // Triggers maybeIdentifyUser
|
||||
}
|
||||
|
||||
private sanitizeProperties = (
|
||||
@@ -325,6 +326,8 @@ export class PosthogAnalytics {
|
||||
if (this.enabled) {
|
||||
this.posthog.reset();
|
||||
}
|
||||
this.optInListener?.unsubscribe();
|
||||
this.optInListener = null;
|
||||
this.setAnonymity(Anonymity.Disabled);
|
||||
}
|
||||
|
||||
@@ -403,7 +406,7 @@ export class PosthogAnalytics {
|
||||
}
|
||||
}
|
||||
|
||||
private startListeningToSettingsChanges(): void {
|
||||
public startListeningToSettingsChanges(): void {
|
||||
// Listen to account data changes from sync so we can observe changes to relevant flags and update.
|
||||
// This is called -
|
||||
// * On page load, when the account data is first received by sync
|
||||
@@ -412,7 +415,7 @@ export class PosthogAnalytics {
|
||||
// * When the user changes their preferences on this device
|
||||
// Note that for new accounts, pseudonymousAnalyticsOptIn won't be set, so updateAnonymityFromSettings
|
||||
// won't be called (i.e. this.anonymity will be left as the default, until the setting changes)
|
||||
optInAnalytics.value$.subscribe((optIn) => {
|
||||
this.optInListener ??= optInAnalytics.value$.subscribe((optIn) => {
|
||||
this.setAnonymity(optIn ? Anonymity.Pseudonymous : Anonymity.Disabled);
|
||||
this.maybeIdentifyUser().catch(() =>
|
||||
logger.log("Could not identify user"),
|
||||
|
||||
@@ -53,7 +53,7 @@ export const LoginPage: FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
setClient({ client, session });
|
||||
setClient(client, session);
|
||||
|
||||
const locationState = location.state;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
|
||||
@@ -95,7 +95,7 @@ export const RegisterPage: FC = () => {
|
||||
}
|
||||
}
|
||||
|
||||
setClient?.({ client: newClient, session });
|
||||
setClient?.(newClient, session);
|
||||
PosthogAnalytics.instance.eventSignup.cacheSignupEnd(new Date());
|
||||
};
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ export function useRegisterPasswordlessUser(): UseRegisterPasswordlessUserType {
|
||||
recaptchaResponse,
|
||||
true,
|
||||
);
|
||||
setClient({ client, session });
|
||||
setClient(client, session);
|
||||
} catch (e) {
|
||||
reset();
|
||||
throw e;
|
||||
|
||||
@@ -89,7 +89,7 @@ export const UnauthenticatedView: FC = () => {
|
||||
// @ts-ignore
|
||||
if (error.errcode === "M_ROOM_IN_USE") {
|
||||
setOnFinished(() => {
|
||||
setClient({ client, session });
|
||||
setClient(client, session);
|
||||
const aliasLocalpart = roomAliasLocalpartFromRoomName(roomName);
|
||||
navigate(`/${aliasLocalpart}`)?.catch((error) => {
|
||||
logger.error("Failed to navigate to alias localpart", error);
|
||||
@@ -111,7 +111,7 @@ export const UnauthenticatedView: FC = () => {
|
||||
if (!createRoomResult.password)
|
||||
throw new Error("Failed to create room with shared secret");
|
||||
|
||||
setClient({ client, session });
|
||||
setClient(client, session);
|
||||
await navigate(
|
||||
getRelativeRoomUrl(
|
||||
createRoomResult.roomId,
|
||||
|
||||
@@ -12,9 +12,9 @@ import { useEffect, useState } from "react";
|
||||
import { type LivekitFocus } from "matrix-js-sdk/src/matrixrtc/LivekitFocus";
|
||||
|
||||
import { useActiveLivekitFocus } from "../room/useActiveFocus";
|
||||
import { useGroupCallErrorBoundary } from "../room/useCallErrorBoundary.ts";
|
||||
import { FailToGetOpenIdToken } from "../utils/errors.ts";
|
||||
import { doNetworkOperationWithRetry } from "../utils/matrix.ts";
|
||||
import { useErrorBoundary } from "../useErrorBoundary";
|
||||
import { FailToGetOpenIdToken } from "../utils/errors";
|
||||
import { doNetworkOperationWithRetry } from "../utils/matrix";
|
||||
|
||||
export interface SFUConfig {
|
||||
url: string;
|
||||
@@ -41,7 +41,7 @@ export function useOpenIDSFU(
|
||||
const [sfuConfig, setSFUConfig] = useState<SFUConfig | undefined>(undefined);
|
||||
|
||||
const activeFocus = useActiveLivekitFocus(rtcSession);
|
||||
const { showGroupCallErrorBoundary } = useGroupCallErrorBoundary();
|
||||
const { showErrorBoundary } = useErrorBoundary();
|
||||
|
||||
useEffect(() => {
|
||||
if (activeFocus) {
|
||||
@@ -50,14 +50,14 @@ export function useOpenIDSFU(
|
||||
setSFUConfig(sfuConfig);
|
||||
},
|
||||
(e) => {
|
||||
showGroupCallErrorBoundary(new FailToGetOpenIdToken(e));
|
||||
showErrorBoundary(new FailToGetOpenIdToken(e));
|
||||
logger.error("Failed to get SFU config", e);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
setSFUConfig(undefined);
|
||||
}
|
||||
}, [client, activeFocus, showGroupCallErrorBoundary]);
|
||||
}, [client, activeFocus, showErrorBoundary]);
|
||||
|
||||
return sfuConfig;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,14 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { beforeEach, expect, type MockedFunction, test, vitest } from "vitest";
|
||||
import {
|
||||
beforeEach,
|
||||
expect,
|
||||
type MockedFunction,
|
||||
onTestFinished,
|
||||
test,
|
||||
vi,
|
||||
} from "vitest";
|
||||
import { render, waitFor, screen } from "@testing-library/react";
|
||||
import { type MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";
|
||||
@@ -15,6 +22,7 @@ import { BrowserRouter } from "react-router-dom";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { type RelationsContainer } from "matrix-js-sdk/src/models/relations-container";
|
||||
import { useState } from "react";
|
||||
import { TooltipProvider } from "@vector-im/compound-web";
|
||||
|
||||
import { type MuteStates } from "./MuteStates";
|
||||
import { prefetchSounds } from "../soundUtils";
|
||||
@@ -28,20 +36,33 @@ import {
|
||||
MockRTCSession,
|
||||
} from "../utils/test";
|
||||
import { GroupCallView } from "./GroupCallView";
|
||||
import { leaveRTCSession } from "../rtcSessionHelpers";
|
||||
import { type WidgetHelpers } from "../widget";
|
||||
import { LazyEventEmitter } from "../LazyEventEmitter";
|
||||
import { MatrixRTCFocusMissingError } from "../utils/errors";
|
||||
|
||||
vitest.mock("../soundUtils");
|
||||
vitest.mock("../useAudioContext");
|
||||
vitest.mock("./InCallView");
|
||||
vi.mock("../soundUtils");
|
||||
vi.mock("../useAudioContext");
|
||||
vi.mock("./InCallView");
|
||||
vi.mock("react-use-measure", () => ({
|
||||
default: (): [() => void, object] => [(): void => {}, {}],
|
||||
}));
|
||||
|
||||
vitest.mock("../rtcSessionHelpers", async (importOriginal) => {
|
||||
const enterRTCSession = vi.hoisted(() => vi.fn(async () => Promise.resolve()));
|
||||
const leaveRTCSession = vi.hoisted(() =>
|
||||
vi.fn(
|
||||
async (
|
||||
rtcSession: unknown,
|
||||
cause: unknown,
|
||||
promiseBeforeHangup = Promise.resolve(),
|
||||
) => await promiseBeforeHangup,
|
||||
),
|
||||
);
|
||||
|
||||
vi.mock("../rtcSessionHelpers", async (importOriginal) => {
|
||||
// TODO: perhaps there is a more elegant way to manage the type import here?
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
||||
const orig = await importOriginal<typeof import("../rtcSessionHelpers")>();
|
||||
vitest.spyOn(orig, "leaveRTCSession");
|
||||
return orig;
|
||||
return { ...orig, enterRTCSession, leaveRTCSession };
|
||||
});
|
||||
|
||||
let playSound: MockedFunction<
|
||||
@@ -55,11 +76,11 @@ const roomMembers = new Map([carol].map((p) => [p.userId, p]));
|
||||
const roomId = "!foo:bar";
|
||||
|
||||
beforeEach(() => {
|
||||
vitest.clearAllMocks();
|
||||
vi.clearAllMocks();
|
||||
(prefetchSounds as MockedFunction<typeof prefetchSounds>).mockResolvedValue({
|
||||
sound: new ArrayBuffer(0),
|
||||
});
|
||||
playSound = vitest.fn();
|
||||
playSound = vi.fn();
|
||||
(useAudioContext as MockedFunction<typeof useAudioContext>).mockReturnValue({
|
||||
playSound,
|
||||
});
|
||||
@@ -75,7 +96,10 @@ beforeEach(() => {
|
||||
);
|
||||
});
|
||||
|
||||
function createGroupCallView(widget: WidgetHelpers | null): {
|
||||
function createGroupCallView(
|
||||
widget: WidgetHelpers | null,
|
||||
joined = true,
|
||||
): {
|
||||
rtcSession: MockRTCSession;
|
||||
getByText: ReturnType<typeof render>["getByText"];
|
||||
} {
|
||||
@@ -88,7 +112,7 @@ function createGroupCallView(widget: WidgetHelpers | null): {
|
||||
const room = mockMatrixRoom({
|
||||
relations: {
|
||||
getChildEventsForEvent: () =>
|
||||
vitest.mocked({
|
||||
vi.mocked({
|
||||
getRelations: () => [],
|
||||
}),
|
||||
} as unknown as RelationsContainer,
|
||||
@@ -106,24 +130,27 @@ function createGroupCallView(widget: WidgetHelpers | null): {
|
||||
localRtcMember,
|
||||
[],
|
||||
).withMemberships(of([]));
|
||||
rtcSession.joined = joined;
|
||||
const muteState = {
|
||||
audio: { enabled: false },
|
||||
video: { enabled: false },
|
||||
} as MuteStates;
|
||||
const { getByText } = render(
|
||||
<BrowserRouter>
|
||||
<GroupCallView
|
||||
client={client}
|
||||
isPasswordlessUser={false}
|
||||
confineToRoom={false}
|
||||
preload={false}
|
||||
skipLobby={false}
|
||||
hideHeader={true}
|
||||
rtcSession={rtcSession as unknown as MatrixRTCSession}
|
||||
isJoined
|
||||
muteStates={muteState}
|
||||
widget={widget}
|
||||
/>
|
||||
<TooltipProvider>
|
||||
<GroupCallView
|
||||
client={client}
|
||||
isPasswordlessUser={false}
|
||||
confineToRoom={false}
|
||||
preload={false}
|
||||
skipLobby={false}
|
||||
hideHeader={true}
|
||||
rtcSession={rtcSession as unknown as MatrixRTCSession}
|
||||
isJoined={joined}
|
||||
muteStates={muteState}
|
||||
widget={widget}
|
||||
/>
|
||||
</TooltipProvider>
|
||||
</BrowserRouter>,
|
||||
);
|
||||
return {
|
||||
@@ -132,7 +159,7 @@ function createGroupCallView(widget: WidgetHelpers | null): {
|
||||
};
|
||||
}
|
||||
|
||||
test("will play a leave sound asynchronously in SPA mode", async () => {
|
||||
test("GroupCallView plays a leave sound asynchronously in SPA mode", async () => {
|
||||
const user = userEvent.setup();
|
||||
const { getByText, rtcSession } = createGroupCallView(null);
|
||||
const leaveButton = getByText("Leave");
|
||||
@@ -143,13 +170,13 @@ test("will play a leave sound asynchronously in SPA mode", async () => {
|
||||
"user",
|
||||
expect.any(Promise),
|
||||
);
|
||||
expect(rtcSession.leaveRoomSession).toHaveBeenCalledOnce();
|
||||
expect(leaveRTCSession).toHaveBeenCalledOnce();
|
||||
// Ensure that the playSound promise resolves within this test to avoid
|
||||
// impacting the results of other tests
|
||||
await waitFor(() => expect(leaveRTCSession).toHaveResolved());
|
||||
});
|
||||
|
||||
test("will play a leave sound synchronously in widget mode", async () => {
|
||||
test("GroupCallView plays a leave sound synchronously in widget mode", async () => {
|
||||
const user = userEvent.setup();
|
||||
const widget = {
|
||||
api: {
|
||||
@@ -158,7 +185,7 @@ test("will play a leave sound synchronously in widget mode", async () => {
|
||||
lazyActions: new LazyEventEmitter(),
|
||||
};
|
||||
let resolvePlaySound: () => void;
|
||||
playSound = vitest
|
||||
playSound = vi
|
||||
.fn()
|
||||
.mockReturnValue(
|
||||
new Promise<void>((resolve) => (resolvePlaySound = resolve)),
|
||||
@@ -183,7 +210,7 @@ test("will play a leave sound synchronously in widget mode", async () => {
|
||||
"user",
|
||||
expect.any(Promise),
|
||||
);
|
||||
expect(rtcSession.leaveRoomSession).toHaveBeenCalledOnce();
|
||||
expect(leaveRTCSession).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
test("GroupCallView leaves the session when an error occurs", async () => {
|
||||
@@ -205,8 +232,15 @@ test("GroupCallView leaves the session when an error occurs", async () => {
|
||||
"error",
|
||||
expect.any(Promise),
|
||||
);
|
||||
expect(rtcSession.leaveRoomSession).toHaveBeenCalledOnce();
|
||||
// Ensure that the playSound promise resolves within this test to avoid
|
||||
// impacting the results of other tests
|
||||
await waitFor(() => expect(leaveRTCSession).toHaveResolved());
|
||||
});
|
||||
|
||||
test("GroupCallView shows errors that occur during joining", async () => {
|
||||
const user = userEvent.setup();
|
||||
enterRTCSession.mockRejectedValue(new MatrixRTCFocusMissingError(""));
|
||||
onTestFinished(() => {
|
||||
enterRTCSession.mockReset();
|
||||
});
|
||||
createGroupCallView(null, false);
|
||||
await user.click(screen.getByRole("button", { name: "Join call" }));
|
||||
screen.getByText("Call is not supported");
|
||||
});
|
||||
|
||||
@@ -67,7 +67,6 @@ import {
|
||||
useSetting,
|
||||
} from "../settings/settings";
|
||||
import { useTypedEventEmitter } from "../useEvents";
|
||||
import { useGroupCallErrorBoundary } from "./useCallErrorBoundary.ts";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@@ -100,6 +99,11 @@ export const GroupCallView: FC<Props> = ({
|
||||
muteStates,
|
||||
widget,
|
||||
}) => {
|
||||
// Used to thread through any errors that occur outside the error boundary
|
||||
const [externalError, setExternalError] = useState<ElementCallError | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
const memberships = useMatrixRTCSessionMemberships(rtcSession);
|
||||
const leaveSoundContext = useLatest(
|
||||
useAudioContext({
|
||||
@@ -121,13 +125,11 @@ export const GroupCallView: FC<Props> = ({
|
||||
};
|
||||
}, [rtcSession]);
|
||||
|
||||
const { showGroupCallErrorBoundary } = useGroupCallErrorBoundary();
|
||||
|
||||
useTypedEventEmitter(
|
||||
rtcSession,
|
||||
MatrixRTCSessionEvent.MembershipManagerError,
|
||||
(error) => {
|
||||
showGroupCallErrorBoundary(
|
||||
setExternalError(
|
||||
new RTCSessionError(
|
||||
ErrorCode.MEMBERSHIP_MANAGER_UNRECOVERABLE,
|
||||
error.message ?? error,
|
||||
@@ -190,17 +192,17 @@ export const GroupCallView: FC<Props> = ({
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof ElementCallError) {
|
||||
showGroupCallErrorBoundary(e);
|
||||
setExternalError(e);
|
||||
} else {
|
||||
logger.error(`Unknown Error while entering RTC session`, e);
|
||||
const error = new UnknownCallError(
|
||||
e instanceof Error ? e : new Error("Unknown error", { cause: e }),
|
||||
);
|
||||
showGroupCallErrorBoundary(error);
|
||||
setExternalError(error);
|
||||
}
|
||||
}
|
||||
},
|
||||
[showGroupCallErrorBoundary],
|
||||
[setExternalError],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -422,7 +424,15 @@ export const GroupCallView: FC<Props> = ({
|
||||
);
|
||||
|
||||
let body: ReactNode;
|
||||
if (isJoined) {
|
||||
if (externalError) {
|
||||
// If an error was recorded within this component but outside
|
||||
// GroupCallErrorBoundary, create a component that rethrows the error from
|
||||
// within the error boundary, so it can be handled uniformly
|
||||
const ErrorComponent = (): ReactNode => {
|
||||
throw externalError;
|
||||
};
|
||||
body = <ErrorComponent />;
|
||||
} else if (isJoined) {
|
||||
body = (
|
||||
<>
|
||||
{shareModal}
|
||||
|
||||
@@ -166,7 +166,6 @@ const widgetPostHangupProcedure = async (
|
||||
logger.error("Failed to send close action", e);
|
||||
}
|
||||
widget.api.transport.stop();
|
||||
PosthogAnalytics.instance.logout();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -11,19 +11,19 @@ import { type ReactElement, useCallback } from "react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
|
||||
import { GroupCallErrorBoundary } from "./GroupCallErrorBoundary.tsx";
|
||||
import { useGroupCallErrorBoundary } from "./useCallErrorBoundary.ts";
|
||||
import { ConnectionLostError } from "../utils/errors.ts";
|
||||
import { GroupCallErrorBoundary } from "./room/GroupCallErrorBoundary";
|
||||
import { useErrorBoundary } from "./useErrorBoundary";
|
||||
import { ConnectionLostError } from "./utils/errors";
|
||||
|
||||
it("should show async error", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
const TestComponent = (): ReactElement => {
|
||||
const { showGroupCallErrorBoundary } = useGroupCallErrorBoundary();
|
||||
const { showErrorBoundary } = useErrorBoundary();
|
||||
|
||||
const onClick = useCallback((): void => {
|
||||
showGroupCallErrorBoundary(new ConnectionLostError());
|
||||
}, [showGroupCallErrorBoundary]);
|
||||
showErrorBoundary(new ConnectionLostError());
|
||||
}, [showErrorBoundary]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -7,18 +7,16 @@ Please see LICENSE in the repository root for full details.
|
||||
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
import type { ElementCallError } from "../utils/errors.ts";
|
||||
|
||||
export type UseErrorBoundaryApi = {
|
||||
showGroupCallErrorBoundary: (error: ElementCallError) => void;
|
||||
showErrorBoundary: (error: Error) => void;
|
||||
};
|
||||
|
||||
export function useGroupCallErrorBoundary(): UseErrorBoundaryApi {
|
||||
const [error, setError] = useState<ElementCallError | null>(null);
|
||||
export function useErrorBoundary(): UseErrorBoundaryApi {
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
|
||||
const memoized: UseErrorBoundaryApi = useMemo(
|
||||
() => ({
|
||||
showGroupCallErrorBoundary: (error: ElementCallError) => setError(error),
|
||||
showErrorBoundary: (error: Error) => setError(error),
|
||||
}),
|
||||
[],
|
||||
);
|
||||
@@ -286,8 +286,9 @@ export class MockRTCSession extends TypedEventEmitter<
|
||||
super();
|
||||
}
|
||||
|
||||
public isJoined(): true {
|
||||
return true;
|
||||
public joined = true;
|
||||
public isJoined(): boolean {
|
||||
return this.joined;
|
||||
}
|
||||
|
||||
public withMemberships(
|
||||
|
||||
386
yarn.lock
386
yarn.lock
@@ -2000,177 +2000,177 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/aix-ppc64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/aix-ppc64@npm:0.25.0"
|
||||
"@esbuild/aix-ppc64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/aix-ppc64@npm:0.25.1"
|
||||
conditions: os=aix & cpu=ppc64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/android-arm64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/android-arm64@npm:0.25.0"
|
||||
"@esbuild/android-arm64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/android-arm64@npm:0.25.1"
|
||||
conditions: os=android & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/android-arm@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/android-arm@npm:0.25.0"
|
||||
"@esbuild/android-arm@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/android-arm@npm:0.25.1"
|
||||
conditions: os=android & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/android-x64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/android-x64@npm:0.25.0"
|
||||
"@esbuild/android-x64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/android-x64@npm:0.25.1"
|
||||
conditions: os=android & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/darwin-arm64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/darwin-arm64@npm:0.25.0"
|
||||
"@esbuild/darwin-arm64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/darwin-arm64@npm:0.25.1"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/darwin-x64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/darwin-x64@npm:0.25.0"
|
||||
"@esbuild/darwin-x64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/darwin-x64@npm:0.25.1"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/freebsd-arm64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/freebsd-arm64@npm:0.25.0"
|
||||
"@esbuild/freebsd-arm64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/freebsd-arm64@npm:0.25.1"
|
||||
conditions: os=freebsd & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/freebsd-x64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/freebsd-x64@npm:0.25.0"
|
||||
"@esbuild/freebsd-x64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/freebsd-x64@npm:0.25.1"
|
||||
conditions: os=freebsd & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-arm64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/linux-arm64@npm:0.25.0"
|
||||
"@esbuild/linux-arm64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/linux-arm64@npm:0.25.1"
|
||||
conditions: os=linux & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-arm@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/linux-arm@npm:0.25.0"
|
||||
"@esbuild/linux-arm@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/linux-arm@npm:0.25.1"
|
||||
conditions: os=linux & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-ia32@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/linux-ia32@npm:0.25.0"
|
||||
"@esbuild/linux-ia32@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/linux-ia32@npm:0.25.1"
|
||||
conditions: os=linux & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-loong64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/linux-loong64@npm:0.25.0"
|
||||
"@esbuild/linux-loong64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/linux-loong64@npm:0.25.1"
|
||||
conditions: os=linux & cpu=loong64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-mips64el@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/linux-mips64el@npm:0.25.0"
|
||||
"@esbuild/linux-mips64el@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/linux-mips64el@npm:0.25.1"
|
||||
conditions: os=linux & cpu=mips64el
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-ppc64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/linux-ppc64@npm:0.25.0"
|
||||
"@esbuild/linux-ppc64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/linux-ppc64@npm:0.25.1"
|
||||
conditions: os=linux & cpu=ppc64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-riscv64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/linux-riscv64@npm:0.25.0"
|
||||
"@esbuild/linux-riscv64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/linux-riscv64@npm:0.25.1"
|
||||
conditions: os=linux & cpu=riscv64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-s390x@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/linux-s390x@npm:0.25.0"
|
||||
"@esbuild/linux-s390x@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/linux-s390x@npm:0.25.1"
|
||||
conditions: os=linux & cpu=s390x
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-x64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/linux-x64@npm:0.25.0"
|
||||
"@esbuild/linux-x64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/linux-x64@npm:0.25.1"
|
||||
conditions: os=linux & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/netbsd-arm64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/netbsd-arm64@npm:0.25.0"
|
||||
"@esbuild/netbsd-arm64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/netbsd-arm64@npm:0.25.1"
|
||||
conditions: os=netbsd & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/netbsd-x64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/netbsd-x64@npm:0.25.0"
|
||||
"@esbuild/netbsd-x64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/netbsd-x64@npm:0.25.1"
|
||||
conditions: os=netbsd & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/openbsd-arm64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/openbsd-arm64@npm:0.25.0"
|
||||
"@esbuild/openbsd-arm64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/openbsd-arm64@npm:0.25.1"
|
||||
conditions: os=openbsd & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/openbsd-x64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/openbsd-x64@npm:0.25.0"
|
||||
"@esbuild/openbsd-x64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/openbsd-x64@npm:0.25.1"
|
||||
conditions: os=openbsd & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/sunos-x64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/sunos-x64@npm:0.25.0"
|
||||
"@esbuild/sunos-x64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/sunos-x64@npm:0.25.1"
|
||||
conditions: os=sunos & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/win32-arm64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/win32-arm64@npm:0.25.0"
|
||||
"@esbuild/win32-arm64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/win32-arm64@npm:0.25.1"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/win32-ia32@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/win32-ia32@npm:0.25.0"
|
||||
"@esbuild/win32-ia32@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/win32-ia32@npm:0.25.1"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/win32-x64@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@esbuild/win32-x64@npm:0.25.0"
|
||||
"@esbuild/win32-x64@npm:0.25.1":
|
||||
version: 0.25.1
|
||||
resolution: "@esbuild/win32-x64@npm:0.25.1"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@@ -3998,135 +3998,142 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-android-arm-eabi@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-android-arm-eabi@npm:4.34.9"
|
||||
"@rollup/rollup-android-arm-eabi@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-android-arm-eabi@npm:4.37.0"
|
||||
conditions: os=android & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-android-arm64@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-android-arm64@npm:4.34.9"
|
||||
"@rollup/rollup-android-arm64@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-android-arm64@npm:4.37.0"
|
||||
conditions: os=android & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-darwin-arm64@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-darwin-arm64@npm:4.34.9"
|
||||
"@rollup/rollup-darwin-arm64@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-darwin-arm64@npm:4.37.0"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-darwin-x64@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-darwin-x64@npm:4.34.9"
|
||||
"@rollup/rollup-darwin-x64@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-darwin-x64@npm:4.37.0"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-freebsd-arm64@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-freebsd-arm64@npm:4.34.9"
|
||||
"@rollup/rollup-freebsd-arm64@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-freebsd-arm64@npm:4.37.0"
|
||||
conditions: os=freebsd & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-freebsd-x64@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-freebsd-x64@npm:4.34.9"
|
||||
"@rollup/rollup-freebsd-x64@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-freebsd-x64@npm:4.37.0"
|
||||
conditions: os=freebsd & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.34.9"
|
||||
"@rollup/rollup-linux-arm-gnueabihf@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.37.0"
|
||||
conditions: os=linux & cpu=arm & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.34.9"
|
||||
"@rollup/rollup-linux-arm-musleabihf@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.37.0"
|
||||
conditions: os=linux & cpu=arm & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.34.9"
|
||||
"@rollup/rollup-linux-arm64-gnu@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.37.0"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-linux-arm64-musl@npm:4.34.9"
|
||||
"@rollup/rollup-linux-arm64-musl@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-linux-arm64-musl@npm:4.37.0"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-loongarch64-gnu@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.34.9"
|
||||
"@rollup/rollup-linux-loongarch64-gnu@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.37.0"
|
||||
conditions: os=linux & cpu=loong64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-powerpc64le-gnu@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.34.9"
|
||||
"@rollup/rollup-linux-powerpc64le-gnu@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.37.0"
|
||||
conditions: os=linux & cpu=ppc64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.34.9"
|
||||
"@rollup/rollup-linux-riscv64-gnu@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.37.0"
|
||||
conditions: os=linux & cpu=riscv64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.34.9"
|
||||
"@rollup/rollup-linux-riscv64-musl@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.37.0"
|
||||
conditions: os=linux & cpu=riscv64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.37.0"
|
||||
conditions: os=linux & cpu=s390x & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-linux-x64-gnu@npm:4.34.9"
|
||||
"@rollup/rollup-linux-x64-gnu@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-linux-x64-gnu@npm:4.37.0"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-linux-x64-musl@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-linux-x64-musl@npm:4.34.9"
|
||||
"@rollup/rollup-linux-x64-musl@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-linux-x64-musl@npm:4.37.0"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.34.9"
|
||||
"@rollup/rollup-win32-arm64-msvc@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.37.0"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.34.9"
|
||||
"@rollup/rollup-win32-ia32-msvc@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.37.0"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc@npm:4.34.9":
|
||||
version: 4.34.9
|
||||
resolution: "@rollup/rollup-win32-x64-msvc@npm:4.34.9"
|
||||
"@rollup/rollup-win32-x64-msvc@npm:4.37.0":
|
||||
version: 4.37.0
|
||||
resolution: "@rollup/rollup-win32-x64-msvc@npm:4.37.0"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@@ -7186,34 +7193,34 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"esbuild@npm:^0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "esbuild@npm:0.25.0"
|
||||
version: 0.25.1
|
||||
resolution: "esbuild@npm:0.25.1"
|
||||
dependencies:
|
||||
"@esbuild/aix-ppc64": "npm:0.25.0"
|
||||
"@esbuild/android-arm": "npm:0.25.0"
|
||||
"@esbuild/android-arm64": "npm:0.25.0"
|
||||
"@esbuild/android-x64": "npm:0.25.0"
|
||||
"@esbuild/darwin-arm64": "npm:0.25.0"
|
||||
"@esbuild/darwin-x64": "npm:0.25.0"
|
||||
"@esbuild/freebsd-arm64": "npm:0.25.0"
|
||||
"@esbuild/freebsd-x64": "npm:0.25.0"
|
||||
"@esbuild/linux-arm": "npm:0.25.0"
|
||||
"@esbuild/linux-arm64": "npm:0.25.0"
|
||||
"@esbuild/linux-ia32": "npm:0.25.0"
|
||||
"@esbuild/linux-loong64": "npm:0.25.0"
|
||||
"@esbuild/linux-mips64el": "npm:0.25.0"
|
||||
"@esbuild/linux-ppc64": "npm:0.25.0"
|
||||
"@esbuild/linux-riscv64": "npm:0.25.0"
|
||||
"@esbuild/linux-s390x": "npm:0.25.0"
|
||||
"@esbuild/linux-x64": "npm:0.25.0"
|
||||
"@esbuild/netbsd-arm64": "npm:0.25.0"
|
||||
"@esbuild/netbsd-x64": "npm:0.25.0"
|
||||
"@esbuild/openbsd-arm64": "npm:0.25.0"
|
||||
"@esbuild/openbsd-x64": "npm:0.25.0"
|
||||
"@esbuild/sunos-x64": "npm:0.25.0"
|
||||
"@esbuild/win32-arm64": "npm:0.25.0"
|
||||
"@esbuild/win32-ia32": "npm:0.25.0"
|
||||
"@esbuild/win32-x64": "npm:0.25.0"
|
||||
"@esbuild/aix-ppc64": "npm:0.25.1"
|
||||
"@esbuild/android-arm": "npm:0.25.1"
|
||||
"@esbuild/android-arm64": "npm:0.25.1"
|
||||
"@esbuild/android-x64": "npm:0.25.1"
|
||||
"@esbuild/darwin-arm64": "npm:0.25.1"
|
||||
"@esbuild/darwin-x64": "npm:0.25.1"
|
||||
"@esbuild/freebsd-arm64": "npm:0.25.1"
|
||||
"@esbuild/freebsd-x64": "npm:0.25.1"
|
||||
"@esbuild/linux-arm": "npm:0.25.1"
|
||||
"@esbuild/linux-arm64": "npm:0.25.1"
|
||||
"@esbuild/linux-ia32": "npm:0.25.1"
|
||||
"@esbuild/linux-loong64": "npm:0.25.1"
|
||||
"@esbuild/linux-mips64el": "npm:0.25.1"
|
||||
"@esbuild/linux-ppc64": "npm:0.25.1"
|
||||
"@esbuild/linux-riscv64": "npm:0.25.1"
|
||||
"@esbuild/linux-s390x": "npm:0.25.1"
|
||||
"@esbuild/linux-x64": "npm:0.25.1"
|
||||
"@esbuild/netbsd-arm64": "npm:0.25.1"
|
||||
"@esbuild/netbsd-x64": "npm:0.25.1"
|
||||
"@esbuild/openbsd-arm64": "npm:0.25.1"
|
||||
"@esbuild/openbsd-x64": "npm:0.25.1"
|
||||
"@esbuild/sunos-x64": "npm:0.25.1"
|
||||
"@esbuild/win32-arm64": "npm:0.25.1"
|
||||
"@esbuild/win32-ia32": "npm:0.25.1"
|
||||
"@esbuild/win32-x64": "npm:0.25.1"
|
||||
dependenciesMeta:
|
||||
"@esbuild/aix-ppc64":
|
||||
optional: true
|
||||
@@ -7267,7 +7274,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
esbuild: bin/esbuild
|
||||
checksum: 10c0/5767b72da46da3cfec51661647ec850ddbf8a8d0662771139f10ef0692a8831396a0004b2be7966cecdb08264fb16bdc16290dcecd92396fac5f12d722fa013d
|
||||
checksum: 10c0/80fca30dd0f21aec23fdfab34f0a8d5f55df5097dd7f475f2ab561d45662c32ee306f5649071cd1a0ba0614b164c48ca3dc3ee1551a4daf204b8af90e4d893f5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9737,11 +9744,11 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"nanoid@npm:^3.3.8":
|
||||
version: 3.3.8
|
||||
resolution: "nanoid@npm:3.3.8"
|
||||
version: 3.3.11
|
||||
resolution: "nanoid@npm:3.3.11"
|
||||
bin:
|
||||
nanoid: bin/nanoid.cjs
|
||||
checksum: 10c0/4b1bb29f6cfebf3be3bc4ad1f1296fb0a10a3043a79f34fbffe75d1621b4318319211cd420549459018ea3592f0d2f159247a6f874911d6d26eaaadda2478120
|
||||
checksum: 10c0/40e7f70b3d15f725ca072dfc4f74e81fcf1fbb02e491cf58ac0c79093adc9b0a73b152bcde57df4b79cd097e13023d7504acb38404a4da7bc1cd8e887b82fe0b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -11483,28 +11490,29 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"rollup@npm:^4.30.1":
|
||||
version: 4.34.9
|
||||
resolution: "rollup@npm:4.34.9"
|
||||
version: 4.37.0
|
||||
resolution: "rollup@npm:4.37.0"
|
||||
dependencies:
|
||||
"@rollup/rollup-android-arm-eabi": "npm:4.34.9"
|
||||
"@rollup/rollup-android-arm64": "npm:4.34.9"
|
||||
"@rollup/rollup-darwin-arm64": "npm:4.34.9"
|
||||
"@rollup/rollup-darwin-x64": "npm:4.34.9"
|
||||
"@rollup/rollup-freebsd-arm64": "npm:4.34.9"
|
||||
"@rollup/rollup-freebsd-x64": "npm:4.34.9"
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "npm:4.34.9"
|
||||
"@rollup/rollup-linux-arm-musleabihf": "npm:4.34.9"
|
||||
"@rollup/rollup-linux-arm64-gnu": "npm:4.34.9"
|
||||
"@rollup/rollup-linux-arm64-musl": "npm:4.34.9"
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "npm:4.34.9"
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "npm:4.34.9"
|
||||
"@rollup/rollup-linux-riscv64-gnu": "npm:4.34.9"
|
||||
"@rollup/rollup-linux-s390x-gnu": "npm:4.34.9"
|
||||
"@rollup/rollup-linux-x64-gnu": "npm:4.34.9"
|
||||
"@rollup/rollup-linux-x64-musl": "npm:4.34.9"
|
||||
"@rollup/rollup-win32-arm64-msvc": "npm:4.34.9"
|
||||
"@rollup/rollup-win32-ia32-msvc": "npm:4.34.9"
|
||||
"@rollup/rollup-win32-x64-msvc": "npm:4.34.9"
|
||||
"@rollup/rollup-android-arm-eabi": "npm:4.37.0"
|
||||
"@rollup/rollup-android-arm64": "npm:4.37.0"
|
||||
"@rollup/rollup-darwin-arm64": "npm:4.37.0"
|
||||
"@rollup/rollup-darwin-x64": "npm:4.37.0"
|
||||
"@rollup/rollup-freebsd-arm64": "npm:4.37.0"
|
||||
"@rollup/rollup-freebsd-x64": "npm:4.37.0"
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "npm:4.37.0"
|
||||
"@rollup/rollup-linux-arm-musleabihf": "npm:4.37.0"
|
||||
"@rollup/rollup-linux-arm64-gnu": "npm:4.37.0"
|
||||
"@rollup/rollup-linux-arm64-musl": "npm:4.37.0"
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "npm:4.37.0"
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "npm:4.37.0"
|
||||
"@rollup/rollup-linux-riscv64-gnu": "npm:4.37.0"
|
||||
"@rollup/rollup-linux-riscv64-musl": "npm:4.37.0"
|
||||
"@rollup/rollup-linux-s390x-gnu": "npm:4.37.0"
|
||||
"@rollup/rollup-linux-x64-gnu": "npm:4.37.0"
|
||||
"@rollup/rollup-linux-x64-musl": "npm:4.37.0"
|
||||
"@rollup/rollup-win32-arm64-msvc": "npm:4.37.0"
|
||||
"@rollup/rollup-win32-ia32-msvc": "npm:4.37.0"
|
||||
"@rollup/rollup-win32-x64-msvc": "npm:4.37.0"
|
||||
"@types/estree": "npm:1.0.6"
|
||||
fsevents: "npm:~2.3.2"
|
||||
dependenciesMeta:
|
||||
@@ -11534,6 +11542,8 @@ __metadata:
|
||||
optional: true
|
||||
"@rollup/rollup-linux-riscv64-gnu":
|
||||
optional: true
|
||||
"@rollup/rollup-linux-riscv64-musl":
|
||||
optional: true
|
||||
"@rollup/rollup-linux-s390x-gnu":
|
||||
optional: true
|
||||
"@rollup/rollup-linux-x64-gnu":
|
||||
@@ -11550,7 +11560,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
rollup: dist/bin/rollup
|
||||
checksum: 10c0/dd0be1f7c4f8a93040026be13ecc39259fb55313db0dac7eafd97a3ac01ab4584e6b1a8afd86b0259dcf391699d5560a678abe6c0729af0aa4f2d5df70f05c8c
|
||||
checksum: 10c0/2e00382e08938636edfe0a7547ea2eaa027205dc0b6ff85d8b82be0fbe55a4ef88a1995fee2a5059e33dbccf12d1376c236825353afb89c96298cc95c5160a46
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -13091,8 +13101,8 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"vite@npm:^5.0.0 || ^6.0.0, vite@npm:^6.0.0":
|
||||
version: 6.2.0
|
||||
resolution: "vite@npm:6.2.0"
|
||||
version: 6.2.3
|
||||
resolution: "vite@npm:6.2.3"
|
||||
dependencies:
|
||||
esbuild: "npm:^0.25.0"
|
||||
fsevents: "npm:~2.3.3"
|
||||
@@ -13138,7 +13148,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
vite: bin/vite.js
|
||||
checksum: 10c0/db62c93d4a823e805c6f8429de035528b3c35cc7f6de4948b41e0528f94ed2ac55047d90f8534f626ef3a04e682883b570fe5ec9ee92f51bf0c3c210dbec5ac1
|
||||
checksum: 10c0/ba6ad7e83e5a63fb0b6f62d3a3963624b8784bdc1bfa2a83e16cf268fb58c76bd9f8e69f39ed34bf8711cdb8fd7702916f878781da53c232c34ef7a85e0600cf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user