# Admin bridge

> Talk to the admin from a page it frames.

Source: https://storeware.ai/docs/sdk/bridge

```ts
import { ... } from '@storeware/plugin-sdk';
```

### connectToHost

Connects an extension to its host.

```ts
function connectToHost(options: BridgeOptions): Bridge
```

### createAppBridge

Connects a framed page to the admin, version 2.

```ts
function createAppBridge(options: AppBridgeOptions): AppBridge
```

### BridgeError

A request the admin refused, with its reason.

```ts
new BridgeError(code: BridgeErrorCode | 'timeout' | 'disposed', message: string)
```

### ExtensionMessage

Sent by the extension to the host.

```ts
type ExtensionMessage = {
    protocol: typeof BRIDGE_PROTOCOL;
    type: 'ready';
} | {
    protocol: typeof BRIDGE_PROTOCOL;
    type: 'resize';
    height: number;
} | {
    protocol: typeof BRIDGE_PROTOCOL;
    type: 'toast';
    message: string;
    tone?: 'info' | 'error';
} | {
    protocol: typeof BRIDGE_PROTOCOL;
    type: 'navigate';
    path: string;
};
```

### HostMessage

Sent by the host to the extension.

```ts
type HostMessage = {
    protocol: typeof BRIDGE_PROTOCOL;
    type: 'context';
    storeId: string;
    context: Record<string, string | string[]>;
} | {
    protocol: typeof BRIDGE_PROTOCOL;
    type: 'session';
    token: string;
} | {
    protocol: typeof BRIDGE_PROTOCOL;
    type: 'theme';
    scheme: 'light' | 'dark';
    variables: Record<string, string>;
};
```

### BridgeOptions

| Name | Type | Description |
| --- | --- | --- |
| `hostOrigin` | `string` | The admin origin, for example https://app.storeware.ai. |
| `onContext?` | `(storeId: string, context: Record<string, string \| string[]>) => void` |  |
| `onSession?` | `(token: string) => void` |  |
| `onTheme?` | `(scheme: 'light' \| 'dark', variables: Record<string, string>) => void` | Called with the admin's tokens on connect and whenever they change. |

### Bridge

| Name | Type | Description |
| --- | --- | --- |
| `ready` | `() => void` |  |
| `resize` | `(height: number) => void` |  |
| `toast` | `(message: string, tone?: 'info' \| 'error') => void` |  |
| `navigate` | `(path: string) => void` |  |
| `applyTheme` | `(element: HTMLElement) => void` | Writes the host's tokens onto an element, usually document.documentElement. |
| `dispose` | `() => void` | Stops listening. Call on unmount. |

### AppBridgeOptions

App Bridge version 2, for a page the admin frames.

| Name | Type | Description |
| --- | --- | --- |
| `hostOrigin` | `string` | The admin origin, for example https://app.storeware.ai. |
| `timeoutMs?` | `number` | How long a request waits for the admin, in milliseconds. The merchant's answers never time out. |
| `window?` | `Pick<Window, 'addEventListener' \| 'removeEventListener'>` | The window to listen on. Injectable for tests. |
| `parent?` | `{ postMessage(message: unknown, targetOrigin: string): void }` | Where messages are posted: the admin's window. Injectable for tests. |

### TitleBar

What a page can put above its frame. Send it again to change it, or `\{\}` to clear it.

| Name | Type | Description |
| --- | --- | --- |
| `title?` | `string` | The heading. |
| `primary?` | `TitleBarAction \| null` | The one button the page is for. |
| `secondary?` | `TitleBarAction[]` | Up to three more. |

### AppBridgeEvents

Things the admin tells the page about after the handshake.

| Name | Type | Description |
| --- | --- | --- |
| `title_bar.action` | `string` | A title bar button, by its id. |
| `save_bar.save` | `void` | The merchant pressed Save. Save, then call `saveBar.result`. |
| `save_bar.discard` | `void` | The merchant chose to discard. Put the page back as it was last saved. |
| `theme` | `Theme` | The admin's colours changed. `applyTheme` already has them. |
| `session` | `{ token: string; expiresAt: string }` | A fresh session token, sent every four minutes. |

### SaveBarControls

| Name | Type | Description |
| --- | --- | --- |
| `dirty` | `(dirty: boolean) => void` | Whether there are unsaved changes. While there are, leaving the page is questioned. |
| `result` | `(ok: boolean, message?: string) => void` | How the save the merchant asked for went. Unsaved changes stay unsaved on a failure. |

### ModalControls

| Name | Type | Description |
| --- | --- | --- |
| `open` | `(path: string, title: string, options?: { size?: 'small' \| 'medium' \| 'large'; }) => Promise<unknown>` | Opens a page of your app's home in a window over the admin. Resolves with what that page passed to `close`, or undefined when the merchant closed it. |
| `close` | `(data?: unknown) => void` | From inside a window: closes it, handing `data` to the page that opened it. |

### AppBridge

| Name | Type | Description |
| --- | --- | --- |
| `ready` | `Promise<Welcome>` | Resolves once the admin has answered the handshake. |
| `welcome` | `Welcome \| null` | The handshake's answer, or null until it arrives. |
| `sessionToken` | `() => Promise<string>` | A session token for a call to your own server. |
| `toast` | `(message: string, tone?: 'info' \| 'error') => void` | A short message, shown with your app's name in front of it. Three per ten seconds. |
| `loading` | `(on: boolean) => void` | The loading bar across the top of the frame. |
| `titleBar` | `(bar: TitleBar) => void` | A heading and buttons above the frame. Presses come back as `title_bar.action`. |
| `saveBar` | `SaveBarControls` | The admin's save bar, on pages that have one. |
| `modal` | `ModalControls` | Pages of your app's home in a window over the admin. |
| `confirm` | `(options: { title: string; message: string; confirmLabel?: string; destructive?: boolean; }) => Promise<boolean>` | Asks the merchant. The window is titled with your app's name. |
| `pick` | `(resource: PickerResource, options?: { multiple?: boolean; max?: number; }) => Promise<Picked[]>` | The merchant chooses records. Empty when they cancel. Refused with `not_granted` when your grant cannot read them. |
| `navigate` | `(path: string) => void` | Another page of this shop's admin, relative to the shop: `/orders`. |
| `appNavigate` | `(path: string) => void` | A page of your app's home: `/settings`. |
| `redirect` | `(url: string) => void` | A page off Storeware. The merchant is shown where it goes first. |
| `resize` | `(height: number) => void` | The frame's height in pixels, kept between 80 and 1200. |
| `autoResize` | `(element: HTMLElement) => () => void` | Keeps the frame as tall as `element`. Returns a function that stops it. |
| `on` | `<E extends keyof AppBridgeEvents>(event: E, handler: (detail: AppBridgeEvents[E]) => void) => () => void` | Listens for something the admin tells the page. Returns a function that stops it. |
| `applyTheme` | `(element: HTMLElement) => void` | Writes the admin's 13 `--sw-*` variables onto an element, usually the root. |
| `dispose` | `() => void` | Stops listening and fails anything still waiting. Call on unmount. |

### BRIDGE_PROTOCOL

Version 1's protocol name. Version 2's is `PROTOCOL` in `./bridge/protocol`.

```ts
const BRIDGE_PROTOCOL: 'storeware.bridge.v1'
```
