import type { ProxyErrorCode, ProviderErrorCode } from '@tokenite/shared'; export type TokeniteConfig = { /** Your app's client ID (from the Tokenite dashboard) */ readonly clientId: string; /** Your app's client secret — only needed for server-side code exchange */ readonly clientSecret?: string; /** The URL Tokenite redirects back to after authorization */ readonly redirectUri: string; /** Tokenite base URL. Default: https://tokenite.ai */ readonly baseUrl?: string; /** Tokenite proxy URL. Default: https://api.tokenite.ai */ readonly proxyUrl?: string; }; /** * OAuth 2.0 / OIDC `prompt` parameter. Tells Tokenite whether to * re-prompt the user even when they have an existing session and/or * an existing grant for this app. * * - `'select_account'` — **recommended for "Sign in with Tokenite" * buttons that follow a sign-out.** Interrupts the silent re-auth * that would otherwise drop the user straight back into your app: * instead Tokenite shows a "Continue as ?" confirmation card * with a "Use a different account" option. The user's existing * spending limit is preserved — they aren't asked to re-set it. * - `'consent'` — re-show the **full** consent screen (budget input * and all), discarding any existing grant. Use this only when you * want the user to actively re-set their budget; for the common * "they signed out, now they're signing back in" case, prefer * `'select_account'`. * - `'login'` — request that the user re-authenticate. Today this * behaves the same as `'consent'` on Tokenite (full session-cookie * clear is a TODO); the consent screen still shows. * - `'none'` — never show UI; fail if interaction is required. * Currently treated as the default (silent reauth). * - `'select_funding'` — **Tokenite extension.** Show the funding picker * so the user can switch where this app's tokens are funded from (their * own key, a team budget, or a campaign they hold). Prefer the * {@link Tokenite.switchFunding} helper over passing this directly. * * The OAuth 2.0 spec allows a space-separated combination * (e.g. `'login consent'`); for that, pass the raw string. The * union above is just for autocomplete on the common values. */ export type OAuthPrompt = 'login' | 'consent' | 'select_account' | 'select_funding' | 'none' | (string & {}); export type AuthorizeOptions = { /** Custom state parameter for CSRF protection. Auto-generated if not provided. */ readonly state?: string; /** Suggested budget amount (user can override on consent screen) */ readonly suggestedBudget?: number; /** * OAuth `prompt` parameter. Most common use: pass `'select_account'` * on "Sign in with Tokenite" buttons that follow a sign-out — it * stops the silent reauth that would otherwise drop the user * straight back into your app, and shows a "Continue as ?" * confirmation card instead. See {@link OAuthPrompt}. */ readonly prompt?: OAuthPrompt; }; export type PopupOptions = { /** Suggested budget amount (user can override on consent screen) */ readonly suggestedBudget?: number; /** * How to host the consent screen. * * - `'iframe'` (default) — overlay an iframe modal in the current * window. Requires the dashboard to allow being framed by your * origin (`Content-Security-Policy: frame-ancestors`). Cleaner UX * but blocked by `X-Frame-Options: DENY`. * - `'window'` — open a separate browser popup window via * `window.open`. Works regardless of frame policy, but the user * may be prompted by their popup blocker. */ readonly mode?: 'iframe' | 'window'; /** Modal/popup width in pixels. Default: 480 */ readonly width?: number; /** Modal/popup height in pixels. Default: 620 */ readonly height?: number; /** * OAuth `prompt` parameter. Most common use: pass `'select_account'` * on "Sign in with Tokenite" buttons that follow a sign-out — it * stops the silent reauth that would otherwise drop the user * straight back into your app, and shows a "Continue as ?" * confirmation card instead. See {@link OAuthPrompt}. */ readonly prompt?: OAuthPrompt; }; export type PopupResult = { /** * OAuth authorization code returned by the consent screen. * Send this to your backend, which exchanges it for an access token * via `tk.exchangeCode(code)`. The exchange requires `clientSecret` * and must never run in browser code. */ readonly code: string; }; export type TopUpOptions = { /** * How to host the top-up screen. * * - `'popup'` (default) — open in a separate browser window via * `window.open`. The user completes the form; the SDK resolves * when Tokenite posts back the new limit. * - `'redirect'` — full-page navigation. The builder's app loses * in-memory state and must reload from the callback URL. */ readonly mode?: 'popup' | 'redirect'; /** * Pre-fill the amount to ADD to the current budget (the top-up form * is additive). Default: the current limit, i.e. doubles the budget. */ readonly suggestedAmount?: number; /** Popup width in pixels. Default: 480 */ readonly width?: number; /** Popup height in pixels. Default: 560 */ readonly height?: number; /** * The user's access token. When provided, the SDK forwards it to the * top-up popup via `postMessage` (origin-locked to the dashboard) and * the popup bootstraps a session from it — skipping the sign-in screen * that would otherwise appear because the popup opens in a different * browser storage partition than the OAuth iframe. Without this the * user is forced to sign in again on first top-up per browser. */ readonly accessToken?: string; }; export type TopUpResult = { readonly ok: true; readonly newLimit: number; readonly remaining: number; } | { readonly ok: false; readonly reason: 'cancelled' | 'popup-blocked' | 'closed' | 'redirected'; }; export type CallWithRecoveryOptions = { /** * What to do when the proxy returns a recoverable funding error. * * - `'popup'` (default) — open Tokenite's top-up popup, then retry the * call once on success. * - `'redirect'` — full-page navigation; the call does not retry (the * builder's app re-loads from the callback and re-invokes manually). * - `'throw'` — disable recovery; surface the original error. */ readonly onFundingNeeded?: 'popup' | 'redirect' | 'throw'; /** Override the suggested top-up amount (the amount to add). */ readonly suggestedAmount?: number; }; export type TokenResponse = { readonly access_token: string; readonly token_type: string; }; export type Provider = 'anthropic' | 'openai' | 'google' | 'grok' | 'bedrock'; /** * The wire flavor a vendor SDK speaks — pick the one matching the SDK * you're using. Used by `tk.agnosticUrl(flavor)` to declare "I want the * shape of flavor X, but I don't care which vendor actually runs the * model I name." */ export type InboundFlavor = 'anthropic' | 'openai' | 'gemini'; export type ProxyCallOptions = { /** The user's Tokenite access token (returned by `tk.exchangeCode()`) */ readonly accessToken: string; /** Which LLM provider to call */ readonly provider: Provider; /** Path on the provider's API (e.g. `/v1/messages`, `/v1/chat/completions`) */ readonly path: string; /** HTTP method. Default: `POST` */ readonly method?: string; /** Request body — the vendor's request shape, JSON-serialised by the SDK */ readonly body: unknown; }; /** Normalised token counts (identical across all providers) */ export type ProxyUsage = { /** Number of tokens in the prompt / input */ readonly inputTokens: number; /** Number of tokens in the completion / output */ readonly outputTokens: number; }; /** * Successful proxy response. * * `data` contains the original vendor response body (e.g. Anthropic's * message object, OpenAI's chat completion, etc.). `provider`, `model`, * and `usage` are extracted and normalised by the proxy so you don't * need to parse vendor-specific fields. */ export type ProxySuccess = { /** Which LLM provider handled the request */ readonly provider: Provider; /** The model that generated the response */ readonly model: string; /** Normalised token usage, or null if the provider didn't report it */ readonly usage: ProxyUsage | null; /** The original, unmodified response body from the LLM provider */ readonly data: unknown; }; /** * Where the error originated. * * - `"proxy"` — Tokenite rejected the request (auth, budget, config). * - `"provider"` — The upstream LLM returned an error (rate limit, overload, etc.). */ export type ErrorSource = 'proxy' | 'provider'; /** * Error response (both proxy-level and provider-level errors share this shape). * * `code` is one of the documented proxy/provider error codes — see the * "Error Codes" section of the README, generated from the canonical * `@tokenite/shared` registry. The type is the union of the known codes * plus an open `string`, so it stays forward-compatible with codes added * server-side before this SDK updates. Narrow a `ProxyResponse` with * `isProxyError`, then branch on `source` to tell proxy from provider. */ export type ProxyError = { readonly error: { /** Machine-readable error code */ readonly code: ProxyErrorCode | ProviderErrorCode | (string & {}); /** Human-readable description */ readonly message: string; /** Where the error originated */ readonly source: ErrorSource; /** Optional structured context (e.g. `retryAfter`, `provider`, `providerMessage`) */ readonly details?: Record; }; }; /** Discriminated union for all non-streaming proxy responses */ export type ProxyResponse = ProxySuccess | ProxyError; /** Type guard: returns true if the response is an error */ export declare const isProxyError: (response: ProxyResponse) => response is ProxyError; /** Type guard: returns true if the response is a success */ export declare const isProxySuccess: (response: ProxyResponse) => response is ProxySuccess; /** * Identity of the user who holds this access token. * * Use `id` as the stable key for per-user state in your app — it survives * token refreshes, re-logins, and device switches. `email` is suitable for * display in your UI; treat it as user-controlled and re-fetch on each * session if you cache it. */ export type UserInfo = { /** Stable Tokenite user id (UUID) */ readonly id: string; /** The user's email address as registered with Tokenite */ readonly email: string; }; /** Visual + identity metadata for a single provider */ export type ProviderInfo = { /** Stable provider id (same value as the `Provider` union) */ readonly id: Provider; /** Human-readable name, e.g. "Anthropic" */ readonly displayName: string; /** Brand colour (hex string, e.g. "#d97706") */ readonly color: string; /** Absolute URL to the provider's logo (PNG or SVG) */ readonly logoUrl: string; /** Whether the logo is a glyph/symbol or a full wordmark */ readonly logoStyle: 'symbol' | 'wordmark'; }; /** * A model the access token may call, scoped to the app's model strategy * and the holder's provider keys. * * - `servedBy` — every provider that hosts this model (catalog fact). * - `callableNow` — the subset the holder can run *right now* (they hold * a key for it). Empty means the model is visible but not yet usable — * render it disabled, or prompt the user to add a key. * * Pass `slug` as the `model` field in `tk.call()`. */ export type ModelInfo = { /** Stable Tokenite model slug — pass this as `model` in tk.call() */ readonly slug: string; /** Human-readable name, e.g. "Claude Haiku 4.5" */ readonly displayName: string; /** The lab that built the model */ readonly creator: 'anthropic' | 'openai' | 'google' | 'grok'; /** Absolute URL to the creator's logo — use it as the model's icon in a picker */ readonly creatorLogoUrl: string; /** Capability tiers this model satisfies (cheap / fast / smart / reasoning) */ readonly tiers: readonly string[]; /** Feature capabilities, e.g. "vision", "tools", "thinking" */ readonly capabilities: readonly string[]; /** Every provider that serves this model */ readonly servedBy: readonly Provider[]; /** Providers the holder can run it through right now (subset of servedBy) */ readonly callableNow: readonly Provider[]; /** Indicative price per million tokens */ readonly pricing: { readonly inputPerMillion: number; readonly outputPerMillion: number; }; }; /** * A provider-agnostic capability bucket. Use this for a "pick a speed / * quality" UI where the user never sees a model name. */ export type TierInfo = { /** Tier id: "cheap" | "fast" | "smart" | "reasoning" */ readonly id: string; /** Whether the holder can run at least one model in this tier */ readonly reachable: boolean; /** A representative callable model slug for this tier, or null */ readonly recommendedModel: string | null; }; /** Summary of the app the access token belongs to */ export type AppInfo = { readonly id: string; readonly name: string; readonly description: string | null; readonly websiteUrl: string | null; /** Absolute URL to the app's icon (PNG/SVG). null when the developer hasn't set one — render initials or a generic glyph. */ readonly iconUrl: string | null; }; /** * Full access context for a single access token: the app it belongs to, * the user who holds it, and the providers it can call. * * `providers` lists only the providers the user has an active key for — * exactly the set that will succeed through `tk.call()` (budget permitting). * * `user` identifies the human who holds the token. Use `user.id` as the * stable key for any per-user state in your app — it survives token * refreshes and re-logins, unlike the access token itself. */ export type AccessContext = { readonly app: AppInfo; readonly user: UserInfo; readonly providers: readonly ProviderInfo[]; /** * Models the token may call — already filtered to the app's strategy * and the user's keys. Render a picker from this; no need to maintain * your own model list. Each entry's `callableNow` says whether it's * usable now or needs a key. */ readonly models: readonly ModelInfo[]; /** * Provider-agnostic capability buckets. For a "pick a tier" UI where * the user never sees a model name — `recommendedModel` gives you a * concrete slug to pass to `tk.call()`. */ readonly tiers: readonly TierInfo[]; }; //# sourceMappingURL=types.d.ts.map