iOS
The public API of the iOS, generated from release 1.0.1
Classes
KindlyWebViewClient
class
public final class KindlyWebViewClientThe Kindly web-view chat SDK. Use it through KindlyWebViewSDK; every member is static and may be called from any thread.
Member | Declaration | Description |
|---|---|---|
delegate | public static var delegate: KindlyWebViewClientDelegate? | The link delegate. Held weakly, and kept across start() and kill(). |
events | static var events: AnyPublisher<KindlyEvent, Never> | Every event: load, message, buttonClick, ui, globalIcon and state. Emitted on the main thread. A hot stream with no replay; valid before start(). |
state | static var state: AnyPublisher<KindlyEventState, Never> | The SDK state. Replays the current value to every new subscriber; emits on the main thread. |
currentState | static var currentState: KindlyEventState | The current state, readable from any thread. |
isSupported | static var isSupported: Bool | false when the chat cannot run in this app: the app declares WKAppBoundDomains without chat.kindlycdn.com, or the current chat page reported, while it loaded, that the web view lacks features the widget needs (the next page checks again: after endChat(), kill() or a start() with another bot key or market; a start() with the same ones keeps the page). displayChat() then shows an "unsupported" screen instead of the chat; nothing crashes. |
verboseLogging | static var verboseLogging: Bool | Debug-level logs under the OSLog subsystem ai.kindly.webview. Off by default. The logs never contain chat content, tokens or URLs beyond scheme and host. |
enableCrashReporting | static var enableCrashReporting: Bool | Whether the SDK reports its own errors to Kindly. Defaults to true. Applied at start(), and immediately when changed afterwards. |
start(botKey:languageCode:market:authTokenProvider:) | static func start(botKey: String, languageCode: String = "en", market: String, authTokenProvider: KindlyWebViewAuthTokenProvider? = nil) | Starts the SDK for a bot. The chat page is created on the first displayChat(), but the usage metrics start here, and the error reports unless enableCrashReporting is off, so an app that asks for the user's consent calls start after it. Calling it again with the same bot key and market keeps the page and replaces the language (for the next page) and the auth provider. A different bot key or market closes the chat and discards the page; the old conversation stays stored for when you switch back. Parameters - botKey: The bot key. - languageCode: The chat language, for example en or nb. Defaults to en. - market: Required market slug. The widget loads /settings/{botKey}/{market}.json; there is no fallback to another market. - authTokenProvider: Called with the chat id when the chat authenticates. See KindlyWebViewAuthTokenProvider. |
start(botKey:languageCode:market:authCredentialsProvider:) | static func start(botKey: String, languageCode: String = "en", market: String, authCredentialsProvider: @escaping KindlyWebViewAuthCredentialsProvider) | Starts the SDK with a provider of full credentials (id token, companion access token, issuer, expiry). Otherwise the same as the token overload. |
displayChat(languageCode:triggerDialogueId:) | static func displayChat(languageCode: String? = nil, triggerDialogueId: String? = nil) | Presents the chat as a sheet over the top view controller. The first call loads the widget; later calls reopen it instantly with the conversation intact. Logs an error and does nothing before start(). Parameters - languageCode: A language for this display. A language other than the live page's reloads the page. - triggerDialogueId: A dialogue to start when the chat opens. |
closeChat() | static func closeChat() | Dismisses the chat. The conversation and the page stay alive, so sendMessage and triggerDialogue keep working while it is hidden. |
endChat() | static func endChat() async | Ends the conversation: tells the backend the user left (when a chat page is loaded), dismisses the chat, and clears the stored conversation, so the next displayChat() starts a new one with a fresh greeting. When no chat page is loaded (never displayed, or released) the backend is not told; that session expires on its own. Returns immediately before start(). |
kill() | static func kill() async | endChat(), then shuts the SDK down. Call start() again before anything else. |
sendMessage(_:newContext:) | static func sendMessage(_ text: String, newContext: [String: String]? = nil) async throws | Sends a message as the user. The text is trimmed; empty text throws KindlyWebViewError.invalidArgument(_:). Throws KindlyWebViewError.chatNotReady when no chat page exists yet (call displayChat() first). While the page is loading the message waits (up to 30 seconds). It opens the chat only when the chat is displayed. newContext goes with this message only. |
triggerDialogue(id:) | static func triggerDialogue(id: String) | Starts a dialogue. Needs a chat page (logs an error otherwise); while the chat is hidden the dialogue runs without opening it. |
setNewContext(_:) | static func setNewContext(_ context: [String: String]) | Context for the next message, button click or trigger. Applied to the loaded page right away, otherwise when the next page loads; once delivered it is not applied again. The widget merges context, so two calls before the next message send both maps. |
clearNewContext() | static func clearNewContext() | Withdraws context set with setNewContext, including context already delivered to the loaded page. |
authenticate() | static func authenticate() async throws | Authenticates the chat with the provider given to start(). Throws KindlyWebViewError.noAuthProvider without one. With a loaded page the widget re-authenticates now; a page that is still loading does once it has loaded (in call order with deauthenticate(), and the call throws KindlyWebViewError.chatNotReady if that page fails); without a page the next page does. |
deauthenticate() | static func deauthenticate() async throws | Makes the chat anonymous. Until authenticate(), token requests are refused and new pages load without auth. A page that is still loading is told once it has loaded. |
Structures
KindlyAuthCredentials
struct
public struct KindlyAuthCredentials: Equatable, SendableThe credentials the host app hands the SDK to authenticate a chat.
Copied from the native SDK. The web-view SDK passes them to the hosted widget: the bearer goes as idToken (the widget refuses credentials without one), the companion access token as accessToken, issuer as is, and expiresAt as Unix seconds.
The Kindly platform verifies an authenticated chat in one of three ways, and this single type covers all of them — which is why nothing here is named after any one of them:
- Kindly JWT — a JWT your own backend signs. Only idToken is read; accessToken is ignored by this strategy.
- Identity provider (JWKS) — a JWT minted by your identity provider. Set accessToken as well when the provider hands you a separate access token; the backend then verifies the pair together and forwards the access token to your webhooks rather than the id token.
- Introspection — an opaque bearer token. Put it in idToken and set issuer so the backend knows which provider to introspect it against.
Every field is optional, but at least one of idToken / accessToken must be set — whichever is present becomes the Authorization: Bearer (see bearerToken). A single-JWT integration can keep returning a plain String from a KindlyWebViewAuthTokenProvider and never touch this type at all.
Member | Declaration | Description |
|---|---|---|
idToken | public let idToken: String? | The OIDC id token, when your provider issues one. Optional. This is the preferred bearer, not a mandatory field — plenty of providers hand back only an access token, and an opaque introspection bearer has no id token at all. What the SDK actually requires is that at least one of idToken / accessToken is set; see bearerToken. |
accessToken | public let accessToken: String? | The access token, when your provider issues one. Its role depends on what else is set. Alongside an idToken it is the dual-token companion and is sent as X-Access-Token. On its own it becomes the bearer — see bearerToken. The Kindly JWT strategy ignores the companion form. |
issuer | public let issuer: String? | The identity provider this credential came from. Sent as X-Auth-Issuer. Required when the bot has more than one provider configured, and when idToken is opaque — the backend cannot read an iss claim out of a token it cannot decode, so without this it has no way to pick a provider. |
expiresAt | public let expiresAt: Date? | When these credentials stop being valid, if you know. Worth supplying when idToken is opaque: the SDK reads exp out of a JWT itself, but an opaque token tells it nothing, and credentials with no known expiry are treated as non-expiring and never proactively refreshed. This is a hint, not an override. The SDK refreshes on whichever comes first out of this, the exp claim it can read, and the expiry the backend reports. A date more than 1e12 seconds after 1970 is read as a millisecond value that was passed as seconds, and is divided by 1000. |
init(idToken:accessToken:issuer:expiresAt:) | public init( idToken: String? = nil, accessToken: String? = nil, issuer: String? = nil, expiresAt: Date? = nil ) | Set at least one of idToken / accessToken. Credentials carrying neither cannot authenticate anything — the SDK reports them as an empty result from your callback and the chat stays anonymous. Parameters - idToken: The OIDC id token, if your provider issues one. - accessToken: The access token, if your provider issues one. - issuer: The provider's issuer. Required for opaque tokens and multi-provider bots. - expiresAt: When the credentials expire, if known. |
init(idToken:accessToken:issuer:expiresAtUnixSeconds:) | public init( idToken: String? = nil, accessToken: String? = nil, issuer: String? = nil, expiresAtUnixSeconds: Int? ) | Convenience for providers that report expiry the way OAuth does — Unix seconds. Parameters - expiresAtUnixSeconds: Expiry as seconds since 1970, exactly as an exp claim or an introspection response carries it. |
bearerToken | var bearerToken: String? | The token actually sent as Authorization: Bearer, or nil when neither field was set. Authorization is mandatory on the backend's auth route, so whichever token the host has goes there — idToken first, falling back to accessToken. A provider that returns only an access token is a normal, supported case: the backend verifies it by whichever strategy the bot is configured for, exactly as it did before dual-token support existed. |
hasToken | var hasToken: Bool | true when these credentials carry something usable. |
companionAccessToken | var companionAccessToken: String? | The access token in its companion role — the value that will be sent as X-Access-Token, or nil when no companion header will be sent. Exposed so a host can see what the SDK will actually do rather than re-deriving the rule. It is nil in two cases that are easy to get wrong: when the access token is itself the bearer (no id token was supplied), and when it merely duplicates the id token. The backend verifies the companion against the id token's at_hash and rejects a mismatched pair outright, so sending a duplicate would fail an auth that would otherwise have succeeded. |
KindlyEvent
struct
public struct KindlyEventAn event emitted by the Kindly web-view SDK.
Besides the typed detail, every event carries the raw kindly:* type string, the time it was emitted in epoch milliseconds, and the detail as JSON text, so wrappers and hosts can forward events without hand-written serialisers.
Member | Declaration | Description |
|---|---|---|
type | public let type: KindlyEventType | The type of event. |
detail | public let detail: KindlyEventDetail | The event details. |
timestamp | public let timestamp: Int64 | When the event was emitted, in milliseconds since 1970. |
rawType | public let rawType: String | The raw event type, kindly:load, kindly:message, kindly:buttonclick, kindly:ui, kindly:globalicon or kindly:state. |
detailJSON | public let detailJSON: String | The event detail as JSON text. For widget events it is the SDK's own projection of what the page sent: the widget fields the SDK forwards, with the same limits as the typed detail, URLs without their query and never an attachment's download URL. For state and SDK-synthesised events it is the equivalent object. |
date | public var date: Date | timestamp as a Date. |
init(type:detail:) | public init(type: KindlyEventType, detail: KindlyEventDetail) | Creates an event stamped with the current time, with detailJSON built from detail, for example to test your event handling. |
KindlyEventAttachment
struct
public struct KindlyEventAttachmentAttachment data for events. The attachment's download URL carries a session token and is never forwarded; storagePath identifies the file.
Member | Declaration | Description |
|---|---|---|
id | public let id: String | Attachment ID |
name | public let name: String | Attachment name |
format | public let format: String | Attachment format |
status | public let status: String | Attachment status |
sender | public let sender: String | Attachment sender |
storagePath | public let storagePath: String | Storage path |
init(id:name:format:status:sender:storagePath:) | public init( id: String, name: String, format: String, status: String, sender: String, storagePath: String ) | Creates an attachment, for example to test your event handling. |
KindlyEventButton
struct
public struct KindlyEventButtonButton data for events.
Member | Declaration | Description |
|---|---|---|
id | public let id: String? | Button ID |
type | public let type: String | Button type |
label | public let label: String | Button label text |
value | public let value: String? | Button value (an absolute URL loses its query) |
index | public let index: Int? | Button index |
hasBeenSelected | public let hasBeenSelected: Bool | Whether the button has been selected |
context | public let context: [String: Any]? | Button context data (flat, at most 20 primitive values) |
init(id:type:label:value:index:hasBeenSelected:context:) | public init( id: String? = nil, type: String, label: String, value: String? = nil, index: Int? = nil, hasBeenSelected: Bool = false, context: [String: Any]? = nil ) | Creates a button, for example to test your event handling. |
KindlyEventGlobalIcon
struct
public struct KindlyEventGlobalIconGlobal icon action data for events.
Member | Declaration | Description |
|---|---|---|
type | public let type: String | Action type |
source | public let source: String | Action source |
value | public let value: [String: Any]? | Additional value data (the icon) |
init(type:source:value:) | public init(type: String, source: String = "user", value: [String: Any]? = nil) | Creates a global icon action, for example to test your event handling. |
KindlyEventImage
struct
public struct KindlyEventImageImage data for events.
Member | Declaration | Description |
|---|---|---|
url | public let url: String | Image URL (query removed) |
altText | public let altText: String? | Alt text for accessibility |
id | public let id: String? | Image ID |
init(url:altText:id:) | public init(url: String, altText: String? = nil, id: String? = nil) | Creates an image, for example to test your event handling. |
KindlyEventLanguage
struct
public struct KindlyEventLanguageLanguage data for events.
Member | Declaration | Description |
|---|---|---|
code | public let code: String | Language code (e.g., "en", "es") |
name | public let name: String | Language name (e.g., "English", "Español") |
isDefault | public let isDefault: Bool | Whether this is the default language |
init(code:name:isDefault:) | public init(code: String, name: String, isDefault: Bool = false) | Creates a language, for example to test your event handling. |
KindlyEventMessage
struct
public struct KindlyEventMessageMessage data for events.
Member | Declaration | Description |
|---|---|---|
id | public let id: String | Message ID. A message the user just typed carries a tempId-... id until the server confirms it. |
chatId | public let chatId: String? | The chat/session ID this message belongs to. |
text | public let text: String? | Message text content |
sender | public let sender: KindlyEventMessageSender | Message sender type |
created | public let created: Date? | Message creation timestamp |
isFromUser | public let isFromUser: Bool | Whether the message is from the user |
exchangeID | public let exchangeID: String? | Exchange ID if applicable |
videoSource | public let videoSource: String? | Video source URL if applicable (query removed) |
exchangeType | public let exchangeType: KindlyEventExchangeType? | Exchange type if applicable |
buttons | public let buttons: [KindlyEventButton] | Message buttons if any |
images | public let images: [KindlyEventImage] | Message images if any |
attachments | public let attachments: [KindlyEventAttachment] | Message attachments if any |
init(id:chatId:text:sender:created:isFromUser:exchangeID:videoSource:exchangeType:buttons:images:attachments:) | public init( id: String, chatId: String? = nil, text: String? = nil, sender: KindlyEventMessageSender, created: Date? = nil, isFromUser: Bool, exchangeID: String? = nil, videoSource: String? = nil, exchangeType: KindlyEventExchangeType? = nil, buttons: [KindlyEventButton] = [], images: [KindlyEventImage] = [], attachments: [KindlyEventAttachment] = [] ) | Creates a message, for example to test your event handling. |
KindlyEventSettings
struct
public struct KindlyEventSettingsSettings data for load events.
Member | Declaration | Description |
|---|---|---|
name | public let name: String | Settings name |
id | public let id: String | Settings ID |
languages | public let languages: [KindlyEventLanguage] | Available languages |
style | public let style: KindlyEventStyle | Style configuration |
init(name:id:languages:style:) | public init(name: String, id: String, languages: [KindlyEventLanguage], style: KindlyEventStyle) | Creates load settings, for example to test your event handling. |
KindlyEventState
struct
public struct KindlyEventState: EquatableState data for events.
The field names match the native SDK. In the web-view SDK isSocketConnected and isConnected both mean "the SDK page has loaded the widget" (also while the chat is hidden), and connectionState is one of none, loading, connected, failed, unsupported and disconnected.
Member | Declaration | Description |
|---|---|---|
isChatDisplayed | public let isChatDisplayed: Bool | Whether the chat is currently displayed |
isStarted | public let isStarted: Bool | Whether the SDK has been started |
isSocketConnected | public let isSocketConnected: Bool | Whether the widget page is loaded |
isConnected | public let isConnected: Bool | Whether the widget page is loaded (same as isSocketConnected) |
connectionState | public let connectionState: String | Current connection state as string |
init(isChatDisplayed:isStarted:isSocketConnected:isConnected:connectionState:) | public init( isChatDisplayed: Bool, isStarted: Bool, isSocketConnected: Bool, isConnected: Bool, connectionState: String ) | Creates a state, for example to test your event handling. |
KindlyEventStyle
struct
public struct KindlyEventStyleStyle data for events.
Member | Declaration | Description |
|---|---|---|
background | public let background: String? | Background color in hex format |
buttonBackground | public let buttonBackground: String? | Button background color in hex format |
buttonText | public let buttonText: String? | Button text color in hex format |
headerBackground | public let headerBackground: String? | Header background color in hex format |
headerText | public let headerText: String? | Header text color in hex format |
inputBackground | public let inputBackground: String? | Input background color in hex format |
inputText | public let inputText: String? | Input text color in hex format |
userMessageBackground | public let userMessageBackground: String? | User message background color in hex format |
userMessageTextColor | public let userMessageTextColor: String? | User message text color in hex format |
botMessageBackground | public let botMessageBackground: String? | Bot message background color in hex format |
botMessageTextColor | public let botMessageTextColor: String? | Bot message text color in hex format |
init(background:buttonBackground:buttonText:headerBackground:headerText:inputBackground:inputText:userMessageBackground:userMessageTextColor:botMessageBackground:botMessageTextColor:) | public init( background: String? = nil, buttonBackground: String? = nil, buttonText: String? = nil, headerBackground: String? = nil, headerText: String? = nil, inputBackground: String? = nil, inputText: String? = nil, userMessageBackground: String? = nil, userMessageTextColor: String? = nil, botMessageBackground: String? = nil, botMessageTextColor: String? = nil ) | Creates a style, for example to test your event handling. |
KindlyEventUIAction
struct
public struct KindlyEventUIActionUI action data for events.
Member | Declaration | Description |
|---|---|---|
type | public let type: KindlyUIActionType | Action type |
source | public let source: String | Action source (user or programmatic) |
chatId | public let chatId: String | Chat ID (empty when the widget had none yet) |
value | public let value: [String: Any]? | Additional value data |
feedbackType | public let feedbackType: String? | Feedback type if applicable |
feedbackValue | public let feedbackValue: [String: Any]? | Feedback value if applicable |
languageCode | public let languageCode: String? | Language code for language change events |
languageName | public let languageName: String? | Language name for language change events |
previousLanguageCode | public let previousLanguageCode: String? | Previous language code for language change events |
previousLanguageName | public let previousLanguageName: String? | Previous language name for language change events |
nextPage | public let nextPage: String? | Next page for navigation events (chat or welcome-page) |
init(type:source:chatId:value:feedbackType:feedbackValue:languageCode:languageName:previousLanguageCode:previousLanguageName:nextPage:) | public init( type: KindlyUIActionType, source: String = "user", chatId: String, value: [String: Any]? = nil, feedbackType: String? = nil, feedbackValue: [String: Any]? = nil, languageCode: String? = nil, languageName: String? = nil, previousLanguageCode: String? = nil, previousLanguageName: String? = nil, nextPage: String? = nil ) | Creates a UI action, for example to test your event handling. |
Enumerations
KindlyEventDetail
enum
public enum KindlyEventDetailEvent details that can be associated with different event types.
Member | Declaration | Description |
|---|---|---|
load(settings:) | case load(settings: KindlyEventSettings) | Settings loaded event |
message(newMessage:chatLog:) | case message(newMessage: KindlyEventMessage, chatLog: [KindlyEventMessage]) | Message event with new message and chat log |
buttonClick(button:buttonType:chatLog:lastMessage:) | case buttonClick(button: KindlyEventButton, buttonType: String, chatLog: [KindlyEventMessage], lastMessage: KindlyEventMessage) | Button click event |
ui(action:) | case ui(action: KindlyEventUIAction) | UI action event |
globalIcon(action:) | case globalIcon(action: KindlyEventGlobalIcon) | Global icon event |
state(state:) | case state(state: KindlyEventState) | State change event |
KindlyEventExchangeType
enum
public enum KindlyEventExchangeType: String, CaseIterableExchange types for events.
Member | Declaration | Description |
|---|---|---|
dialogue | case dialogue | dialogue: a reply from one of the bot's dialogues. |
fallback | case fallback | fallback: the bot's fallback reply, when no dialogue matched. |
greeting | case greeting | greeting: the bot's greeting. |
systemDialogue | case systemDialogue = "system_dialogue" | system_dialogue: a system dialogue, including the widget's own system messages, which it marks system-dialogue. |
userSays | case userSays = "user_says" | user_says. |
KindlyEventMessageSender
enum
public enum KindlyEventMessageSender: String, CaseIterableMessage sender types for events.
Member | Declaration | Description |
|---|---|---|
agent | case agent = "AGENT" | A human agent, after a handover. |
bot | case bot = "BOT" | The bot. |
system | case system = "SYSTEM" | A message from the chat itself rather than from a person or the bot. |
user | case user = "USER" | The user of your app. |
unknown | case unknown = "UNKNOWN" | A sender this version does not map, such as the widget's WEBHOOK and EXTERNAL, or a message without one. |
KindlyEventType
enum
public enum KindlyEventType: String, CaseIterableTypes of events that can be emitted by the Kindly web-view SDK.
Member | Declaration | Description |
|---|---|---|
load | case load = "kindly:load" | The widget loaded its settings. |
message | case message = "kindly:message" | A message was added to the conversation. |
buttonClick | case buttonClick = "kindly:buttonclick" | The user clicked a message button. |
ui | case ui = "kindly:ui" | A UI action happened (open, close, end chat, language change, feedback, ...). |
globalIcon | case globalIcon = "kindly:globalicon" | A global icon was clicked. |
state | case state = "kindly:state" | The SDK state changed. |
KindlyUIActionType
enum
public enum KindlyUIActionType: String, CaseIterableTypes of UI actions that can be performed.
Member | Declaration | Description |
|---|---|---|
openChatBubble | case openChatBubble = "open-chatbubble" | Open chat bubble |
closeChatBubble | case closeChatBubble = "close-chatbubble" | Close chat bubble |
endChat | case endChat = "end-chat" | End chat |
restartChat | case restartChat = "restart-chat" | Restart chat |
downloadChat | case downloadChat = "download-chat" | Download chat |
deleteChat | case deleteChat = "delete-chat" | Delete chat |
changeLanguage | case changeLanguage = "change-language" | Change language |
showFeedback | case showFeedback = "show-feedback" | Show feedback |
submitFeedback | case submitFeedback = "submit-feedback" | Submit feedback |
dismissFeedback | case dismissFeedback = "dismiss-feedback" | Dismiss feedback |
welcomePageStartChat | case welcomePageStartChat = "welcome-page-start-chat" | The user started the chat from the widget's welcome page. |
KindlyWebViewError
enum
public enum KindlyWebViewError: Error, Equatable, SendableErrors the web-view SDK's async throws APIs report.
Member | Declaration | Description |
|---|---|---|
notStarted | case notStarted | start() has not been called, or kill() ran since. |
chatNotReady | case chatNotReady | No loaded chat page exists to run the call (for example sendMessage before the first displayChat(), or after the page failed to load). |
invalidArgument(_:) | case invalidArgument(String) | An argument was refused before anything was sent. The associated value names the argument (text, newContext, botKey, ...), never its content. |
noAuthProvider | case noAuthProvider | authenticate() was called but start() received no auth provider. |
timeout | case timeout | The page did not answer in time. |
widgetError(code:) | case widgetError(code: String) | The hosted widget reported an error. code is a fixed code such as widget_error. |
unsupported | case unsupported | The web view or the host app's configuration cannot run the chat. |
errorDescription | public var errorDescription: String? | A one-line English description for logs, without any argument's content. |
Protocols
KindlyWebViewClientDelegate
protocol
public protocol KindlyWebViewClientDelegate: AnyObjectLets the host app decide what happens to links the chat opens.
Member | Declaration | Description |
|---|---|---|
shouldHandleLink(url:) | func shouldHandleLink(url: URL) async -> Bool | Return true to let the SDK open url outside the app (Safari, Mail, Phone, ...), or false to handle it yourself. Asked for every http, https, mailto, tel and sms link the chat tries to open while it is displayed; other schemes are blocked before this is asked. The SDK cancels the navigation first and then asks, off the navigation callback, so a slow answer never blocks WebKit. An answer that takes more than 5 seconds counts as true. A synchronous implementation satisfies this requirement too. Default implementation A default implementation is provided, so conforming types do not have to implement this. |
Type Aliases
KindlyWebViewAuthCredentialsProvider
typealias
public typealias KindlyWebViewAuthCredentialsProvider = @Sendable (_ chatId: String) async throws -> KindlyAuthCredentialsSupplies full credentials for an authenticated chat: an id token, a companion access token, an issuer and an expiry hint. Same timing and timeout as KindlyWebViewAuthTokenProvider.
KindlyWebViewAuthTokenProvider
typealias
public typealias KindlyWebViewAuthTokenProvider = @Sendable (_ chatId: String) async throws -> StringSupplies a token for an authenticated chat.
Called with the widget's current chatId after it connects, when KindlyWebViewClient's authenticate() runs, and when the previous credentials are about to expire. Return the JWT (or opaque bearer) for that chat, or throw to leave the chat anonymous.
The SDK waits at most 15 seconds. After that it cancels the task, answers the widget with provider_timeout, and the chat continues anonymously; a late result is discarded. An empty string counts as no token (provider_returned_empty).
KindlyWebViewSDK
typealias
public typealias KindlyWebViewSDK = KindlyWebViewClientThe entry point of the Kindly web-view chat SDK.
It hosts Kindly's web chat widget in a WKWebView with a native bridge. Method names follow the native Kindly SDK: start, displayChat, closeChat, endChat, kill, sendMessage, triggerDialogue, setNewContext, clearNewContext, authenticate, deauthenticate, events and state.