@kindly-ai/react-native 1.0.14 → 1.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -1
- package/android/build.gradle +1 -1
- package/android/maven-repo/ai/kindly/sdk/2.0.14/sdk-2.0.14.aar +0 -0
- package/android/maven-repo/ai/kindly/sdk/{2.0.11/sdk-2.0.11.pom → 2.0.14/sdk-2.0.14.pom} +1 -1
- package/android/src/main/java/com/kindlyai/reactnative/KindlyReactNativeModule.kt +73 -1
- package/ios/KindlyReactNative.mm +24 -6
- package/ios/KindlyReactNativeImpl.swift +91 -3
- package/lib/module/NativeKindlyReactNative.js.map +1 -1
- package/lib/module/index.js +67 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeKindlyReactNative.d.ts +6 -1
- package/lib/typescript/src/NativeKindlyReactNative.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +75 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeKindlyReactNative.ts +8 -1
- package/src/index.tsx +113 -1
- package/android/maven-repo/ai/kindly/sdk/2.0.11/sdk-2.0.11.aar +0 -0
package/README.md
CHANGED
|
@@ -37,6 +37,33 @@ KindlySDK.start({
|
|
|
37
37
|
},
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
+
// Identity providers that issue more than a single JWT - a companion access
|
|
41
|
+
// token, an issuer, or an opaque token whose expiry only you know - use
|
|
42
|
+
// authCredentialsCallback instead. It wins when both are given.
|
|
43
|
+
KindlySDK.start({
|
|
44
|
+
botKey: 'YOUR_BOT_KEY',
|
|
45
|
+
market: 'general',
|
|
46
|
+
authCredentialsCallback: async (chatId) => {
|
|
47
|
+
const tokens = await yourAuthBackend.getTokens({ chatId });
|
|
48
|
+
return {
|
|
49
|
+
idToken: tokens.idToken, // optional
|
|
50
|
+
accessToken: tokens.accessToken, // optional
|
|
51
|
+
issuer: 'https://idp.example.com/', // optional
|
|
52
|
+
expiresAt: tokens.expiresAtUnixSeconds, // optional, Unix seconds
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Only an access token? Return only that. It becomes the bearer.
|
|
58
|
+
KindlySDK.start({
|
|
59
|
+
botKey: 'YOUR_BOT_KEY',
|
|
60
|
+
market: 'general',
|
|
61
|
+
authCredentialsCallback: async () => ({
|
|
62
|
+
accessToken: await yourAuthBackend.getAccessToken(),
|
|
63
|
+
issuer: 'https://idp.example.com/',
|
|
64
|
+
}),
|
|
65
|
+
});
|
|
66
|
+
|
|
40
67
|
// 2. Open the chat UI when the user wants it
|
|
41
68
|
<Button title="Open chat" onPress={() => KindlySDK.launchChat()} />
|
|
42
69
|
|
|
@@ -59,7 +86,7 @@ KindlySDK.setDelegate({
|
|
|
59
86
|
|
|
60
87
|
| Method | Purpose |
|
|
61
88
|
|---|---|
|
|
62
|
-
| `start({botKey, market, languageCode?, authTokenCallback?})` | Initialize the SDK. Must be called before any other method. `market` is **required** (Markets feature); the SDK loads that market's settings with no fallback. |
|
|
89
|
+
| `start({botKey, market, languageCode?, authTokenCallback?, authCredentialsCallback?})` | Initialize the SDK. Must be called before any other method. `market` is **required** (Markets feature); the SDK loads that market's settings with no fallback. Use `authCredentialsCallback` for identity providers that issue more than a single JWT. |
|
|
63
90
|
| `displayChat({languageCode?, triggerDialogueId?})` | Show the chat UI. |
|
|
64
91
|
| `launchChat({triggerDialogueId?})` | Connect (if needed) and show chat. Recommended on Android. |
|
|
65
92
|
| `closeChat()` | Dismiss the UI without ending the session. |
|
|
@@ -67,6 +94,32 @@ KindlySDK.setDelegate({
|
|
|
67
94
|
| `kill()` | Tear the SDK down completely; call `start()` again before reuse. |
|
|
68
95
|
| `setLanguage(code)` | Update the language for the current session. |
|
|
69
96
|
|
|
97
|
+
### Authentication
|
|
98
|
+
|
|
99
|
+
| Method | Purpose |
|
|
100
|
+
|---|---|
|
|
101
|
+
| `authenticate()` | Re-authenticate the live chat with fresh credentials. For a sign-in mid-session; expiry is handled by the SDK on its own. |
|
|
102
|
+
| `deauthenticate()` | Sign out of the chat without ending it. History is kept, the chat continues anonymously. |
|
|
103
|
+
|
|
104
|
+
Every field of `KindlyAuthCredentials` is optional, but set at least one of `idToken` /
|
|
105
|
+
`accessToken`. Whichever you supply becomes the `Authorization: Bearer`, id token first. A provider
|
|
106
|
+
that issues only an access token is a normal, supported case, not a workaround. Credentials with
|
|
107
|
+
neither token cannot authenticate and the chat stays anonymous.
|
|
108
|
+
|
|
109
|
+
Send `accessToken` alongside `idToken` only when the two really are a pair from the same provider.
|
|
110
|
+
The backend verifies the companion against the id token's `at_hash` and rejects a mismatch, so
|
|
111
|
+
passing the same value in both fields fails an auth that would otherwise have succeeded. The SDK
|
|
112
|
+
drops a companion that duplicates the id token rather than sending it.
|
|
113
|
+
|
|
114
|
+
The SDK refreshes credentials 30 seconds before they expire, using whichever is earliest of the
|
|
115
|
+
backend's reported expiry, your `expiresAt`, and the `exp` claim of the bearer. If none is known the
|
|
116
|
+
credentials are treated as non-expiring - a trap for opaque tokens, so set `expiresAt` there. A
|
|
117
|
+
token the SDK cannot parse means the expiry is unknown, never that the token is expired.
|
|
118
|
+
|
|
119
|
+
`deauthenticate()` is safe to call when the chat is already anonymous. The local credentials are
|
|
120
|
+
cleared even if the backend call fails, so a sign-out is never left half done, but the promise still
|
|
121
|
+
rejects so you know the backend did not hear about it.
|
|
122
|
+
|
|
70
123
|
### Messaging
|
|
71
124
|
|
|
72
125
|
| Method | Purpose |
|
package/android/build.gradle
CHANGED
|
@@ -125,7 +125,7 @@ dependencies {
|
|
|
125
125
|
// `scripts/bundle-native-sdks.yml` at bundle time to match the just-
|
|
126
126
|
// released Android SDK version (`git describe --tags --abbrev=0` on
|
|
127
127
|
// the public release repo).
|
|
128
|
-
implementation "ai.kindly:sdk:2.0.
|
|
128
|
+
implementation "ai.kindly:sdk:2.0.14"
|
|
129
129
|
|
|
130
130
|
// Required by the AuthTokenCallback bridge in KindlyReactNativeModule.kt
|
|
131
131
|
// (`CompletableDeferred`, `runBlocking`, `withTimeoutOrNull`).
|
|
Binary file
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<modelVersion>4.0.0</modelVersion>
|
|
4
4
|
<groupId>ai.kindly</groupId>
|
|
5
5
|
<artifactId>sdk</artifactId>
|
|
6
|
-
<version>2.0.
|
|
6
|
+
<version>2.0.14</version>
|
|
7
7
|
<packaging>aar</packaging>
|
|
8
8
|
<name>Kindly SDK</name>
|
|
9
9
|
<description>Kindly Chat SDK for Android — customer support chat widget</description>
|
|
@@ -22,6 +22,8 @@ import kotlinx.coroutines.runBlocking
|
|
|
22
22
|
import kotlinx.coroutines.withTimeoutOrNull
|
|
23
23
|
import no.kindly.chatsdk.chat.AuthTokenCallback
|
|
24
24
|
import no.kindly.chatsdk.chat.ChatKindlySDK
|
|
25
|
+
import no.kindly.chatsdk.chat.KindlyAuthCredentials
|
|
26
|
+
import no.kindly.chatsdk.chat.KindlyAuthCredentialsProvider
|
|
25
27
|
import no.kindly.chatsdk.chat.common.CallbackHandover
|
|
26
28
|
import no.kindly.chatsdk.chat.common.KindlySDKInteraction
|
|
27
29
|
import no.kindly.chatsdk.chat.domain.MessageChat
|
|
@@ -59,6 +61,7 @@ class KindlyReactNativeModule(reactContext: ReactApplicationContext) :
|
|
|
59
61
|
|
|
60
62
|
// Pending request maps for the sync round-trips.
|
|
61
63
|
private val authPending = ConcurrentHashMap<String, CompletableDeferred<String?>>()
|
|
64
|
+
private val credentialsPending = ConcurrentHashMap<String, CompletableDeferred<ReadableMap?>>()
|
|
62
65
|
private val shouldHandlePending = ConcurrentHashMap<String, CompletableDeferred<Boolean>>()
|
|
63
66
|
|
|
64
67
|
// Delegate bridge — set on ChatKindlySDK.`interface` when at least one
|
|
@@ -86,13 +89,24 @@ class KindlyReactNativeModule(reactContext: ReactApplicationContext) :
|
|
|
86
89
|
// Best-effort — clear any pending deferreds so the JS side doesn't hang.
|
|
87
90
|
authPending.values.forEach { it.complete(null) }
|
|
88
91
|
authPending.clear()
|
|
92
|
+
// A null credentials map yields a credential with no token, which the
|
|
93
|
+
// provider below rejects, so the chat falls back to anonymous instead of
|
|
94
|
+
// sitting on a deferred nobody will ever complete.
|
|
95
|
+
credentialsPending.values.forEach { it.complete(null) }
|
|
96
|
+
credentialsPending.clear()
|
|
89
97
|
shouldHandlePending.values.forEach { it.complete(true) }
|
|
90
98
|
shouldHandlePending.clear()
|
|
91
99
|
}
|
|
92
100
|
|
|
93
101
|
// MARK: - Lifecycle
|
|
94
102
|
|
|
95
|
-
override fun start(
|
|
103
|
+
override fun start(
|
|
104
|
+
botKey: String,
|
|
105
|
+
languageCode: String?,
|
|
106
|
+
market: String,
|
|
107
|
+
hasAuthCallback: Boolean,
|
|
108
|
+
hasAuthCredentialsCallback: Boolean,
|
|
109
|
+
) {
|
|
96
110
|
val app = context.applicationContext as? Application
|
|
97
111
|
if (app == null) return
|
|
98
112
|
|
|
@@ -120,15 +134,69 @@ class KindlyReactNativeModule(reactContext: ReactApplicationContext) :
|
|
|
120
134
|
null
|
|
121
135
|
}
|
|
122
136
|
|
|
137
|
+
// The credentials provider wins when both are wired, matching the native SDKs.
|
|
138
|
+
val credentialsProvider: KindlyAuthCredentialsProvider? = if (hasAuthCredentialsCallback) {
|
|
139
|
+
KindlyAuthCredentialsProvider { request ->
|
|
140
|
+
val requestId = UUID.randomUUID().toString()
|
|
141
|
+
val pending = CompletableDeferred<ReadableMap?>()
|
|
142
|
+
credentialsPending[requestId] = pending
|
|
143
|
+
|
|
144
|
+
emitEvent("KindlyGetAuthCredentials", Arguments.createMap().apply {
|
|
145
|
+
putString("requestId", requestId)
|
|
146
|
+
putString("chatId", request.chatId)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
val map = pending.await()
|
|
150
|
+
fun str(key: String): String? =
|
|
151
|
+
map?.takeIf { it.hasKey(key) && !it.isNull(key) }?.getString(key)
|
|
152
|
+
|
|
153
|
+
// Both tokens are optional and either one alone is a valid credential:
|
|
154
|
+
// the SDK picks the bearer itself via `bearerToken`. The only thing that
|
|
155
|
+
// disqualifies a credential is carrying neither, which is what
|
|
156
|
+
// `hasToken` answers. Never gate on `idToken`.
|
|
157
|
+
val credentials = KindlyAuthCredentials(
|
|
158
|
+
idToken = str("idToken"),
|
|
159
|
+
accessToken = str("accessToken"),
|
|
160
|
+
issuer = str("issuer"),
|
|
161
|
+
// JS numbers cross the bridge as Double.
|
|
162
|
+
expiresAt = map?.takeIf { it.hasKey("expiresAt") && !it.isNull("expiresAt") }
|
|
163
|
+
?.getDouble("expiresAt")?.toLong(),
|
|
164
|
+
)
|
|
165
|
+
if (!credentials.hasToken) {
|
|
166
|
+
throw IllegalStateException("Auth credentials not provided")
|
|
167
|
+
}
|
|
168
|
+
credentials
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
null
|
|
172
|
+
}
|
|
173
|
+
|
|
123
174
|
ChatKindlySDK.start(
|
|
124
175
|
application = app,
|
|
125
176
|
botKey = botKey,
|
|
126
177
|
languageCode = languageCode ?: "en",
|
|
127
178
|
market = market,
|
|
128
179
|
authTokenCallback = authCallback,
|
|
180
|
+
authCredentialsProvider = credentialsProvider,
|
|
129
181
|
)
|
|
130
182
|
}
|
|
131
183
|
|
|
184
|
+
override fun authenticate(promise: Promise) {
|
|
185
|
+
scope.launch {
|
|
186
|
+
runCatching { ChatKindlySDK.authenticate().await() }
|
|
187
|
+
.onSuccess { promise.resolve(null) }
|
|
188
|
+
.onFailure { promise.reject("AUTH_FAILED", it.message, it) }
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
override fun deauthenticate(promise: Promise) {
|
|
193
|
+
scope.launch {
|
|
194
|
+
runCatching { ChatKindlySDK.deauthenticate().await() }
|
|
195
|
+
.onSuccess { promise.resolve(null) }
|
|
196
|
+
.onFailure { promise.reject("DEAUTH_FAILED", it.message, it) }
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
132
200
|
override fun displayChat(languageCode: String?, triggerDialogueId: String?) {
|
|
133
201
|
val act = getCurrentActivity() ?: return
|
|
134
202
|
ChatKindlySDK.displayChat(act)
|
|
@@ -309,6 +377,10 @@ class KindlyReactNativeModule(reactContext: ReactApplicationContext) :
|
|
|
309
377
|
authPending.remove(requestId)?.complete(token)
|
|
310
378
|
}
|
|
311
379
|
|
|
380
|
+
override fun respondToAuthCredentials(requestId: String, credentials: ReadableMap?) {
|
|
381
|
+
credentialsPending.remove(requestId)?.complete(credentials)
|
|
382
|
+
}
|
|
383
|
+
|
|
312
384
|
override fun respondToShouldHandle(requestId: String, value: Boolean) {
|
|
313
385
|
shouldHandlePending.remove(requestId)?.complete(value)
|
|
314
386
|
}
|
package/ios/KindlyReactNative.mm
CHANGED
|
@@ -78,6 +78,7 @@ static __weak KindlyReactNative *_sharedInstance;
|
|
|
78
78
|
- (NSArray<NSString *> *)supportedEvents {
|
|
79
79
|
return @[
|
|
80
80
|
@"KindlyGetAuthToken",
|
|
81
|
+
@"KindlyGetAuthCredentials",
|
|
81
82
|
@"KindlyOnHandover",
|
|
82
83
|
@"KindlyOnButtonPressed",
|
|
83
84
|
@"KindlyShouldHandleLink",
|
|
@@ -99,13 +100,15 @@ static __weak KindlyReactNative *_sharedInstance;
|
|
|
99
100
|
#pragma mark - Lifecycle
|
|
100
101
|
|
|
101
102
|
- (void)start:(NSString *)botKey
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
languageCode:(NSString *_Nullable)languageCode
|
|
104
|
+
market:(NSString *)market
|
|
105
|
+
hasAuthCallback:(BOOL)hasAuthCallback
|
|
106
|
+
hasAuthCredentialsCallback:(BOOL)hasAuthCredentialsCallback {
|
|
105
107
|
[_impl startWithBotKey:botKey
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
languageCode:languageCode
|
|
109
|
+
market:market
|
|
110
|
+
hasAuthCallback:hasAuthCallback
|
|
111
|
+
hasAuthCredentialsCallback:hasAuthCredentialsCallback];
|
|
109
112
|
}
|
|
110
113
|
|
|
111
114
|
- (void)displayChat:(NSString *_Nullable)languageCode
|
|
@@ -132,6 +135,16 @@ static __weak KindlyReactNative *_sharedInstance;
|
|
|
132
135
|
[_impl killWithResolve:resolve reject:reject];
|
|
133
136
|
}
|
|
134
137
|
|
|
138
|
+
- (void)authenticate:(RCTPromiseResolveBlock)resolve
|
|
139
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
140
|
+
[_impl authenticateWithResolve:resolve reject:reject];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
- (void)deauthenticate:(RCTPromiseResolveBlock)resolve
|
|
144
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
145
|
+
[_impl deauthenticateWithResolve:resolve reject:reject];
|
|
146
|
+
}
|
|
147
|
+
|
|
135
148
|
- (void)setLanguage:(NSString *)languageCode
|
|
136
149
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
137
150
|
reject:(RCTPromiseRejectBlock)reject {
|
|
@@ -241,6 +254,11 @@ static __weak KindlyReactNative *_sharedInstance;
|
|
|
241
254
|
|
|
242
255
|
#pragma mark - Auth + delegate round-trips
|
|
243
256
|
|
|
257
|
+
- (void)respondToAuthCredentials:(NSString *)requestId
|
|
258
|
+
credentials:(NSDictionary *_Nullable)credentials {
|
|
259
|
+
[_impl respondToAuthCredentials:requestId credentials:credentials];
|
|
260
|
+
}
|
|
261
|
+
|
|
244
262
|
- (void)respondToAuthToken:(NSString *)requestId
|
|
245
263
|
token:(NSString *_Nullable)token {
|
|
246
264
|
[_impl respondToAuthToken:requestId token:token];
|
|
@@ -33,9 +33,11 @@ import UIKit
|
|
|
33
33
|
|
|
34
34
|
// Pending request maps for the sync round-trips. Each entry pairs a
|
|
35
35
|
// request UUID with a (semaphore, answer) tuple. Native blocks on the
|
|
36
|
-
// semaphore
|
|
37
|
-
//
|
|
36
|
+
// semaphore - 30s for auth and credentials, 5s for the shouldHandle bools -
|
|
37
|
+
// and JS replies via respondToAuthToken / respondToAuthCredentials /
|
|
38
|
+
// respondToShouldHandle, which signals it.
|
|
38
39
|
private var authPending: [String: PendingAuth] = [:]
|
|
40
|
+
private var credentialsPending: [String: PendingCredentials] = [:]
|
|
39
41
|
private var shouldHandlePending: [String: PendingBool] = [:]
|
|
40
42
|
private let pendingLock = NSLock()
|
|
41
43
|
|
|
@@ -43,6 +45,10 @@ import UIKit
|
|
|
43
45
|
let semaphore: DispatchSemaphore
|
|
44
46
|
var token: String?
|
|
45
47
|
}
|
|
48
|
+
private struct PendingCredentials {
|
|
49
|
+
let semaphore: DispatchSemaphore
|
|
50
|
+
var credentials: [String: Any]?
|
|
51
|
+
}
|
|
46
52
|
private struct PendingBool {
|
|
47
53
|
let semaphore: DispatchSemaphore
|
|
48
54
|
var value: Bool = true
|
|
@@ -66,7 +72,8 @@ import UIKit
|
|
|
66
72
|
@objc public func start(botKey: String,
|
|
67
73
|
languageCode: String?,
|
|
68
74
|
market: String,
|
|
69
|
-
hasAuthCallback: Bool
|
|
75
|
+
hasAuthCallback: Bool,
|
|
76
|
+
hasAuthCredentialsCallback: Bool) {
|
|
70
77
|
let lang = languageCode ?? "en"
|
|
71
78
|
|
|
72
79
|
let authCallback: AuthTokenCallback? = hasAuthCallback ? { [weak self] chatId, promise in
|
|
@@ -105,9 +112,81 @@ import UIKit
|
|
|
105
112
|
}
|
|
106
113
|
} : nil
|
|
107
114
|
|
|
115
|
+
// The credentials callback wins when both are wired, matching the native SDKs.
|
|
116
|
+
if hasAuthCredentialsCallback {
|
|
117
|
+
// Labelled, not a trailing closure: `start` has two overloads whose last
|
|
118
|
+
// parameter is a closure, and only the label says which one we mean.
|
|
119
|
+
KindlyChatClient.start(
|
|
120
|
+
botKey: botKey,
|
|
121
|
+
languageCode: lang,
|
|
122
|
+
market: market,
|
|
123
|
+
authCredentialsCallback: { [weak self] chatId, promise in
|
|
124
|
+
guard let self = self else {
|
|
125
|
+
promise.reject(NSError(domain: "KindlyReactNative",
|
|
126
|
+
code: -1,
|
|
127
|
+
userInfo: [NSLocalizedDescriptionKey: "self deallocated"]))
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
let requestId = UUID().uuidString
|
|
131
|
+
let semaphore = DispatchSemaphore(value: 0)
|
|
132
|
+
|
|
133
|
+
self.pendingLock.lock()
|
|
134
|
+
self.credentialsPending[requestId] = PendingCredentials(semaphore: semaphore, credentials: nil)
|
|
135
|
+
self.pendingLock.unlock()
|
|
136
|
+
|
|
137
|
+
self.emit(name: "KindlyGetAuthCredentials", body: ["requestId": requestId, "chatId": chatId])
|
|
138
|
+
|
|
139
|
+
DispatchQueue.global().async {
|
|
140
|
+
_ = semaphore.wait(timeout: .now() + 30.0)
|
|
141
|
+
self.pendingLock.lock()
|
|
142
|
+
let entry = self.credentialsPending.removeValue(forKey: requestId)
|
|
143
|
+
self.pendingLock.unlock()
|
|
144
|
+
|
|
145
|
+
// Both tokens are optional and either one alone is a valid credential:
|
|
146
|
+
// the SDK picks the bearer itself via `bearerToken`. The only thing
|
|
147
|
+
// that disqualifies a credential is carrying neither, which is what
|
|
148
|
+
// `hasToken` answers. Never gate on `idToken`.
|
|
149
|
+
let payload = entry?.credentials
|
|
150
|
+
let credentials = KindlyAuthCredentials(
|
|
151
|
+
idToken: payload?["idToken"] as? String,
|
|
152
|
+
accessToken: payload?["accessToken"] as? String,
|
|
153
|
+
issuer: payload?["issuer"] as? String,
|
|
154
|
+
expiresAtUnixSeconds: (payload?["expiresAt"] as? NSNumber)?.intValue
|
|
155
|
+
)
|
|
156
|
+
guard credentials.hasToken else {
|
|
157
|
+
promise.reject(NSError(domain: "KindlyReactNative",
|
|
158
|
+
code: -1,
|
|
159
|
+
userInfo: [NSLocalizedDescriptionKey: "Auth credentials not provided"]))
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
promise.fulfill(credentials)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
)
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
|
|
108
169
|
KindlyChatClient.start(botKey: botKey, languageCode: lang, market: market, authTokenCallback: authCallback)
|
|
109
170
|
}
|
|
110
171
|
|
|
172
|
+
@objc public func authenticate(resolve: @escaping RCTPromiseResolveBlock,
|
|
173
|
+
reject: @escaping RCTPromiseRejectBlock) {
|
|
174
|
+
KindlyChatClient.authenticate().then { _ in
|
|
175
|
+
resolve(NSNull())
|
|
176
|
+
}.catch { error in
|
|
177
|
+
reject("AUTH_FAILED", error.localizedDescription, error)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
@objc public func deauthenticate(resolve: @escaping RCTPromiseResolveBlock,
|
|
182
|
+
reject: @escaping RCTPromiseRejectBlock) {
|
|
183
|
+
KindlyChatClient.deauthenticate().then { _ in
|
|
184
|
+
resolve(NSNull())
|
|
185
|
+
}.catch { error in
|
|
186
|
+
reject("DEAUTH_FAILED", error.localizedDescription, error)
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
111
190
|
// displayChat / launchChat / closeChat MUST be invoked from the main
|
|
112
191
|
// queue — they present/dismiss a UIViewController, and UIKit asserts
|
|
113
192
|
// hard on off-thread layer mutations. TurboModule method invocations
|
|
@@ -277,6 +356,15 @@ import UIKit
|
|
|
277
356
|
|
|
278
357
|
// MARK: - Round-trip responders (called by JS)
|
|
279
358
|
|
|
359
|
+
@objc public func respondToAuthCredentials(_ requestId: String, credentials: [String: Any]?) {
|
|
360
|
+
pendingLock.lock()
|
|
361
|
+
defer { pendingLock.unlock() }
|
|
362
|
+
guard var entry = credentialsPending[requestId] else { return }
|
|
363
|
+
entry.credentials = credentials
|
|
364
|
+
credentialsPending[requestId] = entry
|
|
365
|
+
entry.semaphore.signal()
|
|
366
|
+
}
|
|
367
|
+
|
|
280
368
|
@objc public func respondToAuthToken(_ requestId: String, token: String?) {
|
|
281
369
|
pendingLock.lock()
|
|
282
370
|
defer { pendingLock.unlock() }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeKindlyReactNative.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,mBAAmB,QAAQ,cAAc;
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeKindlyReactNative.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,mBAAmB,QAAQ,cAAc;AAoFlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,mBAAmB,CAAC","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -26,6 +26,23 @@ import NativeKindly from "./NativeKindlyReactNative.js";
|
|
|
26
26
|
* anonymous.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Credentials the host app hands the SDK to authenticate a chat.
|
|
31
|
+
*
|
|
32
|
+
* The Kindly platform verifies an authenticated chat in one of three ways: a
|
|
33
|
+
* JWT your own backend signs, a JWT from your identity provider (optionally
|
|
34
|
+
* paired with an access token), or an opaque bearer token validated by
|
|
35
|
+
* introspection. This one type covers all of them.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Callback invoked by the SDK when it needs fresh auth credentials.
|
|
40
|
+
*
|
|
41
|
+
* Use instead of {@link AuthTokenCallback} when your identity provider issues
|
|
42
|
+
* more than a single JWT. Return `null` if credentials can't be provided, and
|
|
43
|
+
* the SDK treats the chat as anonymous.
|
|
44
|
+
*/
|
|
45
|
+
|
|
29
46
|
/** Callback invoked when a handover to a human agent is initiated. */
|
|
30
47
|
|
|
31
48
|
/**
|
|
@@ -77,6 +94,7 @@ export function hexColor(hex) {
|
|
|
77
94
|
// ────────────────────────────────────────────────────────────────────────────
|
|
78
95
|
const eventEmitter = new NativeEventEmitter(Platform.OS === 'ios' ? NativeModules.KindlyReactNative : undefined);
|
|
79
96
|
let authTokenCallback = null;
|
|
97
|
+
let authCredentialsCallback = null;
|
|
80
98
|
let handoverCallback = null;
|
|
81
99
|
let onButtonPressed = null;
|
|
82
100
|
let shouldHandleLink = null;
|
|
@@ -102,6 +120,24 @@ function attachListeners() {
|
|
|
102
120
|
NativeKindly.respondToAuthToken(event.requestId, null);
|
|
103
121
|
}
|
|
104
122
|
});
|
|
123
|
+
eventEmitter.addListener('KindlyGetAuthCredentials', async raw => {
|
|
124
|
+
const event = raw;
|
|
125
|
+
if (authCredentialsCallback == null) {
|
|
126
|
+
NativeKindly.respondToAuthCredentials(event.requestId, null);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
const credentials = await authCredentialsCallback(event.chatId);
|
|
131
|
+
NativeKindly.respondToAuthCredentials(event.requestId, credentials == null ? null : {
|
|
132
|
+
idToken: credentials.idToken ?? null,
|
|
133
|
+
accessToken: credentials.accessToken ?? null,
|
|
134
|
+
issuer: credentials.issuer ?? null,
|
|
135
|
+
expiresAt: credentials.expiresAt ?? null
|
|
136
|
+
});
|
|
137
|
+
} catch {
|
|
138
|
+
NativeKindly.respondToAuthCredentials(event.requestId, null);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
105
141
|
eventEmitter.addListener('KindlyOnHandover', () => {
|
|
106
142
|
handoverCallback?.();
|
|
107
143
|
});
|
|
@@ -139,7 +175,37 @@ export class KindlySDK {
|
|
|
139
175
|
static start(args) {
|
|
140
176
|
attachListeners();
|
|
141
177
|
authTokenCallback = args.authTokenCallback ?? null;
|
|
142
|
-
|
|
178
|
+
authCredentialsCallback = args.authCredentialsCallback ?? null;
|
|
179
|
+
NativeKindly.start(args.botKey, args.languageCode ?? null, args.market, args.authTokenCallback != null, args.authCredentialsCallback != null);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Re-authenticate the live chat, asking your callback for fresh credentials.
|
|
184
|
+
*
|
|
185
|
+
* For when the *identity* changed rather than the token: the user signed in,
|
|
186
|
+
* or switched account, while the chat was already open. Expiry is handled by
|
|
187
|
+
* the SDK on its own.
|
|
188
|
+
*
|
|
189
|
+
* The chat, its history and its socket are all kept. Rejects if the callback
|
|
190
|
+
* failed or the backend refused the credentials.
|
|
191
|
+
*/
|
|
192
|
+
static authenticate() {
|
|
193
|
+
return NativeKindly.authenticate();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Sign the user out of the chat without ending it.
|
|
198
|
+
*
|
|
199
|
+
* Unbinds the identity on the backend and forgets the stored credentials. The
|
|
200
|
+
* chat carries on anonymously with its history intact. Use `endChat()` when
|
|
201
|
+
* the conversation itself should end.
|
|
202
|
+
*
|
|
203
|
+
* Safe to call when already anonymous. The local credentials are cleared even
|
|
204
|
+
* if the backend call fails, but the promise still rejects so you know the
|
|
205
|
+
* backend did not hear about it.
|
|
206
|
+
*/
|
|
207
|
+
static deauthenticate() {
|
|
208
|
+
return NativeKindly.deauthenticate();
|
|
143
209
|
}
|
|
144
210
|
|
|
145
211
|
/** Show the chat UI. */
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeEventEmitter","NativeModules","Platform","NativeKindly","hexColor","hex","cleaned","replace","v","parseInt","length","Error","eventEmitter","OS","KindlyReactNative","undefined","authTokenCallback","handoverCallback","onButtonPressed","shouldHandleLink","shouldHandleNotification","listenersAttached","attachListeners","addListener","raw","event","respondToAuthToken","requestId","token","chatId","button","chatLog","value","url","respondToShouldHandle","notification","KindlySDK","start","args","botKey","languageCode","market","displayChat","triggerDialogueId","launchChat","closeChat","endChat","kill","setLanguage","sendMessage","text","options","newContext","setCustomTheme","theme","colors","Object","keys","forEach","k","clearCustomTheme","setNewContext","context","clearNewContext","saveAuthToken","setAPNSDeviceToken","saveNotificationToken","handleNotification","data","isKindlyNotification","triggerDialogue","dialogueId","clearTriggerDialogue","handleUrl","callHandover","callback","isChatDisplayed","setVerboseLogging","enabled","setCrashReporting","setAllowCameraAccess","setAllowPhotoLibraryAccess","setAutoMatchStatusBarColor","setForceOverrideStatusBarColor","setDelegate","clearDelegate"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,kBAAkB,EAAEC,aAAa,EAAEC,QAAQ,QAAQ,cAAc;AAC1E,OAAOC,YAAY,MAAM,8BAA2B;;AAEpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;;AAGA;AACA;AACA;AACA;AACA;AACA;;AAMA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;;AAKA;;AAqBA;AACA;AACA;AACA;AACA,OAAO,SAASC,QAAQA,CAACC,GAAW,EAAU;EAC5C,MAAMC,OAAO,GAAGD,GAAG,CAACE,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;EACrC,MAAMC,CAAC,GAAGC,QAAQ,CAACH,OAAO,EAAE,EAAE,CAAC;EAC/B,IAAIA,OAAO,CAACI,MAAM,KAAK,CAAC,EAAE;IACxB,OAAO,CAAC,UAAU,GAAGF,CAAC,MAAM,CAAC;EAC/B;EACA,IAAIF,OAAO,CAACI,MAAM,KAAK,CAAC,EAAE;IACxB,OAAOF,CAAC,KAAK,CAAC;EAChB;EACA,MAAM,IAAIG,KAAK,CAAC,iDAAiDN,GAAG,GAAG,CAAC;AAC1E;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMO,YAAY,GAAG,IAAIZ,kBAAkB,CACzCE,QAAQ,CAACW,EAAE,KAAK,KAAK,GAChBZ,aAAa,CAACa,iBAAiB,GAChCC,SACN,CAAC;AAED,IAAIC,iBAA2C,GAAG,IAAI;AACtD,IAAIC,gBAAyC,GAAG,IAAI;AACpD,IAAIC,eAAmD,GAAG,IAAI;AAC9D,IAAIC,gBAAoD,GAAG,IAAI;AAC/D,IAAIC,wBAAoE,GAAG,IAAI;AAE/E,IAAIC,iBAAiB,GAAG,KAAK;AAE7B,SAASC,eAAeA,CAAA,EAAS;EAC/B,IAAID,iBAAiB,EAAE;EACvBA,iBAAiB,GAAG,IAAI;;EAExB;EACA;EACA;
|
|
1
|
+
{"version":3,"names":["NativeEventEmitter","NativeModules","Platform","NativeKindly","hexColor","hex","cleaned","replace","v","parseInt","length","Error","eventEmitter","OS","KindlyReactNative","undefined","authTokenCallback","authCredentialsCallback","handoverCallback","onButtonPressed","shouldHandleLink","shouldHandleNotification","listenersAttached","attachListeners","addListener","raw","event","respondToAuthToken","requestId","token","chatId","respondToAuthCredentials","credentials","idToken","accessToken","issuer","expiresAt","button","chatLog","value","url","respondToShouldHandle","notification","KindlySDK","start","args","botKey","languageCode","market","authenticate","deauthenticate","displayChat","triggerDialogueId","launchChat","closeChat","endChat","kill","setLanguage","sendMessage","text","options","newContext","setCustomTheme","theme","colors","Object","keys","forEach","k","clearCustomTheme","setNewContext","context","clearNewContext","saveAuthToken","setAPNSDeviceToken","saveNotificationToken","handleNotification","data","isKindlyNotification","triggerDialogue","dialogueId","clearTriggerDialogue","handleUrl","callHandover","callback","isChatDisplayed","setVerboseLogging","enabled","setCrashReporting","setAllowCameraAccess","setAllowPhotoLibraryAccess","setAutoMatchStatusBarColor","setForceOverrideStatusBarColor","setDelegate","clearDelegate"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { TurboModule } from 'react-native';
|
|
2
2
|
export interface Spec extends TurboModule {
|
|
3
|
-
start(botKey: string, languageCode: string | null, market: string, hasAuthCallback: boolean): void;
|
|
3
|
+
start(botKey: string, languageCode: string | null, market: string, hasAuthCallback: boolean, hasAuthCredentialsCallback: boolean): void;
|
|
4
4
|
displayChat(languageCode: string | null, triggerDialogueId: string | null): void;
|
|
5
5
|
launchChat(triggerDialogueId: string | null): void;
|
|
6
6
|
closeChat(): void;
|
|
7
7
|
endChat(): Promise<void>;
|
|
8
8
|
kill(): Promise<void>;
|
|
9
|
+
authenticate(): Promise<void>;
|
|
10
|
+
deauthenticate(): Promise<void>;
|
|
9
11
|
setLanguage(languageCode: string): Promise<void>;
|
|
10
12
|
sendMessage(message: string, newContext: {
|
|
11
13
|
[key: string]: string;
|
|
@@ -40,6 +42,9 @@ export interface Spec extends TurboModule {
|
|
|
40
42
|
setAutoMatchStatusBarColor(enabled: boolean): void;
|
|
41
43
|
setForceOverrideStatusBarColor(enabled: boolean): void;
|
|
42
44
|
respondToAuthToken(requestId: string, token: string | null): void;
|
|
45
|
+
respondToAuthCredentials(requestId: string, credentials: {
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
} | null): void;
|
|
43
48
|
respondToShouldHandle(requestId: string, value: boolean): void;
|
|
44
49
|
setDelegate(onButtonPressed: boolean, shouldHandleLink: boolean, shouldHandleNotification: boolean, onHandover: boolean): void;
|
|
45
50
|
callHandover(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeKindlyReactNative.d.ts","sourceRoot":"","sources":["../../../src/NativeKindlyReactNative.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IAEvC,KAAK,CACH,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"NativeKindlyReactNative.d.ts","sourceRoot":"","sources":["../../../src/NativeKindlyReactNative.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,53 @@
|
|
|
10
10
|
* anonymous.
|
|
11
11
|
*/
|
|
12
12
|
export type AuthTokenCallback = (chatId: string) => Promise<string | null>;
|
|
13
|
+
/**
|
|
14
|
+
* Credentials the host app hands the SDK to authenticate a chat.
|
|
15
|
+
*
|
|
16
|
+
* The Kindly platform verifies an authenticated chat in one of three ways: a
|
|
17
|
+
* JWT your own backend signs, a JWT from your identity provider (optionally
|
|
18
|
+
* paired with an access token), or an opaque bearer token validated by
|
|
19
|
+
* introspection. This one type covers all of them.
|
|
20
|
+
*/
|
|
21
|
+
export interface KindlyAuthCredentials {
|
|
22
|
+
/**
|
|
23
|
+
* The OIDC id token, when your provider issues one.
|
|
24
|
+
*
|
|
25
|
+
* Optional. It is the *preferred* bearer, not a mandatory field. Set at least
|
|
26
|
+
* one of `idToken` / `accessToken`; credentials carrying neither cannot
|
|
27
|
+
* authenticate and the chat stays anonymous.
|
|
28
|
+
*/
|
|
29
|
+
idToken?: string | null;
|
|
30
|
+
/**
|
|
31
|
+
* The access token, when your provider issues one.
|
|
32
|
+
*
|
|
33
|
+
* Its role depends on what else is set. Alongside an `idToken` it is the
|
|
34
|
+
* companion, sent as `X-Access-Token`. On its own it becomes the bearer,
|
|
35
|
+
* which is a normal, supported case. The Kindly JWT strategy ignores the
|
|
36
|
+
* companion form.
|
|
37
|
+
*/
|
|
38
|
+
accessToken?: string | null;
|
|
39
|
+
/**
|
|
40
|
+
* Identity provider issuer, sent as `X-Auth-Issuer`. Required for bots with
|
|
41
|
+
* more than one provider configured, and for any opaque token.
|
|
42
|
+
*/
|
|
43
|
+
issuer?: string | null;
|
|
44
|
+
/**
|
|
45
|
+
* When the credentials expire, in Unix **seconds**. Worth supplying for an
|
|
46
|
+
* opaque token. The SDK reads `exp` off a JWT itself, but an opaque token
|
|
47
|
+
* tells it nothing, and credentials with no known expiry are never
|
|
48
|
+
* proactively refreshed.
|
|
49
|
+
*/
|
|
50
|
+
expiresAt?: number | null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Callback invoked by the SDK when it needs fresh auth credentials.
|
|
54
|
+
*
|
|
55
|
+
* Use instead of {@link AuthTokenCallback} when your identity provider issues
|
|
56
|
+
* more than a single JWT. Return `null` if credentials can't be provided, and
|
|
57
|
+
* the SDK treats the chat as anonymous.
|
|
58
|
+
*/
|
|
59
|
+
export type AuthCredentialsCallback = (chatId: string) => Promise<KindlyAuthCredentials | null>;
|
|
13
60
|
/** Callback invoked when a handover to a human agent is initiated. */
|
|
14
61
|
export type HandoverCallback = () => void;
|
|
15
62
|
/**
|
|
@@ -82,7 +129,35 @@ export declare class KindlySDK {
|
|
|
82
129
|
market: string;
|
|
83
130
|
languageCode?: string;
|
|
84
131
|
authTokenCallback?: AuthTokenCallback;
|
|
132
|
+
/**
|
|
133
|
+
* Use instead of `authTokenCallback` when your identity provider issues more
|
|
134
|
+
* than a single JWT. Takes precedence when both are given.
|
|
135
|
+
*/
|
|
136
|
+
authCredentialsCallback?: AuthCredentialsCallback;
|
|
85
137
|
}): void;
|
|
138
|
+
/**
|
|
139
|
+
* Re-authenticate the live chat, asking your callback for fresh credentials.
|
|
140
|
+
*
|
|
141
|
+
* For when the *identity* changed rather than the token: the user signed in,
|
|
142
|
+
* or switched account, while the chat was already open. Expiry is handled by
|
|
143
|
+
* the SDK on its own.
|
|
144
|
+
*
|
|
145
|
+
* The chat, its history and its socket are all kept. Rejects if the callback
|
|
146
|
+
* failed or the backend refused the credentials.
|
|
147
|
+
*/
|
|
148
|
+
static authenticate(): Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* Sign the user out of the chat without ending it.
|
|
151
|
+
*
|
|
152
|
+
* Unbinds the identity on the backend and forgets the stored credentials. The
|
|
153
|
+
* chat carries on anonymously with its history intact. Use `endChat()` when
|
|
154
|
+
* the conversation itself should end.
|
|
155
|
+
*
|
|
156
|
+
* Safe to call when already anonymous. The local credentials are cleared even
|
|
157
|
+
* if the backend call fails, but the promise still rejects so you know the
|
|
158
|
+
* backend did not hear about it.
|
|
159
|
+
*/
|
|
160
|
+
static deauthenticate(): Promise<void>;
|
|
86
161
|
/** Show the chat UI. */
|
|
87
162
|
static displayChat(args?: {
|
|
88
163
|
languageCode?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAcA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAE3E,sEAAsE;AACtE,MAAM,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,MAAM,2BAA2B,GAAG,CACxC,MAAM,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAClC,OAAO,EAAE,KAAK,CAAC;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC,KACvC,IAAI,CAAC;AAEV;;;;GAIG;AACH,MAAM,MAAM,2BAA2B,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;AAEnE;;;;GAIG;AACH,MAAM,MAAM,mCAAmC,GAAG,CAAC,YAAY,EAAE;IAC/D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,KAAK,OAAO,CAAC;AAEd,qEAAqE;AACrE,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2BAA2B,CAAC,EAAE,MAAM,CAAC;CACtC;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAU5C;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -23,13 +23,16 @@ export interface Spec extends TurboModule {
|
|
|
23
23
|
botKey: string,
|
|
24
24
|
languageCode: string | null,
|
|
25
25
|
market: string,
|
|
26
|
-
hasAuthCallback: boolean
|
|
26
|
+
hasAuthCallback: boolean,
|
|
27
|
+
hasAuthCredentialsCallback: boolean
|
|
27
28
|
): void;
|
|
28
29
|
displayChat(languageCode: string | null, triggerDialogueId: string | null): void;
|
|
29
30
|
launchChat(triggerDialogueId: string | null): void;
|
|
30
31
|
closeChat(): void;
|
|
31
32
|
endChat(): Promise<void>;
|
|
32
33
|
kill(): Promise<void>;
|
|
34
|
+
authenticate(): Promise<void>;
|
|
35
|
+
deauthenticate(): Promise<void>;
|
|
33
36
|
setLanguage(languageCode: string): Promise<void>;
|
|
34
37
|
|
|
35
38
|
// Messaging — newContext map shape: { [key: string]: string }
|
|
@@ -75,6 +78,10 @@ export interface Spec extends TurboModule {
|
|
|
75
78
|
// Map<requestId, Deferred> with a 5-second timeout, falling back to a
|
|
76
79
|
// safe default if JS is silent.
|
|
77
80
|
respondToAuthToken(requestId: string, token: string | null): void;
|
|
81
|
+
respondToAuthCredentials(
|
|
82
|
+
requestId: string,
|
|
83
|
+
credentials: { [key: string]: unknown } | null
|
|
84
|
+
): void;
|
|
78
85
|
respondToShouldHandle(requestId: string, value: boolean): void;
|
|
79
86
|
|
|
80
87
|
// Delegate gating — flips on/off the bridge-level routing for each callback.
|
package/src/index.tsx
CHANGED
|
@@ -25,6 +25,57 @@ import NativeKindly from './NativeKindlyReactNative';
|
|
|
25
25
|
*/
|
|
26
26
|
export type AuthTokenCallback = (chatId: string) => Promise<string | null>;
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Credentials the host app hands the SDK to authenticate a chat.
|
|
30
|
+
*
|
|
31
|
+
* The Kindly platform verifies an authenticated chat in one of three ways: a
|
|
32
|
+
* JWT your own backend signs, a JWT from your identity provider (optionally
|
|
33
|
+
* paired with an access token), or an opaque bearer token validated by
|
|
34
|
+
* introspection. This one type covers all of them.
|
|
35
|
+
*/
|
|
36
|
+
export interface KindlyAuthCredentials {
|
|
37
|
+
/**
|
|
38
|
+
* The OIDC id token, when your provider issues one.
|
|
39
|
+
*
|
|
40
|
+
* Optional. It is the *preferred* bearer, not a mandatory field. Set at least
|
|
41
|
+
* one of `idToken` / `accessToken`; credentials carrying neither cannot
|
|
42
|
+
* authenticate and the chat stays anonymous.
|
|
43
|
+
*/
|
|
44
|
+
idToken?: string | null;
|
|
45
|
+
/**
|
|
46
|
+
* The access token, when your provider issues one.
|
|
47
|
+
*
|
|
48
|
+
* Its role depends on what else is set. Alongside an `idToken` it is the
|
|
49
|
+
* companion, sent as `X-Access-Token`. On its own it becomes the bearer,
|
|
50
|
+
* which is a normal, supported case. The Kindly JWT strategy ignores the
|
|
51
|
+
* companion form.
|
|
52
|
+
*/
|
|
53
|
+
accessToken?: string | null;
|
|
54
|
+
/**
|
|
55
|
+
* Identity provider issuer, sent as `X-Auth-Issuer`. Required for bots with
|
|
56
|
+
* more than one provider configured, and for any opaque token.
|
|
57
|
+
*/
|
|
58
|
+
issuer?: string | null;
|
|
59
|
+
/**
|
|
60
|
+
* When the credentials expire, in Unix **seconds**. Worth supplying for an
|
|
61
|
+
* opaque token. The SDK reads `exp` off a JWT itself, but an opaque token
|
|
62
|
+
* tells it nothing, and credentials with no known expiry are never
|
|
63
|
+
* proactively refreshed.
|
|
64
|
+
*/
|
|
65
|
+
expiresAt?: number | null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Callback invoked by the SDK when it needs fresh auth credentials.
|
|
70
|
+
*
|
|
71
|
+
* Use instead of {@link AuthTokenCallback} when your identity provider issues
|
|
72
|
+
* more than a single JWT. Return `null` if credentials can't be provided, and
|
|
73
|
+
* the SDK treats the chat as anonymous.
|
|
74
|
+
*/
|
|
75
|
+
export type AuthCredentialsCallback = (
|
|
76
|
+
chatId: string
|
|
77
|
+
) => Promise<KindlyAuthCredentials | null>;
|
|
78
|
+
|
|
28
79
|
/** Callback invoked when a handover to a human agent is initiated. */
|
|
29
80
|
export type HandoverCallback = () => void;
|
|
30
81
|
|
|
@@ -109,6 +160,7 @@ const eventEmitter = new NativeEventEmitter(
|
|
|
109
160
|
);
|
|
110
161
|
|
|
111
162
|
let authTokenCallback: AuthTokenCallback | null = null;
|
|
163
|
+
let authCredentialsCallback: AuthCredentialsCallback | null = null;
|
|
112
164
|
let handoverCallback: HandoverCallback | null = null;
|
|
113
165
|
let onButtonPressed: KindlyButtonPressedCallback | null = null;
|
|
114
166
|
let shouldHandleLink: KindlyLinkInterceptCallback | null = null;
|
|
@@ -137,6 +189,30 @@ function attachListeners(): void {
|
|
|
137
189
|
}
|
|
138
190
|
});
|
|
139
191
|
|
|
192
|
+
eventEmitter.addListener('KindlyGetAuthCredentials', async (raw: unknown) => {
|
|
193
|
+
const event = raw as { requestId: string; chatId: string };
|
|
194
|
+
if (authCredentialsCallback == null) {
|
|
195
|
+
NativeKindly.respondToAuthCredentials(event.requestId, null);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
const credentials = await authCredentialsCallback(event.chatId);
|
|
200
|
+
NativeKindly.respondToAuthCredentials(
|
|
201
|
+
event.requestId,
|
|
202
|
+
credentials == null
|
|
203
|
+
? null
|
|
204
|
+
: {
|
|
205
|
+
idToken: credentials.idToken ?? null,
|
|
206
|
+
accessToken: credentials.accessToken ?? null,
|
|
207
|
+
issuer: credentials.issuer ?? null,
|
|
208
|
+
expiresAt: credentials.expiresAt ?? null,
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
} catch {
|
|
212
|
+
NativeKindly.respondToAuthCredentials(event.requestId, null);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
140
216
|
eventEmitter.addListener('KindlyOnHandover', () => {
|
|
141
217
|
handoverCallback?.();
|
|
142
218
|
});
|
|
@@ -190,17 +266,53 @@ export class KindlySDK {
|
|
|
190
266
|
market: string;
|
|
191
267
|
languageCode?: string;
|
|
192
268
|
authTokenCallback?: AuthTokenCallback;
|
|
269
|
+
/**
|
|
270
|
+
* Use instead of `authTokenCallback` when your identity provider issues more
|
|
271
|
+
* than a single JWT. Takes precedence when both are given.
|
|
272
|
+
*/
|
|
273
|
+
authCredentialsCallback?: AuthCredentialsCallback;
|
|
193
274
|
}): void {
|
|
194
275
|
attachListeners();
|
|
195
276
|
authTokenCallback = args.authTokenCallback ?? null;
|
|
277
|
+
authCredentialsCallback = args.authCredentialsCallback ?? null;
|
|
196
278
|
NativeKindly.start(
|
|
197
279
|
args.botKey,
|
|
198
280
|
args.languageCode ?? null,
|
|
199
281
|
args.market,
|
|
200
|
-
args.authTokenCallback != null
|
|
282
|
+
args.authTokenCallback != null,
|
|
283
|
+
args.authCredentialsCallback != null
|
|
201
284
|
);
|
|
202
285
|
}
|
|
203
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Re-authenticate the live chat, asking your callback for fresh credentials.
|
|
289
|
+
*
|
|
290
|
+
* For when the *identity* changed rather than the token: the user signed in,
|
|
291
|
+
* or switched account, while the chat was already open. Expiry is handled by
|
|
292
|
+
* the SDK on its own.
|
|
293
|
+
*
|
|
294
|
+
* The chat, its history and its socket are all kept. Rejects if the callback
|
|
295
|
+
* failed or the backend refused the credentials.
|
|
296
|
+
*/
|
|
297
|
+
static authenticate(): Promise<void> {
|
|
298
|
+
return NativeKindly.authenticate();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Sign the user out of the chat without ending it.
|
|
303
|
+
*
|
|
304
|
+
* Unbinds the identity on the backend and forgets the stored credentials. The
|
|
305
|
+
* chat carries on anonymously with its history intact. Use `endChat()` when
|
|
306
|
+
* the conversation itself should end.
|
|
307
|
+
*
|
|
308
|
+
* Safe to call when already anonymous. The local credentials are cleared even
|
|
309
|
+
* if the backend call fails, but the promise still rejects so you know the
|
|
310
|
+
* backend did not hear about it.
|
|
311
|
+
*/
|
|
312
|
+
static deauthenticate(): Promise<void> {
|
|
313
|
+
return NativeKindly.deauthenticate();
|
|
314
|
+
}
|
|
315
|
+
|
|
204
316
|
/** Show the chat UI. */
|
|
205
317
|
static displayChat(
|
|
206
318
|
args: { languageCode?: string; triggerDialogueId?: string } = {}
|
|
Binary file
|