diff --git a/__tests__/components/brain/ContentTabContext.test.tsx b/__tests__/components/brain/ContentTabContext.test.tsx
index 1e06b7d940..765989273a 100644
--- a/__tests__/components/brain/ContentTabContext.test.tsx
+++ b/__tests__/components/brain/ContentTabContext.test.tsx
@@ -1,34 +1,47 @@
-import React from 'react';
-import { renderHook, act } from '@testing-library/react';
-import { ContentTabProvider, useContentTab, WaveVotingState } from '@/components/brain/ContentTabContext';
-import { MyStreamWaveTab } from '@/types/waves.types';
+import React from "react";
+import { renderHook, act } from "@testing-library/react";
+import {
+ ContentTabProvider,
+ useContentTab,
+ WaveVotingState,
+} from "@/components/brain/ContentTabContext";
+import { MyStreamWaveTab } from "@/types/waves.types";
function setup() {
- const wrapper: React.FC<{children: React.ReactNode}> = ({ children }) => (
+ const wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
{children}
);
return renderHook(() => useContentTab(), { wrapper });
}
-describe('ContentTabContext', () => {
- it('defaults to CHAT when params null', () => {
+describe("ContentTabContext", () => {
+ it("defaults to CHAT when params null", () => {
const { result } = setup();
act(() => result.current.updateAvailableTabs(null));
expect(result.current.availableTabs).toEqual([MyStreamWaveTab.CHAT]);
expect(result.current.activeContentTab).toBe(MyStreamWaveTab.CHAT);
});
- it('prevents setting unavailable tab', () => {
+ it("prevents setting unavailable tab", () => {
const { result } = setup();
- act(() => result.current.updateAvailableTabs({ isChatWave: true, isMemesWave: false, votingState: WaveVotingState.NOT_STARTED, hasFirstDecisionPassed: false }));
+ act(() =>
+ result.current.updateAvailableTabs({
+ waveId: "chat-wave",
+ isChatWave: true,
+ isMemesWave: false,
+ votingState: WaveVotingState.NOT_STARTED,
+ hasFirstDecisionPassed: false,
+ })
+ );
act(() => result.current.setActiveContentTab(MyStreamWaveTab.WINNERS));
expect(result.current.activeContentTab).toBe(MyStreamWaveTab.CHAT);
});
- it('sets meme wave tabs correctly', () => {
+ it("sets meme wave tabs correctly", () => {
const { result } = setup();
act(() =>
result.current.updateAvailableTabs({
+ waveId: "meme-wave",
isChatWave: false,
isMemesWave: true,
votingState: WaveVotingState.NOT_STARTED,
@@ -36,11 +49,96 @@ describe('ContentTabContext', () => {
})
);
expect(result.current.availableTabs).toEqual([
- MyStreamWaveTab.CHAT,
MyStreamWaveTab.LEADERBOARD,
+ MyStreamWaveTab.CHAT,
MyStreamWaveTab.MY_VOTES,
MyStreamWaveTab.OUTCOME,
MyStreamWaveTab.FAQ,
]);
});
+
+ it("defaults to LEADERBOARD for memes waves", () => {
+ const { result } = setup();
+ act(() =>
+ result.current.updateAvailableTabs({
+ waveId: "meme-wave",
+ isChatWave: false,
+ isMemesWave: true,
+ votingState: WaveVotingState.NOT_STARTED,
+ hasFirstDecisionPassed: false,
+ })
+ );
+ expect(result.current.activeContentTab).toBe(MyStreamWaveTab.LEADERBOARD);
+ });
+
+ it("defaults to CHAT for non-memes waves", () => {
+ const { result } = setup();
+ act(() =>
+ result.current.updateAvailableTabs({
+ waveId: "default-wave",
+ isChatWave: false,
+ isMemesWave: false,
+ votingState: WaveVotingState.NOT_STARTED,
+ hasFirstDecisionPassed: false,
+ })
+ );
+ expect(result.current.activeContentTab).toBe(MyStreamWaveTab.CHAT);
+ });
+
+ it("restores stored tab for memes wave even when it is CHAT", () => {
+ const { result } = setup();
+ act(() =>
+ result.current.updateAvailableTabs({
+ waveId: "meme-wave",
+ isChatWave: false,
+ isMemesWave: true,
+ votingState: WaveVotingState.NOT_STARTED,
+ hasFirstDecisionPassed: false,
+ })
+ );
+ act(() => result.current.setActiveContentTab(MyStreamWaveTab.CHAT));
+ act(() =>
+ result.current.updateAvailableTabs({
+ waveId: "default-wave",
+ isChatWave: false,
+ isMemesWave: false,
+ votingState: WaveVotingState.NOT_STARTED,
+ hasFirstDecisionPassed: false,
+ })
+ );
+ act(() =>
+ result.current.updateAvailableTabs({
+ waveId: "meme-wave",
+ isChatWave: false,
+ isMemesWave: true,
+ votingState: WaveVotingState.NOT_STARTED,
+ hasFirstDecisionPassed: false,
+ })
+ );
+ expect(result.current.activeContentTab).toBe(MyStreamWaveTab.CHAT);
+ });
+
+ it("falls back to default when stored tab is unavailable", () => {
+ const { result } = setup();
+ act(() =>
+ result.current.updateAvailableTabs({
+ waveId: "default-wave",
+ isChatWave: false,
+ isMemesWave: false,
+ votingState: WaveVotingState.NOT_STARTED,
+ hasFirstDecisionPassed: true,
+ })
+ );
+ act(() => result.current.setActiveContentTab(MyStreamWaveTab.WINNERS));
+ act(() =>
+ result.current.updateAvailableTabs({
+ waveId: "default-wave",
+ isChatWave: false,
+ isMemesWave: false,
+ votingState: WaveVotingState.NOT_STARTED,
+ hasFirstDecisionPassed: false,
+ })
+ );
+ expect(result.current.activeContentTab).toBe(MyStreamWaveTab.CHAT);
+ });
});
diff --git a/components/brain/ContentTabContext.tsx b/components/brain/ContentTabContext.tsx
index 2b289fa4e5..c88a899c3d 100644
--- a/components/brain/ContentTabContext.tsx
+++ b/components/brain/ContentTabContext.tsx
@@ -4,12 +4,14 @@ import type { ReactNode } from "react";
import React, {
createContext,
useState,
+ useEffect,
useContext,
useCallback,
useMemo,
useRef,
} from "react";
import { MyStreamWaveTab } from "@/types/waves.types";
+import useLocalPreference from "@/hooks/useLocalPreference";
export enum WaveVotingState {
NOT_STARTED = "NOT_STARTED",
@@ -33,6 +35,55 @@ interface ContentTabContextType {
updateAvailableTabs: (params: WaveTabParams | null) => void;
}
+const MEMES_WAVE_LAST_TAB_STORAGE_KEY = "memes_wave_last_tab_by_id";
+
+const isValidWaveTab = (value: unknown): value is MyStreamWaveTab =>
+ Object.values(MyStreamWaveTab).includes(value as MyStreamWaveTab);
+
+const isValidWaveTabMap = (
+ value: unknown
+): value is Record => {
+ if (value === null || value === undefined || typeof value !== "object") {
+ return false;
+ }
+
+ return Object.values(value).every((tab) => isValidWaveTab(tab));
+};
+
+const buildMemesTabs = (
+ votingState: WaveVotingState,
+ hasFirstDecisionPassed: boolean
+) => {
+ const tabs: MyStreamWaveTab[] = [];
+ if (votingState !== WaveVotingState.ENDED) {
+ tabs.push(MyStreamWaveTab.LEADERBOARD);
+ }
+ tabs.push(MyStreamWaveTab.CHAT);
+ if (hasFirstDecisionPassed) {
+ tabs.push(MyStreamWaveTab.WINNERS);
+ }
+ tabs.push(MyStreamWaveTab.MY_VOTES);
+ tabs.push(MyStreamWaveTab.OUTCOME);
+ tabs.push(MyStreamWaveTab.FAQ);
+ return tabs;
+};
+
+const buildDefaultTabs = (
+ votingState: WaveVotingState,
+ hasFirstDecisionPassed: boolean
+) => {
+ const tabs: MyStreamWaveTab[] = [MyStreamWaveTab.CHAT];
+ if (votingState !== WaveVotingState.ENDED) {
+ tabs.push(MyStreamWaveTab.LEADERBOARD);
+ }
+ if (hasFirstDecisionPassed) {
+ tabs.push(MyStreamWaveTab.WINNERS);
+ }
+ tabs.push(MyStreamWaveTab.OUTCOME);
+ tabs.push(MyStreamWaveTab.MY_VOTES);
+ return tabs;
+};
+
// Create the context with a default value
const ContentTabContext = createContext({
activeContentTab: MyStreamWaveTab.CHAT,
@@ -45,12 +96,30 @@ const ContentTabContext = createContext({
export const ContentTabProvider: React.FC<{ children: ReactNode }> = ({
children,
}) => {
+ const [tabsByWaveId, setTabsByWaveId] = useLocalPreference<
+ Record
+ >(MEMES_WAVE_LAST_TAB_STORAGE_KEY, {}, isValidWaveTabMap);
const [activeContentTabRaw, setActiveContentTabRaw] =
useState(MyStreamWaveTab.CHAT);
const [availableTabs, setAvailableTabs] = useState([
MyStreamWaveTab.CHAT,
]);
- const lastWaveIdRef = useRef(null);
+ const currentWaveIdRef = useRef(null);
+ const activeContentTabRef = useRef(activeContentTabRaw);
+ const tabsByWaveIdRef = useRef>(tabsByWaveId);
+
+ useEffect(() => {
+ activeContentTabRef.current = activeContentTabRaw;
+ }, [activeContentTabRaw]);
+
+ useEffect(() => {
+ tabsByWaveIdRef.current = tabsByWaveId;
+ }, [tabsByWaveId]);
+
+ const setActiveTabInternal = useCallback((tab: MyStreamWaveTab) => {
+ setActiveContentTabRaw(tab);
+ activeContentTabRef.current = tab;
+ }, []);
// Function to determine which tabs are available based on wave state
// Now accepts a params object or null
@@ -58,12 +127,8 @@ export const ContentTabProvider: React.FC<{ children: ReactNode }> = ({
(params: WaveTabParams | null) => {
if (!params) {
setAvailableTabs([MyStreamWaveTab.CHAT]);
- lastWaveIdRef.current = null;
-
- // If current tab is not CHAT, switch to it
- if (activeContentTabRaw !== MyStreamWaveTab.CHAT) {
- setActiveContentTabRaw(MyStreamWaveTab.CHAT);
- }
+ currentWaveIdRef.current = null;
+ setActiveTabInternal(MyStreamWaveTab.CHAT);
return;
}
@@ -75,83 +140,32 @@ export const ContentTabProvider: React.FC<{ children: ReactNode }> = ({
hasFirstDecisionPassed,
} = params;
- // Chat-type waves only show chat tab
+ let tabs: MyStreamWaveTab[];
if (isChatWave) {
- setAvailableTabs([MyStreamWaveTab.CHAT]);
-
- // If current tab is not CHAT, switch to it
- if (activeContentTabRaw !== MyStreamWaveTab.CHAT) {
- setActiveContentTabRaw(MyStreamWaveTab.CHAT);
- }
- lastWaveIdRef.current = waveId ?? null;
- return;
- }
-
- // For Memes wave - don't set default tab, let it use standard behavior
- if (isMemesWave) {
- const getDefaultTab = (tabsToCheck: MyStreamWaveTab[]) =>
- tabsToCheck.includes(MyStreamWaveTab.LEADERBOARD)
- ? MyStreamWaveTab.LEADERBOARD
- : MyStreamWaveTab.CHAT;
- const tabs: MyStreamWaveTab[] = [];
- if (votingState !== WaveVotingState.ENDED) {
- tabs.push(MyStreamWaveTab.LEADERBOARD);
- }
- tabs.push(MyStreamWaveTab.CHAT);
- if (hasFirstDecisionPassed) {
- tabs.push(MyStreamWaveTab.WINNERS);
- }
- tabs.push(MyStreamWaveTab.MY_VOTES);
- tabs.push(MyStreamWaveTab.OUTCOME);
- tabs.push(MyStreamWaveTab.FAQ);
-
- setAvailableTabs(tabs);
-
- const isNewWave = !!waveId && waveId !== lastWaveIdRef.current;
-
- if (isNewWave || !tabs.includes(activeContentTabRaw)) {
- setActiveContentTabRaw(getDefaultTab(tabs));
- }
-
- lastWaveIdRef.current = waveId ?? null;
- return;
- }
-
- // Default tabs
- const tabs: MyStreamWaveTab[] = [MyStreamWaveTab.CHAT];
-
- // Add Leaderboard if voting hasn't ended
- if (votingState !== WaveVotingState.ENDED) {
- tabs.push(MyStreamWaveTab.LEADERBOARD);
- }
-
- // Add Winners if first decision has passed
- if (hasFirstDecisionPassed) {
- tabs.push(MyStreamWaveTab.WINNERS);
+ tabs = [MyStreamWaveTab.CHAT];
+ } else if (isMemesWave) {
+ tabs = buildMemesTabs(votingState, hasFirstDecisionPassed);
+ } else {
+ tabs = buildDefaultTabs(votingState, hasFirstDecisionPassed);
}
- // Always add Outcome
- tabs.push(MyStreamWaveTab.OUTCOME);
- tabs.push(MyStreamWaveTab.MY_VOTES);
-
- // FAQ tab is only available for Memes waves, which is handled in the isMemesWave block above
-
- // Update available tabs
setAvailableTabs(tabs);
+ currentWaveIdRef.current = waveId ?? null;
- // If current tab is no longer available, switch to a default available tab
- if (!tabs.includes(activeContentTabRaw)) {
- // Prefer to switch to LEADERBOARD if available, otherwise CHAT
- if (tabs.includes(MyStreamWaveTab.LEADERBOARD)) {
- setActiveContentTabRaw(MyStreamWaveTab.LEADERBOARD);
- } else {
- setActiveContentTabRaw(MyStreamWaveTab.CHAT);
- }
- }
+ const storedTab = waveId ? tabsByWaveIdRef.current[waveId] : undefined;
+ const defaultTab =
+ isMemesWave && tabs.includes(MyStreamWaveTab.LEADERBOARD)
+ ? MyStreamWaveTab.LEADERBOARD
+ : MyStreamWaveTab.CHAT;
- lastWaveIdRef.current = waveId ?? null;
+ const nextTab =
+ storedTab !== undefined && tabs.includes(storedTab)
+ ? storedTab
+ : defaultTab;
+
+ setActiveTabInternal(nextTab);
},
- [activeContentTabRaw]
+ [setActiveTabInternal]
);
// Wrapper for setActiveContentTab that validates the tab
@@ -159,13 +173,22 @@ export const ContentTabProvider: React.FC<{ children: ReactNode }> = ({
(tab: MyStreamWaveTab) => {
// Only set the tab if it's available
if (availableTabs.includes(tab)) {
- setActiveContentTabRaw(tab);
+ setActiveTabInternal(tab);
+ const waveId = currentWaveIdRef.current;
+ if (waveId) {
+ const nextMap = {
+ ...tabsByWaveIdRef.current,
+ [waveId]: tab,
+ };
+ tabsByWaveIdRef.current = nextMap;
+ setTabsByWaveId(nextMap);
+ }
} else {
// If tab is not available, default to CHAT
- setActiveContentTabRaw(MyStreamWaveTab.CHAT);
+ setActiveTabInternal(MyStreamWaveTab.CHAT);
}
},
- [availableTabs]
+ [availableTabs, setActiveTabInternal, setTabsByWaveId]
);
// Memoize the context value to prevent unnecessary re-renders
diff --git a/package-lock.json b/package-lock.json
index 38a6e2f0b0..1326887961 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -310,6 +310,7 @@
"node_modules/@babel/core": {
"version": "7.28.5",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -852,6 +853,7 @@
"node_modules/@capacitor/core": {
"version": "7.4.1",
"license": "MIT",
+ "peer": true,
"dependencies": {
"tslib": "^2.1.0"
}
@@ -919,6 +921,7 @@
"node_modules/@coinbase/wallet-sdk": {
"version": "4.3.6",
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"@noble/hashes": "1.4.0",
"clsx": "1.2.1",
@@ -1700,6 +1703,7 @@
"node_modules/@fortawesome/fontawesome-svg-core": {
"version": "6.7.2",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.7.2"
},
@@ -1741,6 +1745,7 @@
"node_modules/@gemini-wallet/core": {
"version": "0.3.2",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@metamask/rpc-errors": "7.0.2",
"eventemitter3": "5.0.1"
@@ -3436,7 +3441,6 @@
"node_modules/@jridgewell/source-map": {
"version": "0.3.11",
"license": "MIT",
- "peer": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
@@ -4081,6 +4085,7 @@
},
"node_modules/@metamask/sdk": {
"version": "0.33.1",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.26.0",
"@metamask/onboarding": "^1.0.1",
@@ -4138,6 +4143,7 @@
"node_modules/@metamask/sdk/node_modules/cross-fetch": {
"version": "4.1.0",
"license": "MIT",
+ "peer": true,
"dependencies": {
"node-fetch": "^2.7.0"
}
@@ -4285,6 +4291,7 @@
"node_modules/@nestjs/common": {
"version": "11.1.9",
"license": "MIT",
+ "peer": true,
"dependencies": {
"file-type": "21.1.0",
"iterare": "1.2.1",
@@ -4495,6 +4502,7 @@
"node_modules/@noble/ciphers": {
"version": "1.3.0",
"license": "MIT",
+ "peer": true,
"engines": {
"node": "^14.21.3 || >=16"
},
@@ -4643,6 +4651,7 @@
"node_modules/@opentelemetry/api": {
"version": "1.9.0",
"license": "Apache-2.0",
+ "peer": true,
"engines": {
"node": ">=8.0.0"
}
@@ -4660,6 +4669,7 @@
"node_modules/@opentelemetry/context-async-hooks": {
"version": "2.2.0",
"license": "Apache-2.0",
+ "peer": true,
"engines": {
"node": "^18.19.0 || >=20.6.0"
},
@@ -4670,6 +4680,7 @@
"node_modules/@opentelemetry/core": {
"version": "2.2.0",
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"@opentelemetry/semantic-conventions": "^1.29.0"
},
@@ -4683,6 +4694,7 @@
"node_modules/@opentelemetry/instrumentation": {
"version": "0.208.0",
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"@opentelemetry/api-logs": "0.208.0",
"import-in-the-middle": "^2.0.0",
@@ -5022,6 +5034,7 @@
"node_modules/@opentelemetry/resources": {
"version": "2.2.0",
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"@opentelemetry/core": "2.2.0",
"@opentelemetry/semantic-conventions": "^1.29.0"
@@ -5036,6 +5049,7 @@
"node_modules/@opentelemetry/sdk-trace-base": {
"version": "2.2.0",
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"@opentelemetry/core": "2.2.0",
"@opentelemetry/resources": "2.2.0",
@@ -5051,6 +5065,7 @@
"node_modules/@opentelemetry/semantic-conventions": {
"version": "1.38.0",
"license": "Apache-2.0",
+ "peer": true,
"engines": {
"node": ">=14"
}
@@ -5696,6 +5711,7 @@
"version": "1.57.0",
"devOptional": true,
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"playwright": "1.57.0"
},
@@ -5709,6 +5725,7 @@
"node_modules/@popperjs/core": {
"version": "2.11.8",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
@@ -7657,6 +7674,7 @@
"node_modules/@solana/kit": {
"version": "3.0.3",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@solana/accounts": "3.0.3",
"@solana/addresses": "3.0.3",
@@ -8187,6 +8205,7 @@
"node_modules/@tanstack/query-core": {
"version": "5.90.11",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
@@ -8195,6 +8214,7 @@
"node_modules/@tanstack/react-query": {
"version": "5.90.11",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@tanstack/query-core": "5.90.11"
},
@@ -8377,8 +8397,7 @@
"node_modules/@types/aria-query": {
"version": "5.0.4",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
@@ -8434,7 +8453,6 @@
"node_modules/@types/eslint": {
"version": "9.6.1",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/estree": "*",
"@types/json-schema": "*"
@@ -8443,7 +8461,6 @@
"node_modules/@types/eslint-scope": {
"version": "3.7.7",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/eslint": "*",
"@types/estree": "*"
@@ -8727,6 +8744,7 @@
"node_modules/@types/node": {
"version": "20.19.25",
"license": "MIT",
+ "peer": true,
"dependencies": {
"undici-types": "~6.21.0"
}
@@ -8771,6 +8789,7 @@
"node_modules/@types/react": {
"version": "19.2.3",
"license": "MIT",
+ "peer": true,
"dependencies": {
"csstype": "^3.0.2"
}
@@ -8778,6 +8797,7 @@
"node_modules/@types/react-dom": {
"version": "19.2.3",
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"@types/react": "^19.2.0"
}
@@ -8871,6 +8891,7 @@
"version": "8.48.0",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.48.0",
@@ -8907,6 +8928,7 @@
"version": "8.48.0",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.48.0",
"@typescript-eslint/types": "8.48.0",
@@ -9501,7 +9523,6 @@
"node_modules/@wagmi/core/node_modules/zustand": {
"version": "5.0.0",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12.20.0"
},
@@ -9583,6 +9604,7 @@
"node_modules/@walletconnect/ethereum-provider": {
"version": "2.21.1",
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"@reown/appkit": "1.7.8",
"@walletconnect/jsonrpc-http-connection": "1.0.8",
@@ -10546,6 +10568,7 @@
"node_modules/@walletconnect/ethereum-provider/node_modules/ws": {
"version": "8.18.0",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=10.0.0"
},
@@ -10972,7 +10995,6 @@
"node_modules/@webassemblyjs/ast": {
"version": "1.14.1",
"license": "MIT",
- "peer": true,
"dependencies": {
"@webassemblyjs/helper-numbers": "1.13.2",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2"
@@ -10980,23 +11002,19 @@
},
"node_modules/@webassemblyjs/floating-point-hex-parser": {
"version": "1.13.2",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@webassemblyjs/helper-api-error": {
"version": "1.13.2",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@webassemblyjs/helper-buffer": {
"version": "1.14.1",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@webassemblyjs/helper-numbers": {
"version": "1.13.2",
"license": "MIT",
- "peer": true,
"dependencies": {
"@webassemblyjs/floating-point-hex-parser": "1.13.2",
"@webassemblyjs/helper-api-error": "1.13.2",
@@ -11005,13 +11023,11 @@
},
"node_modules/@webassemblyjs/helper-wasm-bytecode": {
"version": "1.13.2",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@webassemblyjs/helper-wasm-section": {
"version": "1.14.1",
"license": "MIT",
- "peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
@@ -11022,7 +11038,6 @@
"node_modules/@webassemblyjs/ieee754": {
"version": "1.13.2",
"license": "MIT",
- "peer": true,
"dependencies": {
"@xtuc/ieee754": "^1.2.0"
}
@@ -11030,20 +11045,17 @@
"node_modules/@webassemblyjs/leb128": {
"version": "1.13.2",
"license": "Apache-2.0",
- "peer": true,
"dependencies": {
"@xtuc/long": "4.2.2"
}
},
"node_modules/@webassemblyjs/utf8": {
"version": "1.13.2",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@webassemblyjs/wasm-edit": {
"version": "1.14.1",
"license": "MIT",
- "peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
@@ -11058,7 +11070,6 @@
"node_modules/@webassemblyjs/wasm-gen": {
"version": "1.14.1",
"license": "MIT",
- "peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
@@ -11070,7 +11081,6 @@
"node_modules/@webassemblyjs/wasm-opt": {
"version": "1.14.1",
"license": "MIT",
- "peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
@@ -11081,7 +11091,6 @@
"node_modules/@webassemblyjs/wasm-parser": {
"version": "1.14.1",
"license": "MIT",
- "peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-api-error": "1.13.2",
@@ -11094,7 +11103,6 @@
"node_modules/@webassemblyjs/wast-printer": {
"version": "1.14.1",
"license": "MIT",
- "peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@xtuc/long": "4.2.2"
@@ -11106,13 +11114,11 @@
},
"node_modules/@xtuc/ieee754": {
"version": "1.2.0",
- "license": "BSD-3-Clause",
- "peer": true
+ "license": "BSD-3-Clause"
},
"node_modules/@xtuc/long": {
"version": "4.2.2",
- "license": "Apache-2.0",
- "peer": true
+ "license": "Apache-2.0"
},
"node_modules/abab": {
"version": "2.0.6",
@@ -11141,6 +11147,7 @@
"node_modules/acorn": {
"version": "8.15.0",
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -11167,7 +11174,6 @@
"node_modules/acorn-import-phases": {
"version": "1.0.4",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=10.13.0"
},
@@ -11236,7 +11242,6 @@
"node_modules/ajv-formats": {
"version": "2.1.1",
"license": "MIT",
- "peer": true,
"dependencies": {
"ajv": "^8.0.0"
},
@@ -11252,7 +11257,6 @@
"node_modules/ajv-formats/node_modules/ajv": {
"version": "8.17.1",
"license": "MIT",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -11266,8 +11270,7 @@
},
"node_modules/ajv-formats/node_modules/json-schema-traverse": {
"version": "1.0.0",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/ansi-escapes": {
"version": "4.3.2",
@@ -11640,6 +11643,7 @@
"node_modules/axios": {
"version": "1.13.2",
"license": "MIT",
+ "peer": true,
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
@@ -11717,6 +11721,7 @@
"version": "1.0.0",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/types": "^7.26.0"
}
@@ -11953,6 +11958,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.8.25",
"caniuse-lite": "^1.0.30001754",
@@ -12023,6 +12029,7 @@
"version": "4.0.9",
"hasInstallScript": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"node-gyp-build": "^4.3.0"
},
@@ -12256,6 +12263,7 @@
"node_modules/chart.js": {
"version": "4.5.1",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@kurkle/color": "^0.3.0"
},
@@ -12336,7 +12344,6 @@
"node_modules/chrome-trace-event": {
"version": "1.0.4",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=6.0"
}
@@ -13365,8 +13372,7 @@
"node_modules/dom-accessibility-api": {
"version": "0.5.16",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/dom-helpers": {
"version": "5.2.1",
@@ -13480,6 +13486,7 @@
"node_modules/eciesjs": {
"version": "0.4.16",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@ecies/ciphers": "^0.2.4",
"@noble/ciphers": "^1.3.0",
@@ -13519,7 +13526,8 @@
},
"node_modules/emoji-mart": {
"version": "5.6.0",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/emoji-regex": {
"version": "10.6.0",
@@ -13602,7 +13610,6 @@
"node_modules/enhanced-resolve": {
"version": "5.18.3",
"license": "MIT",
- "peer": true,
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
@@ -13745,8 +13752,7 @@
},
"node_modules/es-module-lexer": {
"version": "1.7.0",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
@@ -13898,6 +13904,7 @@
"version": "9.39.1",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -14092,6 +14099,7 @@
"version": "2.32.0",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
@@ -14754,7 +14762,8 @@
},
"node_modules/eventemitter2": {
"version": "6.4.9",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/eventemitter3": {
"version": "5.0.1",
@@ -14917,8 +14926,7 @@
"url": "https://opencollective.com/fastify"
}
],
- "license": "BSD-3-Clause",
- "peer": true
+ "license": "BSD-3-Clause"
},
"node_modules/fastest-stable-stringify": {
"version": "2.0.2",
@@ -15439,8 +15447,7 @@
},
"node_modules/glob-to-regexp": {
"version": "0.4.1",
- "license": "BSD-2-Clause",
- "peer": true
+ "license": "BSD-2-Clause"
},
"node_modules/glob/node_modules/minimatch": {
"version": "10.1.1",
@@ -16697,7 +16704,6 @@
"node_modules/isomorphic.js": {
"version": "0.2.5",
"license": "MIT",
- "peer": true,
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
@@ -20078,7 +20084,6 @@
"node_modules/lib0": {
"version": "0.2.114",
"license": "MIT",
- "peer": true,
"dependencies": {
"isomorphic.js": "^0.2.4"
},
@@ -20161,7 +20166,6 @@
"node_modules/loader-runner": {
"version": "4.3.1",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=6.11.5"
},
@@ -20246,7 +20250,6 @@
"version": "1.5.0",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"lz-string": "bin/bin.js"
}
@@ -21348,6 +21351,7 @@
"resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz",
"integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@next/env": "16.1.6",
"@swc/helpers": "0.5.15",
@@ -22522,6 +22526,7 @@
"node_modules/porto": {
"version": "0.2.35",
"license": "MIT",
+ "peer": true,
"dependencies": {
"hono": "^4.10.3",
"idb-keyval": "^6.2.1",
@@ -22668,6 +22673,7 @@
"node_modules/porto/node_modules/zod": {
"version": "4.1.13",
"license": "MIT",
+ "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
@@ -22696,6 +22702,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -22832,6 +22839,7 @@
"version": "3.7.4",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -22923,7 +22931,6 @@
"version": "27.5.1",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
@@ -22937,7 +22944,6 @@
"version": "5.2.0",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=10"
},
@@ -22948,8 +22954,7 @@
"node_modules/pretty-format/node_modules/react-is": {
"version": "17.0.2",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/prismjs": {
"version": "1.30.0",
@@ -23006,6 +23011,7 @@
"node_modules/prop-types": {
"version": "15.8.1",
"license": "MIT",
+ "peer": true,
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@@ -23292,7 +23298,6 @@
"node_modules/randombytes": {
"version": "2.1.0",
"license": "MIT",
- "peer": true,
"dependencies": {
"safe-buffer": "^5.1.0"
}
@@ -23300,6 +23305,7 @@
"node_modules/react": {
"version": "19.2.3",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -23344,6 +23350,7 @@
"node_modules/react-dom": {
"version": "19.2.3",
"license": "MIT",
+ "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -23397,6 +23404,7 @@
"node_modules/react-redux": {
"version": "9.2.0",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/use-sync-external-store": "^0.0.6",
"use-sync-external-store": "^1.4.0"
@@ -23561,6 +23569,7 @@
"node_modules/readable-stream": {
"version": "3.6.2",
"license": "MIT",
+ "peer": true,
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -23611,7 +23620,8 @@
},
"node_modules/redux": {
"version": "5.0.1",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/redux-thunk": {
"version": "3.1.0",
@@ -23633,7 +23643,8 @@
},
"node_modules/reflect-metadata": {
"version": "0.2.2",
- "license": "Apache-2.0"
+ "license": "Apache-2.0",
+ "peer": true
},
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
@@ -23791,7 +23802,6 @@
"node_modules/require-from-string": {
"version": "2.0.2",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -23920,6 +23930,7 @@
"node_modules/rollup": {
"version": "4.53.3",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/estree": "1.0.8"
},
@@ -24043,6 +24054,7 @@
"node_modules/rxjs": {
"version": "7.8.2",
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"tslib": "^2.1.0"
}
@@ -24135,6 +24147,7 @@
"node_modules/sass": {
"version": "1.94.2",
"license": "MIT",
+ "peer": true,
"dependencies": {
"chokidar": "^4.0.0",
"immutable": "^5.0.2",
@@ -24192,7 +24205,6 @@
"node_modules/schema-utils": {
"version": "4.3.3",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/json-schema": "^7.0.9",
"ajv": "^8.9.0",
@@ -24225,7 +24237,6 @@
"node_modules/schema-utils/node_modules/ajv-keywords": {
"version": "5.1.0",
"license": "MIT",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3"
},
@@ -24235,8 +24246,7 @@
},
"node_modules/schema-utils/node_modules/json-schema-traverse": {
"version": "1.0.0",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/screenfull": {
"version": "5.2.0",
@@ -24291,7 +24301,6 @@
"node_modules/serialize-javascript": {
"version": "6.0.2",
"license": "BSD-3-Clause",
- "peer": true,
"dependencies": {
"randombytes": "^2.1.0"
}
@@ -24593,6 +24602,7 @@
"node_modules/socket.io-client": {
"version": "4.8.1",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
@@ -25238,6 +25248,7 @@
"node_modules/tailwindcss": {
"version": "3.4.18",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
@@ -25297,6 +25308,7 @@
"node_modules/tailwindcss/node_modules/jiti": {
"version": "1.21.7",
"license": "MIT",
+ "peer": true,
"bin": {
"jiti": "bin/jiti.js"
}
@@ -25344,7 +25356,6 @@
"node_modules/tapable": {
"version": "2.3.0",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=6"
},
@@ -25356,7 +25367,6 @@
"node_modules/terser": {
"version": "5.44.1",
"license": "BSD-2-Clause",
- "peer": true,
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.15.0",
@@ -25373,7 +25383,6 @@
"node_modules/terser-webpack-plugin": {
"version": "5.3.14",
"license": "MIT",
- "peer": true,
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.25",
"jest-worker": "^27.4.5",
@@ -25406,7 +25415,6 @@
"node_modules/terser-webpack-plugin/node_modules/jest-worker": {
"version": "27.5.1",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/node": "*",
"merge-stream": "^2.0.0",
@@ -25419,7 +25427,6 @@
"node_modules/terser-webpack-plugin/node_modules/supports-color": {
"version": "8.1.1",
"license": "MIT",
- "peer": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -25432,13 +25439,11 @@
},
"node_modules/terser/node_modules/commander": {
"version": "2.20.3",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/terser/node_modules/source-map-support": {
"version": "0.5.21",
"license": "MIT",
- "peer": true,
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
@@ -25525,7 +25530,8 @@
},
"node_modules/three": {
"version": "0.163.0",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/throttle-debounce": {
"version": "3.0.1",
@@ -25796,12 +25802,14 @@
},
"node_modules/tslib": {
"version": "2.8.1",
- "license": "0BSD"
+ "license": "0BSD",
+ "peer": true
},
"node_modules/tsx": {
"version": "4.21.0",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "~0.27.0",
"get-tsconfig": "^4.7.5"
@@ -26397,6 +26405,7 @@
"node_modules/typescript": {
"version": "5.9.3",
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -26861,6 +26870,7 @@
"version": "5.0.10",
"hasInstallScript": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"node-gyp-build": "^4.3.0"
},
@@ -26910,6 +26920,7 @@
"node_modules/valtio": {
"version": "2.1.7",
"license": "MIT",
+ "peer": true,
"dependencies": {
"proxy-compare": "^3.0.1"
},
@@ -26962,6 +26973,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"@noble/curves": "1.9.1",
"@noble/hashes": "1.8.0",
@@ -27088,6 +27100,7 @@
"node_modules/wagmi": {
"version": "2.19.5",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@wagmi/connectors": "6.2.0",
"@wagmi/core": "2.22.1",
@@ -27139,6 +27152,7 @@
"node_modules/wagmi/node_modules/@wagmi/core": {
"version": "2.22.1",
"license": "MIT",
+ "peer": true,
"dependencies": {
"eventemitter3": "5.0.1",
"mipd": "0.0.7",
@@ -27164,6 +27178,7 @@
"node_modules/wagmi/node_modules/use-sync-external-store": {
"version": "1.4.0",
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
@@ -27221,7 +27236,6 @@
"node_modules/watchpack": {
"version": "2.4.4",
"license": "MIT",
- "peer": true,
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
@@ -27256,7 +27270,6 @@
"node_modules/webpack": {
"version": "5.103.0",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.8",
@@ -27314,7 +27327,6 @@
"node_modules/webpack/node_modules/eslint-scope": {
"version": "5.1.1",
"license": "BSD-2-Clause",
- "peer": true,
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
@@ -27326,7 +27338,6 @@
"node_modules/webpack/node_modules/estraverse": {
"version": "4.3.0",
"license": "BSD-2-Clause",
- "peer": true,
"engines": {
"node": ">=4.0"
}
@@ -27517,6 +27528,7 @@
"node_modules/ws": {
"version": "8.18.3",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=10.0.0"
},
@@ -27589,6 +27601,7 @@
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
"devOptional": true,
"license": "ISC",
+ "peer": true,
"bin": {
"yaml": "bin.mjs"
},
@@ -27651,6 +27664,7 @@
"node_modules/zod": {
"version": "3.25.76",
"license": "MIT",
+ "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}