import { AuthProvider } from '../types'; export interface ClientConfig { name: string; logoUrl: string; /** Auth method. Configure exactly one method at init time. * Bounded Auth is the default restore/logout surface; start email, social, * and optional text login with loginWithRedirect/loginWithPopup. * Default email/social auth includes a Turnkey Solana wallet. 'phantom' * connects an existing Solana wallet instead. Guests use signInAnonymously(), not * authMethod. */ authMethod: 'none' | 'email' | 'guest' | 'wallet' | 'evm-wallet' | 'rainbowkit' | 'coinbase-smart-wallet' | 'onboard' | 'phantom' | 'mobile-wallet-adapter' | 'privy' | 'privy-expo'; wsApiUrl: string; apiUrl: string; /** * Base URL of the Bounded Functions dispatcher (the imperative escape hatch). * Optional and ADDITIVE — when unset, bounded.functions.invoke() throws a * clear "functions not configured" error. Defaults to the staging dispatcher. */ functionsUrl?: string; appId: string; /** Wallet/SIWS issuer (wallet + guest providers sign challenges against this). */ authApiUrl: string; /** Human-login issuer for hosted Bounded Auth: email OTP, OAuth/social, and * optional text OTP. App-origin OTP helpers are retired; use hosted * loginWithRedirect/loginWithPopup against this issuer. Defaults per network. */ humanAuthApiUrl?: string; /** * Base URL of the Bounded developer API used by first-party platform * surfaces for app provisioning and build control. Defaults per network. */ devApiUrl?: string; /** * Selects a Bounded backend preset. When set, the endpoint defaults * (apiUrl/wsApiUrl/authApiUrl/humanAuthApiUrl/functionsUrl/devApiUrl) resolve * to that network's Bounded services instead of the legacy defaults — so a * Bounded app needs only `{ appId, network }`. Anything you pass explicitly * still wins. Unset = legacy behavior (unchanged for existing apps). */ network?: 'bounded' | 'bounded-staging' | 'bounded-production'; chain: string; rpcUrl: string; skipBackendInit: boolean; authProvider: AuthProvider | null; isServer: boolean; phantomConfig?: { appId?: string; providers?: Array<'injected' | 'google' | 'apple' | 'phantom' | 'deeplink'>; redirectUrl?: string; autoConnect?: boolean; /** Theme for the login modal: 'light' or 'dark'. Defaults to 'dark'. */ theme?: 'light' | 'dark'; appName?: string; appIcon?: string; /** Custom title shown at the top of the login modal. */ modalTitle?: string; /** Custom subtitle shown below the title in the login modal. */ modalSubtitle?: string; }; /** Privy (web) configuration — the @privy-io/react-auth app id + its config * object. Used when authMethod is 'privy' (a co-equal login route alongside * email/phantom/guest). The Privy embedded/external Solana wallet signs the * standard SIWS challenge, so the session is minted via the same wallet path * as Phantom — no Privy-specific backend verification required. */ privyConfig?: { appId: string; config: any; }; /** React Native (Expo) Privy provider instance, bridged from the host app's * tree via setPrivyMethods(). Required when authMethod is * 'privy-expo' because @privy-io/expo is hook-based and must be rendered by * the RN component tree (see PrivyExpoProvider). */ privyExpoProvider?: AuthProvider; /** Solana Mobile Wallet Adapter (Saga/Seeker) registration tuning. Wallet * login already surfaces the device wallet automatically on capable Android * browsers (the SDK registers MWA as a Wallet-Standard wallet whenever the * wallet lane is active), so this is OPTIONAL and only overrides defaults: * appIdentity (defaults to config.name/logoUrl + the page origin; per the * MWA spec `icon` is a path RELATIVE to `uri`), cluster ('mainnet-beta' | * 'devnet' - the mobile wallet authorizes per cluster and signs on the app's * chain, so this may NAME the chain a chainless app authorizes on but may * never contradict `chain`; a contradiction throws), and remoteHostAuthority * (a reflector websocket authority that additionally enables the desktop * QR-code "connect your phone" lane). */ mobileWalletConfig?: { appIdentity?: { name?: string; uri?: string; icon?: string; }; cluster?: string; remoteHostAuthority?: string; }; /** OPT-IN gate for Solana WALLET LOGIN (authMethod:'phantom' / 'wallet'). * OFF BY DEFAULT — the vast majority of apps never support wallets, so the * "connect wallet" choice is only usable when the developer explicitly turns * it on here. Set `walletLogin: true` to enable it with default provider * discovery (Phantom-first, then any Wallet-Standard window.solana), or pass * an object to also set getProvider / network / rpcUrl. Without this (or an * injectedWalletConfig object), attempting wallet login throws a clear error * and existing apps see ZERO behavior change. */ walletLogin?: boolean | { getProvider?: () => any; network?: string | null; rpcUrl?: string | null; /** Awaited immediately before every wallet operation, after all async * preparation, so the app can collect a fresh user gesture. Required for * Solana Mobile (Saga/Seeker): each operation dispatches an Android intent * through window.location.assign, which Chrome blocks without transient * activation. Reject to abort the operation. Leave unset for injected * wallets, which sign in-page. */ confirmWalletAction?: (action: 'connect' | 'login' | 'signMessage' | 'signTransaction' | 'signAndSubmitTransaction') => Promise; }; /** LOGIN MODE for the unified login widget (default 'turnkey'). 'turnkey' runs * Turnkey-native email OTP INLINE in the widget (no second Bounded OTP). * 'bounded' explicitly selects the legacy Better Auth email flow; social and * external-wallet lanes are unchanged. A per-call openBoundedWidget({ authMode }) * can override this. */ authMode?: 'bounded' | 'turnkey'; /** TEXT for the unified login widget. `title` replaces the default "Sign in" * heading; `subtitle` replaces the default subline - pass "" to render no * subline at all. A per-call openBoundedWidget({ title, subtitle }) overrides * these. */ loginWidget?: { title?: string; subtitle?: string; }; /** SITE POLICY: require an email on file for every user (default false). Native * wallet login carries no email, so when true the unified widget suppresses the * "Continue with wallet" lane (email/social remain). Overrides walletLogin and * any per-call `wallet: true`. Set `walletLogin: false` to hide the wallet lane * without requiring email. */ requireEmail?: boolean; /** Solana WALLET LOGIN provider configuration (advanced). Passing this object * ALSO opts the app into wallet login (equivalent to walletLogin). The slim, * dependency-free "connect wallet" path rides the injected Solana provider a * browser wallet exposes (Phantom's window.phantom.solana, or any * Wallet-Standard window.solana). The user's REAL wallet becomes * @user.address; login = SIWS; the full signing surface (signMessage / * signTransaction / signAndSubmitTransaction) is the wallet's own keypair. * Pass getProvider to point at a specific wallet or bridge a custom provider. */ injectedWalletConfig?: { getProvider?: () => any; network?: string | null; rpcUrl?: string | null; /** See walletLogin.confirmWalletAction - the fresh-gesture hook Solana * Mobile needs before each wallet operation. */ confirmWalletAction?: (action: 'connect' | 'login' | 'signMessage' | 'signTransaction' | 'signAndSubmitTransaction') => Promise; }; /** EVM WALLET LOGIN provider configuration (authMethod:'evm-wallet'). The EVM * twin of injectedWalletConfig: a slim, dependency-free "connect an Ethereum * wallet" path that rides the EIP-1193 injected provider a browser wallet * exposes (MetaMask / Rabby / Coinbase Wallet / any window.ethereum), discovered * via EIP-6963. The user's REAL EVM wallet becomes @user.evmAddress; login = * SIWE (EIP-4361). LOGIN-ONLY: EVM onchain apps were removed, so this * configures no write surface. Selecting authMethod:'evm-wallet' enables it; * pass getProvider to point at a specific wallet, chainId for the SIWE prompt, * or domain/uri as same-origin assertions for the SIWE authority. */ evmWalletConfig?: { getProvider?: () => any; chainId?: number; domain?: string; uri?: string; }; } export declare const DEFAULT_CLIENT_CONFIG: ClientConfig; export declare let clientConfig: ClientConfig; type BoundedEndpoints = Pick; export declare const BOUNDED_NETWORKS: Record; /** * The hosted `/.well-known/bounded-webhook-keys.json` URL for the configured * Bounded network, or `undefined` when no Bounded network is set. Used by * `verifyWebhook` so a staging receiver that did `init({ network: * 'bounded-staging' })` verifies against the STAGING signing keys instead of * the production default. Synchronous and non-blocking on purpose: a pure * webhook receiver may never call `init()`, so we read the already-applied * config rather than awaiting `getConfig()` (which blocks on initialization). * Returns `undefined` when the network is unknown so the caller keeps its * fail-closed production default (audit SDK LOW-7). */ export declare function getWebhookKeysUrl(): string | undefined; /** * The app id configured via `init({ appId })`, or `undefined` when none has been set. * Synchronous + non-blocking on purpose (mirrors {@link getWebhookKeysUrl}): a pure webhook * receiver may never call `init()`, and `getConfig()` would block on initialization. Used by * `verifyWebhook` to bind a webhook to THIS app by default (#072) rather than trusting any * app's shared-key-signed delivery. */ export declare function getConfiguredSessionNamespace(): string; export declare function getConfiguredAppId(): string | undefined; /** * True when init() configured a Bounded network (the Cloudflare-native stack). * Synchronous + non-blocking. Used to route reads/writes that behave differently * on Bounded vs the legacy backend (e.g. `count`/`aggregate`, which on * Bounded must use the deterministic server aggregation, not the legacy AI query). */ export declare function isBoundedNetwork(): boolean; /** * Config-scoped variant of {@link isBoundedNetwork}: reports whether a SPECIFIC * config (e.g. a scoped `createClient()` instance's) targets a Bounded network, * rather than the module global. Used so a scoped client routes count/aggregate * by its OWN network, not the global one. */ export declare function isBoundedNetworkConfig(config: ClientConfig): boolean; /** * Merge a partial config over a base config, applying the Bounded endpoint * precedence rule used everywhere: defaults (or `base`) < network preset < * explicit fields. Pure - never touches module state. Shared by `init` (base = * the current global) and `createClient` (base = the pristine defaults) so both * resolve endpoints identically. Throws on an unsupported `network`. */ export declare function resolveClientConfig(base: ClientConfig, newConfig: Partial): ClientConfig; export declare function init(newConfig: Partial): Promise; export declare function getConfig(): Promise; export {};