Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 26 additions & 10 deletions src/components/providers/WalletProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
useRef,
} from "react";
import { Keypair } from "@stellar/stellar-sdk";
import { abortAllRequests } from "@/services/api";
import { cacheClearByPrefix } from "@/services/cache";

export interface WalletAccount {
address: string;
Expand All @@ -21,21 +23,23 @@ interface WalletContextValue {
isConnected: boolean;
isConnecting: boolean;
accounts: WalletAccount[];
cacheVersion: number;
connect: () => Promise<void>;
disconnect: () => Promise<void>;
switchAccount: (address: string) => Promise<void>;
purgeCache: () => void;
purgeCache: (oldAddress?: string) => Promise<void>;
}

const WalletContext = createContext<WalletContextValue>({
account: null,
isConnected: false,
isConnecting: false,
accounts: [],
cacheVersion: 0,
connect: async () => {},
disconnect: async () => {},
switchAccount: async () => {},
purgeCache: () => {},
purgeCache: async () => {},
});

let switchGuard = Promise.resolve();
Expand All @@ -46,10 +50,21 @@ export function WalletProvider({ children }: { children: React.ReactNode }) {
const [isConnecting, setIsConnecting] = useState(false);
const cacheVersion = useRef(0);

const purgeCache = useCallback(() => {
const purgeCache = useCallback(async (oldAddress?: string) => {
cacheVersion.current += 1;

setAccount(null);
setAccounts([]);

localStorage.removeItem("utility-wallet-session");
localStorage.removeItem("utility-wallet-accounts");
localStorage.removeItem("utility-auth-session");

abortAllRequests();

if (oldAddress) {
await cacheClearByPrefix(`utility:${oldAddress}`);
}
}, []);

const connect = useCallback(async () => {
Expand All @@ -76,18 +91,18 @@ export function WalletProvider({ children }: { children: React.ReactNode }) {
}, [isConnecting]);

const disconnect = useCallback(async () => {
purgeCache();
setAccount(null);
setAccounts([]);
}, [purgeCache]);
await purgeCache(account?.address);
}, [purgeCache, account]);

const switchAccount = useCallback(
async (address: string) => {
switchGuard = switchGuard.then(async () => {
const target = accounts.find((a) => a.address === address);
if (!target) return;
setAccount(null);
await new Promise((r) => setTimeout(r, 0));

const oldAddress = account?.address;
await purgeCache(oldAddress);

setAccount(target);
localStorage.setItem(
"utility-wallet-session",
Expand All @@ -96,7 +111,7 @@ export function WalletProvider({ children }: { children: React.ReactNode }) {
});
await switchGuard;
},
[accounts]
[accounts, account, purgeCache]
);

useEffect(() => {
Expand All @@ -123,6 +138,7 @@ export function WalletProvider({ children }: { children: React.ReactNode }) {
isConnected: !!account,
isConnecting,
accounts,
cacheVersion: cacheVersion.current,
connect,
disconnect,
switchAccount,
Expand Down
11 changes: 11 additions & 0 deletions src/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const defaultConfig: ApiConfig = {
};

let sessionToken: string | null = null;
const activeControllers = new Set<AbortController>();

export function setSessionToken(token: string | null) {
sessionToken = token;
Expand All @@ -32,6 +33,13 @@ export function getSessionToken(): string | null {
return sessionToken;
}

export function abortAllRequests(): void {
for (const ctrl of activeControllers) {
ctrl.abort();
}
activeControllers.clear();
}

async function request<T>(
method: HttpMethod,
path: string,
Expand All @@ -41,6 +49,7 @@ async function request<T>(
const cfg = { ...defaultConfig, ...config };
const url = `${cfg.baseUrl}${path}`;
const controller = new AbortController();
activeControllers.add(controller);
const timeoutId = setTimeout(() => controller.abort(), cfg.timeout);

try {
Expand Down Expand Up @@ -83,6 +92,8 @@ async function request<T>(
error: (err as Error).message || "Network error",
status: 0,
};
} finally {
activeControllers.delete(controller);
}
}

Expand Down
16 changes: 16 additions & 0 deletions src/services/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,22 @@ export async function cacheClear(): Promise<void> {
}
}

export async function cacheClearByPrefix(prefix: string): Promise<void> {
try {
const db = await getDb();
const keys = await db.getAllKeys("kv");
const tx = db.transaction("kv", "readwrite");
for (const key of keys) {
if (String(key).startsWith(prefix)) {
tx.store.delete(key);
}
}
await tx.done;
} catch {
// silently fail
}
}

export async function cacheKeys(prefix?: string): Promise<string[]> {
try {
const db = await getDb();
Expand Down
Loading