# `@getuserfeedback/protocol`

Public contracts for host integrations that load and control the getuserfeedback widget, plus versioned realtime wire messages shared by clients and services.

## Chat realtime

The `chat-realtime` export defines the registration and invalidation messages used after a WebSocket transport opens. A socket has one protocol mode and cannot switch between widget and chat registration. Registration sequences are scoped to one chat socket and increase for every client send, including retries after a missing or retryable outcome. A new socket starts a new sequence. Servers atomically claim only newer sequences before authentication; older or equal attempts are `superseded` and cannot mutate registration state. Clients apply outcomes only for their latest sequence and ignore older outcomes.

Only `chat.connected` establishes an authorized audience. That audience is an immutable registration snapshot: it is never silently retargeted when identity configuration changes. `audienceRevision` identifies the snapshot, and `registrationExpiresAt` is the authoritative moment when the server stops authorizing it. `registrationExpiresInMs` is the remaining lease duration measured when the server constructs the response. It is a clock-independent scheduling hint, not a new expiry boundary: transport time has already consumed part of it, so clients refresh and stop with a safety margin. The socket may remain open after expiry or revocation, but it receives no audience events until a newer registration succeeds. Clients register again before expiry and after changing credentials or identity inputs.

A rejection for a newly claimed latest sequence leaves the socket unauthorized. `superseded` is different: it reports an attempt that did not claim state and therefore does not clear a newer registration. `retryable` governs automatic retry of the same operation with unchanged inputs; `false` does not prevent a later registration after credentials or configuration change. A structurally invalid request with a usable sequence produces `invalid_request`; failed authentication produces `invalid_auth`. A routed `chat.connect` request whose sequence cannot be parsed clears server-side authorization and closes the socket without an outcome, because an uncorrelated rejection cannot be applied safely.

`conversations.sync` is scoped to its named audience revision, is only a best-effort invalidation hint, and never establishes or changes authorization. Clients reconcile through authenticated HTTP after registration, after each matching hint, and periodically while connected; the socket is not a source of truth.

## Lifecycle contract

This package defines the public shapes for:

- init-time widget configuration
- post-load widget commands
- host SDK types and settlement helpers

## What hosts can do after init

After the widget has been initialized, a public host integration may:

- identify the current user with `identify`
- update consent with `configure({ consent })`
- update theme with `configure({ colorScheme })`
- update auth with `configure({ auth })`
- open, prefetch, prerender, close, or reset flows

## Identification

Public identification is already supported.

Use one of these public command shapes:

- `{ kind: "identify", userId, traits? }`
- `{ kind: "identify", traits }`

`identify` is a post-init lifecycle operation. The public root contract does not currently accept identity inside `init` or `configure`.

## Navigation updates

Explicit public navigation update commands are not part of the current public contract.

There is no public `navigate`, `updatePage`, or `hostContextUpdated` command in `@getuserfeedback/protocol`. Hosts should not invent private navigation bridges on top of internal loader or core commands.

Loader-driven integrations may still observe browser URL changes internally for targeting and telemetry, but that behavior is internal runtime behavior, not a stable public contract yet.

## GTM and other adapters

Adapters built on top of this package should only bridge capabilities that exist in this public contract.

- Use `identify` only because it is public and supported.
- Keep consent and theme updates mapped to `configure`.
- Do not expose custom navigation-update fields until this package defines a public navigation contract.
