Documentation Index
Fetch the complete documentation index at: https://docs.privacyboost.io/llms.txt
Use this file to discover all available pages before exploring further.
Error Handling & Performance
This guide covers TypeScript-specific error handling patterns and performance optimization. For the cross-platform error code reference, see Error Handling.
PrivacyBoostError
All SDK errors extend PrivacyBoostError:
import { PrivacyBoostError } from '@sunnyside-io/privacy-boost';
class PrivacyBoostError extends Error {
code: string; // Error code for programmatic handling
message: string; // Human-readable message
retryable: boolean; // Whether the operation can be retried
cause?: Error; // Original error if wrapped
isAuthError(): boolean; // Is this an auth/session error?
isWalletError(): boolean; // Is this a wallet-related error?
}
Type-Safe Error Handling
import { PrivacyBoostError, ErrorCodes } from '@sunnyside-io/privacy-boost';
try {
await sdk.vault.shield({ tokenAddress, amount });
} catch (error) {
if (error instanceof PrivacyBoostError) {
switch (error.code) {
case ErrorCodes.TRANSACTION_REJECTED:
return; // User cancelled — do nothing
case ErrorCodes.INSUFFICIENT_BALANCE:
showToast('Not enough balance');
return;
default:
if (error.retryable) {
await retryLater();
} else {
showError(error.message);
}
}
}
// Non-SDK errors
throw error;
}
Retry with Exponential Backoff
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (!(error instanceof PrivacyBoostError) || !error.retryable || attempt === maxRetries) {
throw error;
}
await new Promise(r => setTimeout(r, 1000 * attempt));
}
}
throw new Error('Unreachable');
}
const balance = await withRetry(() => sdk.vault.getBalance(token));
Auto Re-Authentication
async function withAuth<T>(fn: () => Promise<T>): Promise<T> {
try {
return await fn();
} catch (error) {
if (error instanceof PrivacyBoostError && error.code === 'SESSION_EXPIRED') {
await sdk.auth.authenticate(adapter);
return await fn();
}
throw error;
}
}
User-Friendly Error Messages
function userMessage(error: PrivacyBoostError): string {
const messages: Record<string, string> = {
WALLET_NOT_CONNECTED: 'Please connect your wallet',
TRANSACTION_REJECTED: 'Request cancelled',
WRONG_NETWORK: 'Please switch to the correct network',
SESSION_EXPIRED: 'Session expired, please log in again',
INSUFFICIENT_BALANCE: 'Not enough balance',
NETWORK_ERROR: 'Connection failed, please try again',
RATE_LIMITED: 'Too many requests, please wait',
};
return messages[error.code] || error.message;
}
WASM Loading
The SDK includes a WebAssembly module for ZK proof generation. Managing how and when it loads affects initial page load time.
Lazy Loading
Don’t import the SDK at the top level in routes that don’t need it:
async function initPrivacy() {
const { PrivacyBoost } = await import('@sunnyside-io/privacy-boost');
return await PrivacyBoost.create(config);
}
Preloading
For routes that will need the SDK, preload in the background:
function preloadSDK() {
import('@sunnyside-io/privacy-boost').then(({ loadWasm }) => {
loadWasm().catch(() => {
// Ignore preload errors
});
});
}
// Call early in your app
useEffect(() => {
preloadSDK();
}, []);
Code Splitting
// React Router example
const PrivacyWallet = React.lazy(() => import('./PrivacyWallet'));
function App() {
return (
<Routes>
<Route path="/wallet" element={
<Suspense fallback={<Loading />}>
<PrivacyWallet />
</Suspense>
} />
</Routes>
);
}
Tree Shaking
Import only what you need:
// Imports entire package
import * as SDK from '@sunnyside-io/privacy-boost';
// Tree-shakeable imports
import { PrivacyBoost, PrivacyBoostError } from '@sunnyside-io/privacy-boost';
Caching & Network
Balance Caching
The SDK caches balances locally. Control refresh behavior:
// Get cached balance (fast, no network call)
const cached = await sdk.vault.getBalance(tokenAddress);
// Force refresh from server
await sdk.vault.refreshBalance(tokenAddress);
const fresh = await sdk.vault.getBalance(tokenAddress);
// Refresh all tracked balances at once (more efficient than individual refreshes)
await sdk.vault.refreshBalances();
Request Deduplication
Avoid redundant concurrent requests:
const pendingRequests = new Map<string, Promise<unknown>>();
async function deduplicated<T>(key: string, request: () => Promise<T>): Promise<T> {
if (pendingRequests.has(key)) {
return pendingRequests.get(key) as Promise<T>;
}
const promise = request().finally(() => pendingRequests.delete(key));
pendingRequests.set(key, promise);
return promise;
}
const balance = await deduplicated(
`balance:${tokenAddress}`,
() => sdk.vault.getBalance(tokenAddress)
);
Parallel Requests
// Sequential — slow
const b1 = await sdk.vault.getBalance(token1);
const b2 = await sdk.vault.getBalance(token2);
// Parallel — fast
const [b1, b2] = await Promise.all([
sdk.vault.getBalance(token1),
sdk.vault.getBalance(token2),
]);
Next Steps