@peers-app/peers-ui 0.30.5 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -11,6 +11,8 @@ export { Typeahead, type TypeaheadItem } from "./components/typeahead";
11
11
  export { isDesktop, mainContentPath } from "./globals";
12
12
  export * from "./hooks";
13
13
  export { openLink } from "./host-shell/host-shell-consumer";
14
+ export * from "./local-network/local-network-access";
15
+ export * from "./local-network/local-network-offer";
14
16
  export * from "./operator-console/operator-console";
15
17
  export * from "./operator-console/operator-console-state";
16
18
  export { type GlobalOverlay, globalOverlays, registerGlobalOverlay, unregisterGlobalOverlay, } from "./root-layout/global-overlays";
package/dist/index.js CHANGED
@@ -32,6 +32,8 @@ Object.defineProperty(exports, "mainContentPath", { enumerable: true, get: funct
32
32
  __exportStar(require("./hooks"), exports);
33
33
  var host_shell_consumer_1 = require("./host-shell/host-shell-consumer");
34
34
  Object.defineProperty(exports, "openLink", { enumerable: true, get: function () { return host_shell_consumer_1.openLink; } });
35
+ __exportStar(require("./local-network/local-network-access"), exports);
36
+ __exportStar(require("./local-network/local-network-offer"), exports);
35
37
  __exportStar(require("./operator-console/operator-console"), exports);
36
38
  __exportStar(require("./operator-console/operator-console-state"), exports);
37
39
  var global_overlays_1 = require("./root-layout/global-overlays");
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Direct connections on the home network, as the UI sees them.
3
+ *
4
+ * In the PWA, Chrome gates connections to LAN addresses behind a site permission ("devices on
5
+ * your local network"). A denial sticks, so the app asks only when it can explain why and has a
6
+ * desktop to connect to: a card on the home screen, once, and a row on the Network page. The
7
+ * PWA fills {@link localNetworkAccess} and registers the dial with
8
+ * {@link setLocalNetworkConnectHandler}; other hosts leave it undefined and show nothing.
9
+ */
10
+ /**
11
+ * Chrome's local-network permission for peers.app: `prompt` until the user answers, then
12
+ * `granted` or `denied`. `unsupported` when the browser has no such permission to query.
13
+ */
14
+ export type LocalNetworkPermission = "granted" | "prompt" | "denied" | "unsupported";
15
+ /** One of the user's desktops the PWA can offer to connect to directly. */
16
+ export interface LocalNetworkDesktop {
17
+ deviceId: string;
18
+ /** What the user calls it, or a generic name. */
19
+ name: string;
20
+ }
21
+ /** What the PWA knows about reaching the user's desktops directly on the LAN. */
22
+ export interface LocalNetworkAccessState {
23
+ permission: LocalNetworkPermission;
24
+ /** The phone is on mobile data, where the home network isn't reachable. */
25
+ cellular: boolean;
26
+ /** A desktop of the user's that publishes a direct address; none means nothing to offer. */
27
+ desktop?: LocalNetworkDesktop;
28
+ /** A connect the user asked for is running (Chrome's prompt may be up). */
29
+ connecting: boolean;
30
+ /** The last connect the user asked for. */
31
+ lastResult?: {
32
+ ok: boolean;
33
+ message: string;
34
+ at: number;
35
+ };
36
+ /**
37
+ * Android may be blocking Chrome from the LAN: Chrome's own permission is granted, but direct
38
+ * dials to an online desktop fail at once. This is a heuristic, not an OS permission check.
39
+ */
40
+ androidBlocked: boolean;
41
+ }
42
+ /** Undefined outside the PWA, where the app reaches the LAN on its own. */
43
+ export declare const localNetworkAccess: import("@peers-app/peers-sdk").Observable<LocalNetworkAccessState | undefined>;
44
+ /** The user tapped Not now (or Connect) on the home-screen card: it isn't shown again. */
45
+ export declare const localNetworkOfferDismissed: import("@peers-app/peers-sdk").PersistentVar<boolean>;
46
+ /** The user dismissed the one-time notice that Android is blocking Chrome. */
47
+ export declare const localNetworkAndroidNoticeDismissed: import("@peers-app/peers-sdk").PersistentVar<boolean>;
48
+ /** The PWA registers the dial that a tap on Connect runs (it brings up Chrome's prompt). */
49
+ export declare function setLocalNetworkConnectHandler(handler: (() => Promise<void>) | undefined): void;
50
+ /**
51
+ * Runs the registered connect, if any. A failed dial lands in
52
+ * {@link LocalNetworkAccessState.lastResult}; anything thrown is logged, never left unhandled
53
+ * (the UI calls this without awaiting it).
54
+ */
55
+ export declare function connectOnLocalNetwork(): Promise<void>;
56
+ /** Whether the home-screen card should show now; see the module doc. */
57
+ export declare function shouldOfferLocalNetwork(state: LocalNetworkAccessState | undefined, dismissed: boolean): boolean;
58
+ /** The Android guidance, shared by the notice and the Network page. */
59
+ export declare const ANDROID_LOCAL_NETWORK_HELP = "Android may be blocking Chrome from your local network. Check Settings \u2192 Apps \u2192 Chrome \u2192 Permissions \u2192 Nearby devices \u2192 Allow. If it is already allowed, check the desktop and its firewall.";
60
+ /** The guidance for a permission the user denied in Chrome. */
61
+ export declare const CHROME_LOCAL_NETWORK_HELP = "Chrome is blocking peers.app from devices on your local network. To allow it: Chrome \u2192 Settings \u2192 Site settings \u2192 All sites \u2192 peers.app \u2192 allow devices on your local network.";
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ /**
3
+ * Direct connections on the home network, as the UI sees them.
4
+ *
5
+ * In the PWA, Chrome gates connections to LAN addresses behind a site permission ("devices on
6
+ * your local network"). A denial sticks, so the app asks only when it can explain why and has a
7
+ * desktop to connect to: a card on the home screen, once, and a row on the Network page. The
8
+ * PWA fills {@link localNetworkAccess} and registers the dial with
9
+ * {@link setLocalNetworkConnectHandler}; other hosts leave it undefined and show nothing.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.CHROME_LOCAL_NETWORK_HELP = exports.ANDROID_LOCAL_NETWORK_HELP = exports.localNetworkAndroidNoticeDismissed = exports.localNetworkOfferDismissed = exports.localNetworkAccess = void 0;
13
+ exports.setLocalNetworkConnectHandler = setLocalNetworkConnectHandler;
14
+ exports.connectOnLocalNetwork = connectOnLocalNetwork;
15
+ exports.shouldOfferLocalNetwork = shouldOfferLocalNetwork;
16
+ const peers_sdk_1 = require("@peers-app/peers-sdk");
17
+ /** Undefined outside the PWA, where the app reaches the LAN on its own. */
18
+ exports.localNetworkAccess = (0, peers_sdk_1.observable)(undefined);
19
+ /** The user tapped Not now (or Connect) on the home-screen card: it isn't shown again. */
20
+ exports.localNetworkOfferDismissed = (0, peers_sdk_1.deviceVar)("localNetwork:offerDismissed", {
21
+ defaultValue: false,
22
+ });
23
+ /** The user dismissed the one-time notice that Android is blocking Chrome. */
24
+ exports.localNetworkAndroidNoticeDismissed = (0, peers_sdk_1.deviceVar)("localNetwork:androidNoticeDismissed", { defaultValue: false });
25
+ let connectHandler;
26
+ /** The PWA registers the dial that a tap on Connect runs (it brings up Chrome's prompt). */
27
+ function setLocalNetworkConnectHandler(handler) {
28
+ connectHandler = handler;
29
+ }
30
+ /**
31
+ * Runs the registered connect, if any. A failed dial lands in
32
+ * {@link LocalNetworkAccessState.lastResult}; anything thrown is logged, never left unhandled
33
+ * (the UI calls this without awaiting it).
34
+ */
35
+ async function connectOnLocalNetwork() {
36
+ try {
37
+ await connectHandler?.();
38
+ }
39
+ catch (error) {
40
+ console.warn("[LocalNetwork] Connect failed", error);
41
+ }
42
+ }
43
+ /** Whether the home-screen card should show now; see the module doc. */
44
+ function shouldOfferLocalNetwork(state, dismissed) {
45
+ return (!!state &&
46
+ !dismissed &&
47
+ state.permission === "prompt" &&
48
+ !!state.desktop &&
49
+ !state.cellular &&
50
+ !state.connecting);
51
+ }
52
+ /** The Android guidance, shared by the notice and the Network page. */
53
+ exports.ANDROID_LOCAL_NETWORK_HELP = "Android may be blocking Chrome from your local network. Check Settings → Apps → Chrome → Permissions → Nearby devices → Allow. If it is already allowed, check the desktop and its firewall.";
54
+ /** The guidance for a permission the user denied in Chrome. */
55
+ exports.CHROME_LOCAL_NETWORK_HELP = "Chrome is blocking peers.app from devices on your local network. To allow it: Chrome → Settings → Site settings → All sites → peers.app → allow devices on your local network.";
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The home screen's one-time cards: the offer to connect directly on this Wi-Fi (which brings
3
+ * up Chrome's local-network prompt), and the notice when Android is blocking Chrome. Renders
4
+ * nothing outside the PWA or once dismissed.
5
+ */
6
+ export declare function LocalNetworkHomeCards(): import("react/jsx-runtime").JSX.Element | null;
7
+ /**
8
+ * The Network page's row for direct connections on the home network: the permission state, a
9
+ * Connect button while Chrome hasn't been asked, and how to undo a block. PWA only.
10
+ */
11
+ export declare function LocalNetworkRow(): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LocalNetworkHomeCards = LocalNetworkHomeCards;
4
+ exports.LocalNetworkRow = LocalNetworkRow;
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const hooks_1 = require("../hooks");
7
+ const local_network_access_1 = require("./local-network-access");
8
+ /**
9
+ * The home screen's one-time cards: the offer to connect directly on this Wi-Fi (which brings
10
+ * up Chrome's local-network prompt), and the notice when Android is blocking Chrome. Renders
11
+ * nothing outside the PWA or once dismissed.
12
+ */
13
+ function LocalNetworkHomeCards() {
14
+ const [state] = (0, hooks_1.useObservable)(local_network_access_1.localNetworkAccess);
15
+ const [offerDismissed] = (0, hooks_1.useObservable)(local_network_access_1.localNetworkOfferDismissed);
16
+ const [noticeDismissed] = (0, hooks_1.useObservable)(local_network_access_1.localNetworkAndroidNoticeDismissed);
17
+ if (state?.androidBlocked && !noticeDismissed) {
18
+ return ((0, jsx_runtime_1.jsx)("div", { className: "card mb-3", "data-testid": "local-network-android-notice", children: (0, jsx_runtime_1.jsxs)("div", { className: "card-body", children: [(0, jsx_runtime_1.jsx)("p", { className: "card-text mb-2", children: local_network_access_1.ANDROID_LOCAL_NETWORK_HELP }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "btn btn-sm btn-outline-secondary", onClick: () => (0, local_network_access_1.localNetworkAndroidNoticeDismissed)(true), children: "OK" })] }) }));
19
+ }
20
+ if (!(0, local_network_access_1.shouldOfferLocalNetwork)(state, offerDismissed))
21
+ return null;
22
+ return ((0, jsx_runtime_1.jsx)("div", { className: "card mb-3", "data-testid": "local-network-offer", children: (0, jsx_runtime_1.jsxs)("div", { className: "card-body", children: [(0, jsx_runtime_1.jsxs)("h6", { className: "card-title", children: [(0, jsx_runtime_1.jsx)("i", { className: "bi-wifi me-2" }), "Connect directly to your devices on this Wi-Fi"] }), (0, jsx_runtime_1.jsx)("p", { className: "card-text small mb-2", children: "Works even when Peers' server can't be reached. Chrome will ask to let peers.app connect to devices on your local network." }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "btn btn-sm btn-primary me-2", onClick: () => {
23
+ (0, local_network_access_1.localNetworkOfferDismissed)(true);
24
+ void (0, local_network_access_1.connectOnLocalNetwork)();
25
+ }, children: "Connect" }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "btn btn-sm btn-outline-secondary", onClick: () => (0, local_network_access_1.localNetworkOfferDismissed)(true), children: "Not now" })] }) }));
26
+ }
27
+ /**
28
+ * The Network page's row for direct connections on the home network: the permission state, a
29
+ * Connect button while Chrome hasn't been asked, and how to undo a block. PWA only.
30
+ */
31
+ function LocalNetworkRow() {
32
+ const [state] = (0, hooks_1.useObservable)(local_network_access_1.localNetworkAccess);
33
+ if (!state)
34
+ return null;
35
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "mt-2", "data-testid": "local-network-row", children: [(0, jsx_runtime_1.jsx)("strong", { children: "Direct on Wi-Fi:" }), " ", (0, jsx_runtime_1.jsx)(LocalNetworkStatus, { state: state })] }));
36
+ }
37
+ function LocalNetworkStatus({ state }) {
38
+ if (state.androidBlocked)
39
+ return (0, jsx_runtime_1.jsx)("span", { className: "text-warning", children: local_network_access_1.ANDROID_LOCAL_NETWORK_HELP });
40
+ if (state.permission === "denied")
41
+ return (0, jsx_runtime_1.jsx)("span", { className: "text-warning", children: local_network_access_1.CHROME_LOCAL_NETWORK_HELP });
42
+ if (state.permission === "unsupported")
43
+ return (0, jsx_runtime_1.jsx)("span", { className: "text-muted", children: "Not available in this browser" });
44
+ const result = state.lastResult && ((0, jsx_runtime_1.jsx)("span", { className: `ms-2 small ${state.lastResult.ok ? "text-success" : "text-warning"}`, children: state.lastResult.message }));
45
+ if (state.permission === "granted")
46
+ return ((0, jsx_runtime_1.jsxs)("span", { children: ["Allowed", state.cellular ? " (not used on mobile data)" : "", result] }));
47
+ if (!state.desktop)
48
+ return (0, jsx_runtime_1.jsx)("span", { className: "text-muted", children: "No desktop of yours offers a direct connection yet" });
49
+ return ((0, jsx_runtime_1.jsxs)("span", { children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "btn btn-sm btn-outline-primary", disabled: state.connecting || state.cellular, onClick: () => void (0, local_network_access_1.connectOnLocalNetwork)(), title: "Chrome will ask to let peers.app connect to devices on your local network", children: state.connecting ? "Connecting…" : `Connect to ${state.desktop.name}` }), state.cellular && (0, jsx_runtime_1.jsx)("span", { className: "ms-2 small text-muted", children: "Join your Wi-Fi first" }), result] }));
50
+ }
@@ -7,6 +7,7 @@ const react_1 = require("react");
7
7
  const loading_indicator_1 = require("../../components/loading-indicator");
8
8
  const trust_level_badge_1 = require("../../components/trust-level-badge");
9
9
  const hooks_1 = require("../../hooks");
10
+ const local_network_offer_1 = require("../../local-network/local-network-offer");
10
11
  const ui_loader_1 = require("../../ui-router/ui-loader");
11
12
  const connection_troubleshooter_1 = require("./connection-troubleshooter");
12
13
  const device_details_modal_1 = require("./device-details-modal");
@@ -178,7 +179,7 @@ function NetworkViewerList() {
178
179
  if (showTroubleshooter) {
179
180
  return (0, jsx_runtime_1.jsx)(connection_troubleshooter_1.ConnectionTroubleshooter, { onBack: () => setShowTroubleshooter(false) });
180
181
  }
181
- return ((0, jsx_runtime_1.jsxs)("div", { className: "container-fluid p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "d-flex justify-content-between align-items-center mb-4", children: [(0, jsx_runtime_1.jsx)("h2", { children: "Network Viewer" }), (0, jsx_runtime_1.jsxs)("div", { className: "d-flex gap-2", children: [(0, network_viewer_ipc_1.getNetworkViewerPlatformApi)()?.runDiagnostics && ((0, jsx_runtime_1.jsxs)("button", { className: "btn btn-sm btn-outline-warning", onClick: () => setShowTroubleshooter(true), title: "Run connection diagnostics", children: [(0, jsx_runtime_1.jsx)("i", { className: "bi bi-stethoscope me-1" }), "Troubleshoot"] })), (0, jsx_runtime_1.jsx)("button", { className: "btn btn-sm btn-outline-secondary", onClick: () => (0, network_viewer_section_1.networkViewerSection)("sync-recovery"), title: "Records that could not be materialized", children: "Sync recovery" }), (0, jsx_runtime_1.jsxs)("button", { className: "btn btn-sm btn-primary", onClick: handleRefresh, disabled: refreshing, children: [(0, jsx_runtime_1.jsx)("i", { className: `bi bi-arrow-clockwise ${refreshing ? "spin" : ""}` }), refreshing ? " Refreshing..." : " Refresh"] })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "card mb-2", children: (0, jsx_runtime_1.jsxs)("div", { className: "card-body", children: [(0, jsx_runtime_1.jsx)("h5", { className: "card-title", children: "Local Device" }), (0, jsx_runtime_1.jsxs)("div", { className: "row", children: [(0, jsx_runtime_1.jsxs)("div", { className: "col-md-6", children: [(0, jsx_runtime_1.jsx)("strong", { children: "Device ID:" }), " ", (0, jsx_runtime_1.jsx)("code", { className: "text-muted small", children: overview.localDeviceId })] }), (0, jsx_runtime_1.jsxs)("div", { className: "col-md-6", children: [(0, jsx_runtime_1.jsx)("strong", { children: "User ID:" }), " ", (0, jsx_runtime_1.jsx)("code", { className: "text-muted small", children: overview.localUserId })] })] })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "row mb-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "col-md-4", children: (0, jsx_runtime_1.jsx)("div", { className: "card", style: { height: "100%" }, children: (0, jsx_runtime_1.jsx)("div", { className: "card-body p-2", children: (0, jsx_runtime_1.jsx)(usage_graph_1.UsageGraph, { label: "Connections", fetchUsage: async () => {
182
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "container-fluid p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "d-flex justify-content-between align-items-center mb-4", children: [(0, jsx_runtime_1.jsx)("h2", { children: "Network Viewer" }), (0, jsx_runtime_1.jsxs)("div", { className: "d-flex gap-2", children: [(0, network_viewer_ipc_1.getNetworkViewerPlatformApi)()?.runDiagnostics && ((0, jsx_runtime_1.jsxs)("button", { className: "btn btn-sm btn-outline-warning", onClick: () => setShowTroubleshooter(true), title: "Run connection diagnostics", children: [(0, jsx_runtime_1.jsx)("i", { className: "bi bi-stethoscope me-1" }), "Troubleshoot"] })), (0, jsx_runtime_1.jsx)("button", { className: "btn btn-sm btn-outline-secondary", onClick: () => (0, network_viewer_section_1.networkViewerSection)("sync-recovery"), title: "Records that could not be materialized", children: "Sync recovery" }), (0, jsx_runtime_1.jsxs)("button", { className: "btn btn-sm btn-primary", onClick: handleRefresh, disabled: refreshing, children: [(0, jsx_runtime_1.jsx)("i", { className: `bi bi-arrow-clockwise ${refreshing ? "spin" : ""}` }), refreshing ? " Refreshing..." : " Refresh"] })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "card mb-2", children: (0, jsx_runtime_1.jsxs)("div", { className: "card-body", children: [(0, jsx_runtime_1.jsx)("h5", { className: "card-title", children: "Local Device" }), (0, jsx_runtime_1.jsxs)("div", { className: "row", children: [(0, jsx_runtime_1.jsxs)("div", { className: "col-md-6", children: [(0, jsx_runtime_1.jsx)("strong", { children: "Device ID:" }), " ", (0, jsx_runtime_1.jsx)("code", { className: "text-muted small", children: overview.localDeviceId })] }), (0, jsx_runtime_1.jsxs)("div", { className: "col-md-6", children: [(0, jsx_runtime_1.jsx)("strong", { children: "User ID:" }), " ", (0, jsx_runtime_1.jsx)("code", { className: "text-muted small", children: overview.localUserId })] })] }), (0, jsx_runtime_1.jsx)(local_network_offer_1.LocalNetworkRow, {})] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "row mb-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "col-md-4", children: (0, jsx_runtime_1.jsx)("div", { className: "card", style: { height: "100%" }, children: (0, jsx_runtime_1.jsx)("div", { className: "card-body p-2", children: (0, jsx_runtime_1.jsx)(usage_graph_1.UsageGraph, { label: "Connections", fetchUsage: async () => {
182
183
  const diagnostics = await (0, network_viewer_ipc_1.getNetworkDiagnosticsConsumer)();
183
184
  const { overview: currentOverview } = await diagnostics.tools.getOverview();
184
185
  return currentOverview.totalConnections;
@@ -44,6 +44,7 @@ const group_switcher_1 = require("../components/group-switcher");
44
44
  const router_1 = require("../components/router");
45
45
  const globals_1 = require("../globals");
46
46
  const hooks_1 = require("../hooks");
47
+ const local_network_offer_1 = require("../local-network/local-network-offer");
47
48
  const identity_routes_1 = require("../screens/identity/identity-routes");
48
49
  const color_mode_dropdown_1 = require("../screens/settings/color-mode-dropdown");
49
50
  const system_apps_1 = require("../system-apps");
@@ -351,7 +352,7 @@ function AppLauncherTab({ isMobile }) {
351
352
  }
352
353
  (0, tabs_state_1.goToTabPath)(appItem.path);
353
354
  };
354
- return ((0, jsx_runtime_1.jsxs)("div", { className: `container-fluid ${isMobile ? "p-2" : "p-4"}`, style: { maxHeight: "100%", overflowY: "auto" }, children: [(0, jsx_runtime_1.jsx)("div", { className: isMobile ? "mb-3" : "mb-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "position-relative", children: [(0, jsx_runtime_1.jsx)("i", { className: "bi-search position-absolute", style: {
355
+ return ((0, jsx_runtime_1.jsxs)("div", { className: `container-fluid ${isMobile ? "p-2" : "p-4"}`, style: { maxHeight: "100%", overflowY: "auto" }, children: [(0, jsx_runtime_1.jsx)(local_network_offer_1.LocalNetworkHomeCards, {}), (0, jsx_runtime_1.jsx)("div", { className: isMobile ? "mb-3" : "mb-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "position-relative", children: [(0, jsx_runtime_1.jsx)("i", { className: "bi-search position-absolute", style: {
355
356
  left: "12px",
356
357
  top: "50%",
357
358
  transform: "translateY(-50%)",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peers-app/peers-ui",
3
- "version": "0.30.5",
3
+ "version": "0.31.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/peers-app/peers-ui.git"
@@ -36,7 +36,7 @@
36
36
  "lint:fix": "biome check --write ."
37
37
  },
38
38
  "peerDependencies": {
39
- "@peers-app/peers-sdk": "^0.30.5",
39
+ "@peers-app/peers-sdk": "^0.31.0",
40
40
  "bootstrap": "^5.3.3",
41
41
  "react": "^18.0.0",
42
42
  "react-dom": "^18.0.0"
@@ -47,7 +47,7 @@
47
47
  "@babel/preset-react": "^7.24.1",
48
48
  "@babel/preset-typescript": "^7.27.1",
49
49
  "@biomejs/biome": "2.3.11",
50
- "@peers-app/peers-sdk": "0.30.5",
50
+ "@peers-app/peers-sdk": "0.31.0",
51
51
  "@testing-library/dom": "^10.4.0",
52
52
  "@testing-library/jest-dom": "^6.6.3",
53
53
  "@testing-library/react": "^16.3.0",