> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go.gbgplc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Concepts

> Architecture, message protocol, capability model, and design rationale behind GBGBridge.

This document explains the architecture and design principles behind GBGBridge. Understanding these concepts will help you integrate effectively and make informed decisions about how to structure your host application.

## Overview

GBGBridge solves a fundamental problem: web-based identity verification journeys need access to native device capabilities (camera, NFC, biometrics) that are not available — or are severely limited — in a browser context. Rather than building separate native UIs for every journey variation, GBGBridge lets a single web journey drive the user experience while delegating capability-intensive operations to the native host.

## Key Terminology

| Term                 | Definition                                                                                                                                                                 |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Journey**          | A web-based identity verification flow (e.g., document capture + face match + NFC read). The journey runs as HTML/JavaScript inside a WebView.                             |
| **Host**             | The native iOS application that embeds the journey WebView. The host provides native capabilities.                                                                         |
| **Bridge**           | The communication layer between the web journey and the native host. Comprises JavaScript stubs on the web side and `BridgeHost` on the native side.                       |
| **Capability**       | A native feature that the host can provide (e.g., `camera.document`, `nfc.read`). Capabilities can be declared via typed slots (recommended) or in configuration.          |
| **Typed Slot**       | A built-in `CaptureCapability` property on `BridgeHost` (e.g., `documentCapture`, `selfieCapture`). Setting a handler on a slot declares the capability as supported.      |
| **Handler**          | A native Swift object conforming to `BridgeCapabilityHandler` that fulfills requests for a specific action, or a closure set on a typed slot.                              |
| **Permission State** | Metadata about the native permission status for a capability (e.g., `granted`, `denied`, `notDetermined`). Reported in capability query responses.                         |
| **Message**          | A structured JSON envelope exchanged between the web journey and the native host. Every message has a type (request, response, or event), a correlation ID, and a payload. |
| **Action**           | A string identifier for the operation a message relates to (e.g., `"camera.document.capture"`, `"capability.query"`).                                                      |
| **Responder**        | A callback object provided to handlers, used to send a response back to the web journey.                                                                                   |
| **Bootstrap Script** | A JavaScript snippet injected at document start that initializes the `window.GBGBridge` namespace and `receive()` function.                                                |

## Architecture

### Component Diagram

```mermaid theme={null}
graph TB
    subgraph "iOS Host Application"
        BH[BridgeHost<br/>Message Router]
        DC[documentCapture<br/>CaptureCapability Slot]
        SC[selfieCapture<br/>CaptureCapability Slot]
        CH2[NFCHandler<br/>Custom Capability]
        CQH[CapabilityQueryHandler<br/>Built-in]
        DEL[BridgeHostDelegate<br/>Observer]
        CD[CameraDetector<br/>Permission Helper]
    end

    subgraph "WebView Layer"
        BWV[BridgeWebView<br/>UIViewRepresentable]
        BWVC[BridgeWebViewConfigurator<br/>Setup Utility]
        WV[WKWebView]
    end

    subgraph "Web Journey (JavaScript)"
        JS[Journey Code]
        GB[window.GBGBridge]
        MH[webkit.messageHandlers.gbgBridge]
    end

    DC --> BH
    SC --> BH
    CH2 --> BH
    CQH --> BH
    DEL -.-> BH
    CD -.-> DC
    CD -.-> SC
    BH --> WV
    BWVC --> WV
    BWV --> BWVC
    WV --> GB
    WV --> MH
    MH -->|postMessage| BH
    BH -->|evaluateJavaScript| GB
    JS --> MH
    GB --> JS
```

### Layers

1. **Capability Layer** — Typed slots (`CaptureCapability`) and custom capabilities declare what the host supports. `CameraDetector` provides hardware and permission detection.
2. **Routing Layer** — `BridgeHost` receives messages from the WebView, decodes them, and routes requests to typed slot handlers, custom capability handlers, or `BridgeCapabilityHandler` implementations.
3. **Handler Layer** — Typed slots handle capture requests via closures and return strongly-typed `CaptureResult` values. The `BridgeCapabilityHandler` protocol supports arbitrary request handling.
4. **Transport Layer** — `BridgeWebViewConfigurator` and `BridgeWebView` manage the WebView, inject the bootstrap script, and wire up the message channels.
5. **Observation Layer** — `BridgeHostDelegate` lets you observe all messages and handle unrouted requests.

## Message Protocol

All communication uses structured JSON envelopes. The protocol version is `1.0`.

### Message Envelope

```json theme={null}
{
  "version": "1.0",
  "correlationId": "uuid-string",
  "type": "request | response | event",
  "timestamp": 1700000000000,
  "payload": {
    "action": "camera.document.capture",
    "data": { },
    "status": "success | error | cancelled | unsupported | acknowledged",
    "error": {
      "code": "CAMERA_DENIED",
      "message": "User denied camera access",
      "recoverable": true
    }
  }
}
```

### Message Types

| Type       | Direction        | Purpose                                                         |
| ---------- | ---------------- | --------------------------------------------------------------- |
| `request`  | Web → Native     | The web journey asks the host to perform an action.             |
| `response` | Native → Web     | The host sends the result of a request back to the web journey. |
| `event`    | Either direction | An asynchronous notification with no expected response.         |

### Message Flow

```mermaid theme={null}
sequenceDiagram
    participant Web as Web Journey
    participant Bridge as BridgeHost
    participant Handler as CapabilityHandler

    Web->>Bridge: request (capability.query)
    Bridge->>Handler: route to CapabilityQueryHandler
    Handler->>Bridge: respond(success, capabilities)
    Bridge->>Web: response (capability.query, success)

    Web->>Bridge: request (camera.capture)
    Bridge->>Handler: route to CameraHandler
    Note over Handler: Present camera UI,<br/>capture document
    Handler->>Bridge: respond(success, imageData)
    Bridge->>Web: response (camera.capture, success)

    Bridge->>Web: event (journey.progress)
    Note over Web: Update UI based on event
```

### Correlation IDs

Every request has a `correlationId`. When the host responds, it includes the same `correlationId` so the web journey can match responses to their original requests. Events generate their own unique correlation IDs.

### Response Statuses

| Status         | Meaning                                                            |
| -------------- | ------------------------------------------------------------------ |
| `success`      | The request completed successfully. Check `data` for the result.   |
| `error`        | The request failed. Check `error` for details.                     |
| `cancelled`    | The user cancelled the operation (e.g., dismissed a camera sheet). |
| `unsupported`  | The requested capability is not available on this host.            |
| `acknowledged` | The request was received and is being processed asynchronously.    |

## Request Routing

When a message arrives from the web journey:

1. `BridgeHost` decodes the JSON envelope into a `BridgeMessage`.
2. The message is appended to `receivedMessages` (observable).
3. The delegate's `bridgeHost(_:didReceive:)` is called.
4. If the message type is `request`:
   * If a handler is registered for the message's `action`, the handler's `handle(request:responder:)` is called.
   * If no handler is registered, the message is added to `pendingRequests` and the delegate's `bridgeHost(_:unhandledRequest:)` is called.
5. If the message type is `response` or `event`, no routing occurs — it is stored and reported to the delegate.

```mermaid theme={null}
flowchart TD
    A[Message arrives from WebView] --> B[Decode to BridgeMessage]
    B --> C[Append to receivedMessages]
    C --> D[Notify delegate: didReceive]
    D --> E{Message type?}
    E -->|request| F{Handler registered?}
    E -->|response/event| G[Done — stored and observed]
    F -->|Yes| H[Call handler.handle]
    H --> I[Handler calls responder]
    I --> J[Response sent to WebView]
    F -->|No| K[Add to pendingRequests]
    K --> L[Notify delegate: unhandledRequest]
```

## Typed Capability Slots

GBGBridge provides typed capability slots as the recommended way to declare and handle well-known capabilities. A typed slot is a `CaptureCapability` instance exposed as a property on `BridgeHost`.

### Built-in Slots

| Slot             | Property               | Capability ID     | Action ID                 |
| ---------------- | ---------------------- | ----------------- | ------------------------- |
| Document Capture | `host.documentCapture` | `camera.document` | `camera.document.capture` |
| Selfie Capture   | `host.selfieCapture`   | `camera.selfie`   | `camera.selfie.capture`   |

### Handler-as-Declaration

Setting a `handler` on a typed slot simultaneously declares support and provides the implementation:

```swift theme={null}
// This single line declares the capability AND provides the handler
host.documentCapture.handler = { request in
    return await host.documentCapture.awaitCompletion()
}
```

When `handler` is set and `isEnabled` is `true`, the slot reports `isSupported = true`. This means the capability query response automatically reflects the current state — no separate configuration step is needed.

### Automatic Features

Typed slots provide several features automatically:

* **Capability query integration** — Supported slots appear in `capability.query` responses with version and permission state metadata.
* **Result encoding** — Handlers return strongly-typed `CaptureResult` values. The SDK encodes them into the bridge protocol format (base64 image data, dimensions, etc.).
* **Busy rejection** — If a request arrives while another is already active, the slot responds with an error automatically.
* **SwiftUI reactivity** — `activeRequest` is `@Published`, so views can react to capture requests (e.g., present a camera `fullScreenCover`).

### Permission State

Each typed slot has a `permissionState` property that can be populated using `CameraDetector`:

```swift theme={null}
let camera = CameraDetector.check()
host.documentCapture.permissionState = camera.permissionState
host.selfieCapture.permissionState = camera.permissionState
```

This information is included in the `capability.query` response, allowing the web journey to detect permission issues before attempting capture.

## Capability Negotiation

Before attempting to use a native feature, the web journey sends a `capability.query` request. GBGBridge includes a built-in handler (`CapabilityQueryHandler`) that responds automatically.

When using `init(hostVersion:)`, the response is built dynamically from typed slots and custom capabilities. When using `init(configuration:)`, it uses the static `BridgeConfiguration` dictionary.

This pattern allows the web journey to:

* **Adapt its UI** — Show or hide steps based on available capabilities.
* **Prevent errors** — Avoid requesting capabilities that aren't supported.
* **Check permissions** — Detect whether native permissions have been granted before attempting operations.
* **Degrade gracefully** — Fall back to alternative flows when capabilities are missing.

### Query Response Format

```json theme={null}
{
  "environment": "ios",
  "hostVersion": "1.0.0",
  "capabilities": {
    "camera.document": {
      "supported": true,
      "version": "1.0",
      "permissionState": "granted"
    },
    "camera.selfie": {
      "supported": true,
      "version": "1.0",
      "permissionState": "notDetermined"
    },
    "nfc.read": {
      "supported": true,
      "version": "1.0"
    }
  }
}
```

The `permissionState` field is included when the typed slot or configuration provides it. It is omitted for capabilities that don't report permission state.

See the [Capability Handling Guide](/docs/go-v2/developer-integration/sdks/ios/capability-handling) for detailed patterns including typed slots, custom capabilities, and environment-specific behavior.

## Transport Mechanism

### Web → Native (Incoming)

The web journey calls:

```javascript theme={null}
window.webkit.messageHandlers.gbgBridge.postMessage(messageObject);
```

WebKit delivers this to `BridgeHost` via the `WKScriptMessageHandler` protocol.

### Native → Web (Outgoing)

The host evaluates JavaScript on the WebView:

```javascript theme={null}
window.GBGBridge.receive(parsedMessageObject);
```

The `receive()` function is established by the bootstrap script that `BridgeWebViewConfigurator` injects at document start.

### Bootstrap Script

The default bootstrap script is:

```javascript theme={null}
window.GBGBridge = window.GBGBridge || {};
window.GBGBridge.receive = window.GBGBridge.receive || function(){};
```

This creates the namespace and a no-op `receive()` function. The web journey replaces `receive()` with its own implementation once loaded. Because injection happens at document start, the namespace is guaranteed to exist before any web code runs.

You can supply a custom bootstrap script via `BridgeConfiguration.bootstrapScript` if your web journey requires additional initialization.

## Threading Model

* `BridgeHost` is annotated `@MainActor`. All property access and method calls must happen on the main thread.
* `BridgeCapabilityHandler.handle(request:responder:)` is `async`, allowing handlers to perform asynchronous work (e.g., presenting a camera sheet, waiting for NFC scan completion).
* `BridgeResponder.respond()` is safe to call from any thread — it dispatches back to the main actor internally.
* `BridgeWebView` is a SwiftUI `UIViewRepresentable` and follows standard SwiftUI threading rules.

## Design Rationale

### Why a message protocol instead of direct method calls?

A message protocol decouples the web journey from the native host. The web journey doesn't need to know whether it's running in an iOS app, an Android app, or an iframe — it sends the same messages regardless. This also allows the protocol to evolve without breaking existing integrations.

### Why declare capabilities upfront?

Capability declaration serves two purposes: it lets the web journey adapt before hitting a dead end, and it gives the host application explicit control over what features are exposed. A host app might have camera hardware but choose not to expose camera capture for a particular journey.

### Why typed capability slots?

Typed slots eliminate a class of integration errors. With the configuration-based approach, integrators had to keep capability declarations and handler registrations in sync manually — using matching string keys. Typed slots make this impossible to get wrong: setting a handler declares support in a single step. They also provide automatic result encoding, busy rejection, and permission state reporting.

### Why `@MainActor` on BridgeHost?

WebKit APIs (`WKWebView`, `WKUserContentController`) must be accessed on the main thread. Since `BridgeHost` interacts directly with WebKit for both receiving and sending messages, constraining it to the main actor eliminates a class of threading bugs.

### Why no external dependencies?

GBGBridge is a foundational integration layer. Adding dependencies would increase binary size, create version conflicts with consumer apps, and introduce supply-chain risk. The framework uses only Apple system frameworks.

## Next Steps

* [API Reference](/docs/go-v2/developer-integration/sdks/ios/api-reference) — Detailed documentation for every public symbol
* [Embedding Guide](/docs/go-v2/developer-integration/sdks/ios/embedding) — SwiftUI and UIKit integration patterns
* [Messaging Guide](/docs/go-v2/developer-integration/sdks/ios/messaging) — Sending events and handling requests
