UNPKG

sui-svelte-wallet-kit

Version:

Svelte 5 wallet kit for Sui: connect wallets, manage accounts, SuiNS, balance, sign transactions/messages

168 lines (167 loc) 5.94 kB
import { SuiClient, getFullnodeUrl } from '@mysten/sui/client'; // Environment guards export const isBrowser = typeof window !== 'undefined'; export const hasLocalStorage = () => isBrowser && !!window.localStorage; const STORAGE_KEY = 'sui-module-connection'; // Storage helpers export const getConnectionData = () => { if (!hasLocalStorage()) return null; const data = window.localStorage.getItem(STORAGE_KEY); return data ? JSON.parse(data) : null; }; export const updateConnectionData = (partial) => { if (!hasLocalStorage()) return; const current = getConnectionData() || {}; window.localStorage.setItem(STORAGE_KEY, JSON.stringify({ ...current, ...partial })); }; export const saveConnectionData = (walletName, autoConnect) => { if (!autoConnect || !hasLocalStorage()) return; const current = getConnectionData() || {}; window.localStorage.setItem(STORAGE_KEY, JSON.stringify({ ...current, walletName, autoConnect: true })); }; export const clearConnectionData = () => { if (!hasLocalStorage()) return; window.localStorage.removeItem(STORAGE_KEY); }; // OAuth redirect URL utilities export const getSafeRedirectUrlForOAuth = () => { if (!isBrowser) return undefined; try { const url = new URL(window.location.href); url.hash = ''; url.search = ''; url.pathname = '/'; return url.toString(); } catch { return undefined; } }; export const normalizeAbsoluteUrl = (value) => { try { if (typeof value !== 'string' || value.trim().length === 0) return undefined; const url = new URL(value); if (url.protocol === 'http:' || url.protocol === 'https:') return url.toString(); return undefined; } catch { return undefined; } }; export const pickRedirectFromList = (list) => { if (!isBrowser) return undefined; try { const values = Array.isArray(list) ? list : []; const valid = values.map((v) => normalizeAbsoluteUrl(v)).filter((v) => typeof v === 'string'); if (valid.length === 0) return undefined; const current = new URL(window.location.href); const sameOrigin = valid.filter((u) => { try { return new URL(u).origin === current.origin; } catch { return false; } }); if (sameOrigin.length > 0) { const root = sameOrigin.find((u) => { try { return new URL(u).pathname === '/'; } catch { return false; } }); return root || sameOrigin[0]; } return valid[0]; } catch { return undefined; } }; export const getPreferredRedirectUrlForOAuth = (zkLoginGoogle) => { try { const fromSingle = normalizeAbsoluteUrl(zkLoginGoogle?.redirectUrl); if (fromSingle) return fromSingle; const fromList = pickRedirectFromList(zkLoginGoogle?.redirectUrls); if (fromList) return fromList; return getSafeRedirectUrlForOAuth(); } catch { return getSafeRedirectUrlForOAuth(); } }; // Network selection + client cache export const getConfiguredNetwork = (zkLoginGoogle) => { try { const net = zkLoginGoogle?.network; if (net === 'mainnet' || net === 'testnet' || net === 'devnet') return net; } catch { } return undefined; }; export const getDefaultChain = (zkLoginGoogle) => { const cfg = getConfiguredNetwork(zkLoginGoogle); if (cfg) return `sui:${cfg}`; try { const selected = getConnectionData()?.selectedChain; if (typeof selected === 'string' && selected.startsWith('sui:')) return selected; } catch { } return 'sui:mainnet'; }; // SuiClient cache with Enoki registration callback const _clientCache = {}; export const getSuiClient = (chainIdLike, options = {}) => { const network = chainIdLike?.split?.(':')?.[1] || 'mainnet'; if (!_clientCache[network]) { _clientCache[network] = new SuiClient({ url: getFullnodeUrl(network), network }); // Register Enoki wallets only when zkLoginGoogle is enabled and in browser environment if (options.zkLoginGoogle && isBrowser) { const apiKey = options.zkLoginGoogle?.apiKey; const googleId = options.zkLoginGoogle?.googleClientId; if (!apiKey || !googleId) { try { const missing = [!apiKey ? 'apiKey' : null, !googleId ? 'googleClientId' : null] .filter(Boolean) .join(', '); console.error(`[SuiModule] Enoki zkLogin is enabled but missing: ${missing}. Provide zkLoginGoogle={ apiKey, googleClientId }. See docs: https://docs.enoki.mystenlabs.com/ts-sdk/sign-in`); } catch { } } else { const isSuspicious = options.isSuspiciousEnokiConfig?.(apiKey, googleId) ?? false; if (isSuspicious) { try { console.error(`[SuiModule] Enoki config looks unusual: ${typeof apiKey === 'string' && apiKey.length < 16 ? 'apiKey too short; ' : ''}${typeof googleId === 'string' && !googleId.endsWith('.apps.googleusercontent.com') ? 'googleClientId should typically end with .apps.googleusercontent.com; ' : ''}please verify`); } catch { } } else { options.onEnokiRegister?.(_clientCache[network], network); } } } } return _clientCache[network]; };