Merge branch 'livekit' into robin/berry

This commit is contained in:
Robin
2025-03-27 14:07:24 -04:00
22 changed files with 409 additions and 306 deletions

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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.
![MSC4195 compatible setup](MSC4195_setup.drawio.png)
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]

View File

@@ -5,7 +5,7 @@ import PackageDescription
let package = Package(
name: "EmbeddedElementCall",
platforms: [.iOS(.v17_6)],
platforms: [.iOS(.v17)],
products: [
.library(
name: "EmbeddedElementCall",

View File

@@ -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]);

View File

@@ -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"),

View File

@@ -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

View File

@@ -95,7 +95,7 @@ export const RegisterPage: FC = () => {
}
}
setClient?.({ client: newClient, session });
setClient?.(newClient, session);
PosthogAnalytics.instance.eventSignup.cacheSignupEnd(new Date());
};

View File

@@ -47,7 +47,7 @@ export function useRegisterPasswordlessUser(): UseRegisterPasswordlessUserType {
recaptchaResponse,
true,
);
setClient({ client, session });
setClient(client, session);
} catch (e) {
reset();
throw e;

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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");
});

View File

@@ -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}

View File

@@ -166,7 +166,6 @@ const widgetPostHangupProcedure = async (
logger.error("Failed to send close action", e);
}
widget.api.transport.stop();
PosthogAnalytics.instance.logout();
}
};

View File

@@ -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>

View File

@@ -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),
}),
[],
);

View File

@@ -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
View File

@@ -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