Today WebView Bridge
Web SDK

TypeScript

The full type surface of @today/webview-bridge.

@today/webview-bridge ships its own types. The complete public surface:

// ── Client ────────────────────────────────────────────────────────────────

export interface WebViewBridgeOptions {
  /** Override the global lookup name. Defaults to "todayWebViewBridge". */
  channelName?: string
  /** Inject a channel directly, bypassing the window lookup (tests / custom transports). */
  channel?: NativeChannel
}

export interface WebViewBridge {
  isAvailable(): boolean
  readonly platform: Platform
  track(event: string, properties?: TrackProperties): void
  getHeaders(): Promise<Record<string, string>>
  refreshToken(): Promise<RefreshTokenResult>
  // Host mints the session cookie itself; the bearer is never returned to JS.
  // Resolves false with no host, an unsupported host, or a failed mint.
  establishSession(options?: { refresh?: boolean }): Promise<boolean>
  fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>
}

export function createWebViewBridge(options?: WebViewBridgeOptions): WebViewBridge

// ── Values ──────────────────────────────────────────────────────────────────

export type Platform = 'ios' | 'android' | 'macos' | 'windows' | 'web'

export type TrackProperties = Record<string, string | number | boolean>

export interface RefreshTokenResult {
  authorization: string // ready-to-use header value, e.g. "Bearer <token>"
}

// ── Errors ────────────────────────────────────────────────────────────────

export class BridgeError extends Error {}
export class BridgeUnavailableError extends BridgeError {} // no native host
export class BridgeProtocolError extends BridgeError {} // host replied with a malformed payload

The raw channel (advanced)

You normally never touch the channel directly — the client wraps it. If you are writing the native shim or a test double, this is the shape the SDK expects to find on window:

interface NativeChannel {
  // The known BridgeMessage members, or any `{ type: string }`. An unrecognised
  // `type` resolves to `undefined` (never rejects), which is what keeps
  // capability rollout additive and forward-compatible.
  postMessage(message: BridgeMessage | { type: string }): Promise<unknown>
}

// The wire payload field names stay `ename` / `parameters` for the analytics
// pipeline; the public `track(event, properties)` maps onto them.
type BridgeMessage =
  | { type: 'track'; ename: string; parameters?: TrackProperties }
  | { type: 'headers' }
  | { type: 'refreshToken' }
  | { type: 'establishSession'; refresh?: boolean }

declare global {
  interface Window {
    // iOS — WKScriptMessageHandlerWithReply
    webkit?: {
      messageHandlers?: {
        todayWebViewBridge?: NativeChannel
      }
    }
    // Android — injected shim object
    todayWebViewBridge?: NativeChannel
    // Host-injected synchronous platform tag (authoritative for iOS vs macOS)
    __todayWebView?: { platform?: Platform }
  }
}

export {}

Both transports expose the same postMessage(message): Promise shape. That uniformity is the whole point of the channel design — see the Message envelope and Native Reference.

On this page