react-native-newinstance-chat 0.2.0 → 0.3.0
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/NewinstanceChat.podspec +1 -1
- package/README.md +123 -0
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/newinstancechat/NewinstanceChatModule.kt +67 -2
- package/ios/NewinstanceChatImpl.swift +27 -3
- package/lib/module/index.js +16 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts +11 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +100 -0
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.tsx +17 -0
- package/src/types.ts +102 -0
package/NewinstanceChat.podspec
CHANGED
|
@@ -18,7 +18,7 @@ Pod::Spec.new do |s|
|
|
|
18
18
|
s.pod_target_xcconfig = { "DEFINES_MODULE" => "YES" }
|
|
19
19
|
|
|
20
20
|
# Native chat SDK we wrap, published on CocoaPods Trunk.
|
|
21
|
-
s.dependency "LiveAndAiChat", "~> 0.
|
|
21
|
+
s.dependency "LiveAndAiChat", "~> 0.3.0"
|
|
22
22
|
|
|
23
23
|
install_modules_dependencies(s)
|
|
24
24
|
end
|
package/README.md
CHANGED
|
@@ -75,6 +75,96 @@ sdk.openChat();
|
|
|
75
75
|
The chat screen renders natively — there is no React component to mount.
|
|
76
76
|
Your RN UI is whatever button / banner / FAB triggers `openChat()`.
|
|
77
77
|
|
|
78
|
+
### Authenticating the customer
|
|
79
|
+
|
|
80
|
+
`apiKey` is the publishable widget key **ID**, never the `keyId:secret`
|
|
81
|
+
form, which belongs on your server only.
|
|
82
|
+
|
|
83
|
+
There are two ways to say who the customer is.
|
|
84
|
+
|
|
85
|
+
**Anonymous.** Supply nothing. The chat collects whatever it needs.
|
|
86
|
+
|
|
87
|
+
**Verified.** Have your backend mint a chat identity token and hand it to
|
|
88
|
+
the app. The token is the identity, so no other customer fields are needed:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
// Your backend, with the SECRET key, typically at sign-in:
|
|
92
|
+
// POST https://api.newinstance.cloud/api/v1/chat/sessions
|
|
93
|
+
// x-api-key: sk_live_abc123:YOUR_SECRET_KEY
|
|
94
|
+
// { "customerId": "usr_123", "customerName": "Ada Lovelace",
|
|
95
|
+
// "customerEmail": "ada@example.com", "customerPhone": "+44 20 7946 0958",
|
|
96
|
+
// "metadata": { "plan": "enterprise" }, "expiresInSeconds": 21600 }
|
|
97
|
+
// -> { token, expiresAt, session: { sessionId, ... } }
|
|
98
|
+
|
|
99
|
+
sdk.setUserToken(tokenFromYourBackend);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Everything you put in that payload is signed into the token, so the chat
|
|
103
|
+
session already knows the customer before the app says anything:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
customerId -> the verified customer id
|
|
107
|
+
customerName -> the name on the conversation and on every message
|
|
108
|
+
customerEmail -> also satisfies the merchant's "require email" setting
|
|
109
|
+
customerPhone -> shown to the agent
|
|
110
|
+
metadata -> any extra context your agents should see
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The client then passes **one string**. It never repeats the name, never
|
|
114
|
+
repeats the email, and is never shown a pre-chat form.
|
|
115
|
+
|
|
116
|
+
The server verifies the signature and derives the name, email and customer
|
|
117
|
+
id from the token's claims, so a tampered app cannot claim to be someone
|
|
118
|
+
else. `customerId` passed *without* a token is recorded for agent context
|
|
119
|
+
only and is not treated as identity.
|
|
120
|
+
|
|
121
|
+
Tokens expire (one hour by default). A rejected token arrives on the error
|
|
122
|
+
event as `INVALID_IDENTITY_TOKEN`; mint a fresh one.
|
|
123
|
+
|
|
124
|
+
Sessions are managed over REST: `POST /api/v1/chat/sessions` to create,
|
|
125
|
+
`DELETE /api/v1/chat/sessions?customerId=...` on sign-out. You choose the
|
|
126
|
+
lifetime (60 seconds to 24 hours, default 1 hour) with `expiresInSeconds`.
|
|
127
|
+
|
|
128
|
+
A customer holds **one** live session at a time. Creating another while
|
|
129
|
+
theirs is valid returns `409` with the existing session; mint again once it
|
|
130
|
+
expires or after you revoke it. Revocation takes effect on the next request,
|
|
131
|
+
so an invalidated token stops working immediately even though its signature
|
|
132
|
+
is still valid.
|
|
133
|
+
|
|
134
|
+
The token is the session: the identity is signed into it, and the platform
|
|
135
|
+
stores no copy. Decode the token if you need the name, email, phone or
|
|
136
|
+
metadata back.
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
### Theming
|
|
140
|
+
|
|
141
|
+
The chat resolves colours from three layers:
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
dashboard theme > your local theme > the SDK's built-in theme
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The merchant's dashboard configuration wins, your local theme fills in what
|
|
148
|
+
the dashboard did not set, and the built-in palette fills in the rest, so
|
|
149
|
+
every colour always has a value, even with no network. Merging is per
|
|
150
|
+
token, so setting one colour does not discard the others.
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
const sdk = new NewinstanceChat({
|
|
154
|
+
apiKey: 'sk_live_…',
|
|
155
|
+
theme: { mode: 'dark', sentBubble: '#16A34A' },
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Every `ChatThemeOverride` field is optional; colours are hex strings. An
|
|
160
|
+
unparseable value is ignored rather than throwing. `mode` is only a
|
|
161
|
+
preference: the dashboard's explicit light/dark wins, and its `auto` defers
|
|
162
|
+
to yours, then to the device.
|
|
163
|
+
|
|
164
|
+
If remote configuration cannot be fetched, your local theme still applies
|
|
165
|
+
and the chat stays fully usable; you get a `CONFIG_FETCH_FAILED` warning on
|
|
166
|
+
the error event.
|
|
167
|
+
|
|
78
168
|
### Subscribing to events
|
|
79
169
|
|
|
80
170
|
```ts
|
|
@@ -89,6 +179,39 @@ Event names: `messageReceived`, `messageSent`, `agentTypingChanged`,
|
|
|
89
179
|
`connectionStateChanged`, `unreadCountChanged`, `error`,
|
|
90
180
|
`attachmentUpdated`, `chatClosed`. See `src/types.ts` for payload shapes.
|
|
91
181
|
|
|
182
|
+
### The error event
|
|
183
|
+
|
|
184
|
+
`error` is the channel for "why is my chat not working". It never surfaces
|
|
185
|
+
in the chat interface the customer sees, and it never carries the API key,
|
|
186
|
+
the identity token, or customer data.
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
sdk.addListener('error', (e) => {
|
|
190
|
+
if (e.code === 'INVALID_IDENTITY_TOKEN') return refreshChatToken();
|
|
191
|
+
if (!e.recoverable) reportToYourMonitoring(e.code, e.message);
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
| `code` | What went wrong |
|
|
196
|
+
|---|---|
|
|
197
|
+
| `MISSING_WIDGET_KEY` | No API key was supplied |
|
|
198
|
+
| `INVALID_PUBLIC_KEY` | The key was rejected: wrong key, wrong environment, revoked, expired |
|
|
199
|
+
| `CHAT_CONFIG_UNAVAILABLE` | The key is fine, but the organization has no chat configuration |
|
|
200
|
+
| `CHAT_DISABLED` | Chat is switched off in the dashboard |
|
|
201
|
+
| `CONFIG_FETCH_FAILED` | Remote configuration could not be loaded; the local/built-in theme is in use |
|
|
202
|
+
| `INVALID_IDENTITY_TOKEN` | The token was malformed, expired, or signed for another organization |
|
|
203
|
+
| `NETWORK_ERROR` | The backend could not be reached |
|
|
204
|
+
| `TRANSPORT_ERROR` | The realtime connection dropped |
|
|
205
|
+
| `CHAT_INITIALIZATION_FAILED` | The conversation could not be started |
|
|
206
|
+
| `MESSAGE_SEND_FAILED` | A message could not be delivered |
|
|
207
|
+
| `ATTACHMENT_FAILED` | An attachment could not be uploaded |
|
|
208
|
+
| `SERVER_ERROR` | The backend returned something unusable |
|
|
209
|
+
|
|
210
|
+
The same codes are emitted by the web, Android, iOS and Flutter SDKs.
|
|
211
|
+
`type` (`network` / `validation` / `auth` / `system`) is still present for
|
|
212
|
+
handlers written against 0.2.x; `code` is `undefined` only when the
|
|
213
|
+
underlying native SDK predates coded errors.
|
|
214
|
+
|
|
92
215
|
### The chat-close event
|
|
93
216
|
|
|
94
217
|
`chatClosed` fires **exactly once per chat presentation**, however the
|
package/android/build.gradle
CHANGED
|
@@ -73,5 +73,5 @@ repositories {
|
|
|
73
73
|
dependencies {
|
|
74
74
|
implementation "com.facebook.react:react-android"
|
|
75
75
|
// Native chat SDK the bridge wraps. Published under cloud.newinstance.
|
|
76
|
-
implementation "cloud.newinstance:liveandaichat:0.
|
|
76
|
+
implementation "cloud.newinstance:liveandaichat:0.3.0"
|
|
77
77
|
}
|
|
@@ -4,7 +4,10 @@ import cloud.newinstance.liveandaichat.ConnectionState
|
|
|
4
4
|
import cloud.newinstance.liveandaichat.LiveAndAiChat
|
|
5
5
|
import cloud.newinstance.liveandaichat.LiveAndAiChatConfig
|
|
6
6
|
import cloud.newinstance.liveandaichat.LiveAndAiChatError
|
|
7
|
+
import cloud.newinstance.liveandaichat.ChatSdkError
|
|
8
|
+
import cloud.newinstance.liveandaichat.ChatThemeOverride
|
|
7
9
|
import cloud.newinstance.liveandaichat.ChatUser
|
|
10
|
+
import cloud.newinstance.liveandaichat.ErrorType
|
|
8
11
|
import cloud.newinstance.liveandaichat.model.AttachmentRequest
|
|
9
12
|
import cloud.newinstance.liveandaichat.model.AttachmentSource
|
|
10
13
|
import cloud.newinstance.liveandaichat.model.ChatCloseEvent
|
|
@@ -15,6 +18,7 @@ import com.facebook.react.bridge.Arguments
|
|
|
15
18
|
import com.facebook.react.bridge.Promise
|
|
16
19
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
17
20
|
import com.facebook.react.bridge.ReadableMap
|
|
21
|
+
import com.facebook.react.bridge.ReadableType
|
|
18
22
|
import com.facebook.react.bridge.WritableMap
|
|
19
23
|
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
20
24
|
|
|
@@ -39,6 +43,13 @@ class NewinstanceChatModule(reactContext: ReactApplicationContext) :
|
|
|
39
43
|
private var sdk: LiveAndAiChat? = null
|
|
40
44
|
private var pendingUser: ChatUser? = null
|
|
41
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Whether the host identified the customer with a chat identity token.
|
|
48
|
+
* Used only to tell an API-key rejection apart from a token rejection when
|
|
49
|
+
* reporting an auth failure.
|
|
50
|
+
*/
|
|
51
|
+
private var usingIdentityToken: Boolean = false
|
|
52
|
+
|
|
42
53
|
override fun getName(): String = NAME
|
|
43
54
|
|
|
44
55
|
private fun emit(event: String, body: Any?) {
|
|
@@ -66,12 +77,27 @@ class NewinstanceChatModule(reactContext: ReactApplicationContext) :
|
|
|
66
77
|
}
|
|
67
78
|
} else null
|
|
68
79
|
|
|
80
|
+
// Local theme arrives as a flat string map; unknown keys are ignored by
|
|
81
|
+
// ChatThemeOverride.fromMap so a newer JS SDK cannot break this bridge.
|
|
82
|
+
val themeOverride = if (config.hasKey("theme")) {
|
|
83
|
+
config.getMap("theme")?.let { map ->
|
|
84
|
+
val values = mutableMapOf<String, String?>()
|
|
85
|
+
val it = map.keySetIterator()
|
|
86
|
+
while (it.hasNextKey()) {
|
|
87
|
+
val key = it.nextKey()
|
|
88
|
+
if (map.getType(key) == ReadableType.String) values[key] = map.getString(key)
|
|
89
|
+
}
|
|
90
|
+
ChatThemeOverride.fromMap(values)
|
|
91
|
+
}
|
|
92
|
+
} else null
|
|
93
|
+
|
|
69
94
|
try {
|
|
70
95
|
val cfg = LiveAndAiChatConfig(
|
|
71
96
|
apiKey = apiKey,
|
|
72
97
|
baseUrl = baseUrl ?: LiveAndAiChatConfig.DEFAULT_BASE_URL,
|
|
73
98
|
transport = transport,
|
|
74
99
|
initialMessage = initialMessage,
|
|
100
|
+
theme = themeOverride,
|
|
75
101
|
)
|
|
76
102
|
sdk?.destroy()
|
|
77
103
|
val builder = LiveAndAiChat.Builder(reactApplicationContext).config(cfg)
|
|
@@ -87,13 +113,18 @@ class NewinstanceChatModule(reactContext: ReactApplicationContext) :
|
|
|
87
113
|
}
|
|
88
114
|
|
|
89
115
|
override fun setUser(user: ReadableMap) {
|
|
90
|
-
val
|
|
91
|
-
|
|
116
|
+
val token = if (user.hasKey("customerToken")) user.getString("customerToken") else null
|
|
117
|
+
// With a token the display name is irrelevant: the backend replaces the
|
|
118
|
+
// whole identity from the token's signed claims.
|
|
119
|
+
val name = user.getString("customerName")?.takeIf { it.isNotBlank() }
|
|
120
|
+
?: (if (!token.isNullOrBlank()) "Customer" else return)
|
|
92
121
|
val chatUser = ChatUser(
|
|
93
122
|
customerName = name,
|
|
94
123
|
customerId = if (user.hasKey("customerId")) user.getString("customerId") else null,
|
|
95
124
|
customerEmail = if (user.hasKey("customerEmail")) user.getString("customerEmail") else null,
|
|
125
|
+
customerToken = token,
|
|
96
126
|
)
|
|
127
|
+
usingIdentityToken = !token.isNullOrBlank()
|
|
97
128
|
val current = sdk
|
|
98
129
|
if (current != null) {
|
|
99
130
|
current.setUser(chatUser)
|
|
@@ -240,12 +271,46 @@ class NewinstanceChatModule(reactContext: ReactApplicationContext) :
|
|
|
240
271
|
|
|
241
272
|
override fun onError(error: LiveAndAiChatError) {
|
|
242
273
|
val map = Arguments.createMap()
|
|
274
|
+
map.putString("code", sdkErrorCode(error))
|
|
243
275
|
map.putString("type", error.type.name.lowercase())
|
|
244
276
|
map.putString("message", error.message)
|
|
245
277
|
map.putBoolean("recoverable", error.recoverable)
|
|
246
278
|
emit("error", map)
|
|
247
279
|
}
|
|
248
280
|
|
|
281
|
+
/**
|
|
282
|
+
* Normalise onto the cross-platform code vocabulary. `error.code` carries
|
|
283
|
+
* the raw GraphQL/transport code when the native SDK has one; otherwise the
|
|
284
|
+
* broad type decides. An auth failure while a chat identity token is in use
|
|
285
|
+
* is reported as a token problem, which is the difference between
|
|
286
|
+
* "rotate your key" and "mint a fresh token".
|
|
287
|
+
*/
|
|
288
|
+
private fun sdkErrorCode(error: LiveAndAiChatError): String {
|
|
289
|
+
val known = setOf(
|
|
290
|
+
ChatSdkError.CHAT_CONFIG_UNAVAILABLE,
|
|
291
|
+
ChatSdkError.CHAT_DISABLED,
|
|
292
|
+
ChatSdkError.INVALID_PUBLIC_KEY,
|
|
293
|
+
ChatSdkError.MISSING_WIDGET_KEY,
|
|
294
|
+
ChatSdkError.CONFIG_FETCH_FAILED,
|
|
295
|
+
ChatSdkError.CHAT_INITIALIZATION_FAILED,
|
|
296
|
+
ChatSdkError.NETWORK_ERROR,
|
|
297
|
+
ChatSdkError.SERVER_ERROR,
|
|
298
|
+
ChatSdkError.INVALID_IDENTITY_TOKEN,
|
|
299
|
+
ChatSdkError.TRANSPORT_ERROR,
|
|
300
|
+
ChatSdkError.MESSAGE_SEND_FAILED,
|
|
301
|
+
ChatSdkError.ATTACHMENT_FAILED,
|
|
302
|
+
)
|
|
303
|
+
error.code?.let { if (it in known) return it }
|
|
304
|
+
return when (error.type) {
|
|
305
|
+
ErrorType.AUTH ->
|
|
306
|
+
if (usingIdentityToken) ChatSdkError.INVALID_IDENTITY_TOKEN else ChatSdkError.INVALID_PUBLIC_KEY
|
|
307
|
+
ErrorType.UNAVAILABLE -> ChatSdkError.CHAT_CONFIG_UNAVAILABLE
|
|
308
|
+
ErrorType.NETWORK -> ChatSdkError.NETWORK_ERROR
|
|
309
|
+
ErrorType.VALIDATION -> ChatSdkError.SERVER_ERROR
|
|
310
|
+
ErrorType.SYSTEM -> ChatSdkError.CHAT_INITIALIZATION_FAILED
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
249
314
|
// MARK: - Helpers
|
|
250
315
|
|
|
251
316
|
private fun chatMessageToMap(m: ChatMessage): WritableMap {
|
|
@@ -29,6 +29,11 @@ public final class NewinstanceChatImpl: NSObject, LiveAndAiChatDelegate {
|
|
|
29
29
|
private var sdk: LiveAndAiChat?
|
|
30
30
|
private var pendingUser: ChatUser?
|
|
31
31
|
|
|
32
|
+
/// Whether the host identified the customer with a chat identity token.
|
|
33
|
+
/// Used only to tell an API-key rejection apart from a token rejection when
|
|
34
|
+
/// reporting an auth failure.
|
|
35
|
+
private var usingIdentityToken: Bool = false
|
|
36
|
+
|
|
32
37
|
// MARK: - configure / setUser / initialize
|
|
33
38
|
|
|
34
39
|
@objc(configure:resolver:rejecter:)
|
|
@@ -49,6 +54,17 @@ public final class NewinstanceChatImpl: NSObject, LiveAndAiChatDelegate {
|
|
|
49
54
|
}
|
|
50
55
|
}()
|
|
51
56
|
|
|
57
|
+
// Local theme arrives as a flat string dictionary; unknown keys are
|
|
58
|
+
// ignored by fromDictionary so a newer JS SDK cannot break this bridge.
|
|
59
|
+
let themeOverride: ChatThemeOverride? = {
|
|
60
|
+
guard let raw = configDict["theme"] as? NSDictionary else { return nil }
|
|
61
|
+
var values: [String: String] = [:]
|
|
62
|
+
for (key, value) in raw {
|
|
63
|
+
if let k = key as? String, let v = value as? String { values[k] = v }
|
|
64
|
+
}
|
|
65
|
+
return values.isEmpty ? nil : ChatThemeOverride.fromDictionary(values)
|
|
66
|
+
}()
|
|
67
|
+
|
|
52
68
|
DispatchQueue.main.async { [weak self] in
|
|
53
69
|
guard let self = self else { return }
|
|
54
70
|
do {
|
|
@@ -56,7 +72,8 @@ public final class NewinstanceChatImpl: NSObject, LiveAndAiChatDelegate {
|
|
|
56
72
|
apiKey: apiKey,
|
|
57
73
|
baseUrl: baseUrl ?? LiveAndAiChatConfig.defaultBaseUrl,
|
|
58
74
|
transport: transport,
|
|
59
|
-
initialMessage: initialMessage
|
|
75
|
+
initialMessage: initialMessage,
|
|
76
|
+
theme: themeOverride
|
|
60
77
|
)
|
|
61
78
|
let builder = LiveAndAiChat.Builder().config(cfg)
|
|
62
79
|
if let user = self.pendingUser { _ = builder.user(user) }
|
|
@@ -76,14 +93,20 @@ public final class NewinstanceChatImpl: NSObject, LiveAndAiChatDelegate {
|
|
|
76
93
|
|
|
77
94
|
@objc(setUser:)
|
|
78
95
|
public func setUser(_ userDict: NSDictionary) {
|
|
79
|
-
|
|
96
|
+
let token = (userDict["customerToken"] as? String).flatMap { $0.isEmpty ? nil : $0 }
|
|
97
|
+
// With a token the display name is irrelevant: the backend replaces the
|
|
98
|
+
// whole identity from the token's signed claims.
|
|
99
|
+
let providedName = (userDict["customerName"] as? String).flatMap { $0.isEmpty ? nil : $0 }
|
|
100
|
+
guard let name = providedName ?? (token != nil ? "Customer" : nil) else { return }
|
|
80
101
|
let user = ChatUser(
|
|
81
102
|
customerName: name,
|
|
82
103
|
customerId: userDict["customerId"] as? String,
|
|
83
|
-
customerEmail: userDict["customerEmail"] as? String
|
|
104
|
+
customerEmail: userDict["customerEmail"] as? String,
|
|
105
|
+
customerToken: token
|
|
84
106
|
)
|
|
85
107
|
DispatchQueue.main.async { [weak self] in
|
|
86
108
|
guard let self = self else { return }
|
|
109
|
+
self.usingIdentityToken = token != nil
|
|
87
110
|
if let sdk = self.sdk {
|
|
88
111
|
sdk.setUser(user)
|
|
89
112
|
} else {
|
|
@@ -247,6 +270,7 @@ public final class NewinstanceChatImpl: NSObject, LiveAndAiChatDelegate {
|
|
|
247
270
|
}
|
|
248
271
|
public func didEncounterError(_ error: LiveAndAiChatError) {
|
|
249
272
|
emitter?.emitEvent("error", body: [
|
|
273
|
+
"code": error.sdkCode(usingIdentityToken: usingIdentityToken),
|
|
250
274
|
"type": Self.errorTypeName(error.type),
|
|
251
275
|
"message": error.message,
|
|
252
276
|
"recoverable": error.recoverable,
|
package/lib/module/index.js
CHANGED
|
@@ -29,11 +29,27 @@ export class NewinstanceChat {
|
|
|
29
29
|
* Identify the customer. Safe to call before or after `initialize()`. If
|
|
30
30
|
* called before `configure()` resolves, the user is queued and applied
|
|
31
31
|
* once the native instance exists.
|
|
32
|
+
*
|
|
33
|
+
* Prefer `customerToken`: it is minted by your backend, so the server can
|
|
34
|
+
* verify who the customer is. `customerName` / `customerEmail` /
|
|
35
|
+
* `customerId` alone are client-asserted and are not trusted as identity.
|
|
32
36
|
*/
|
|
33
37
|
setUser(user) {
|
|
34
38
|
NativeNewinstanceChat.setUser(user);
|
|
35
39
|
}
|
|
36
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Identify the customer with a backend-minted chat identity token only.
|
|
43
|
+
* Nothing else needs to be supplied: the server derives the name, email and
|
|
44
|
+
* customer id from the token's signed claims.
|
|
45
|
+
*/
|
|
46
|
+
setUserToken(customerToken) {
|
|
47
|
+
NativeNewinstanceChat.setUser({
|
|
48
|
+
customerName: 'Customer',
|
|
49
|
+
customerToken
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
37
53
|
/**
|
|
38
54
|
* Fetch org config, restore the saved conversation, and connect the
|
|
39
55
|
* subscription transport in the background. Concurrent callers share
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeEventEmitter","NativeModules","NativeNewinstanceChat","emitterSource","NewinstanceChat","emitter","constructor","config","ready","configure","setUser","user","initialize","openChat","closeChat","sendMessage","text","retryMessage","messageId","attachFile","opts","source","uri","Promise","reject","Error","removeAttachment","id","clearAttachments","addListener","event","handler","sub","remove","destroy"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SACEA,kBAAkB,EAClBC,aAAa,QAER,cAAc;AAErB,OAAOC,qBAAqB,MAAM,4BAAyB;
|
|
1
|
+
{"version":3,"names":["NativeEventEmitter","NativeModules","NativeNewinstanceChat","emitterSource","NewinstanceChat","emitter","constructor","config","ready","configure","setUser","user","setUserToken","customerToken","customerName","initialize","openChat","closeChat","sendMessage","text","retryMessage","messageId","attachFile","opts","source","uri","Promise","reject","Error","removeAttachment","id","clearAttachments","addListener","event","handler","sub","remove","destroy"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SACEA,kBAAkB,EAClBC,aAAa,QAER,cAAc;AAErB,OAAOC,qBAAqB,MAAM,4BAAyB;AAyB3D;AACA;AACA;AACA,MAAMC,aAAkB,GACtBF,aAAa,CAACG,eAAe,IAAKF,qBAAiC;AACrE,MAAMG,OAAO,GAAG,IAAIL,kBAAkB,CAACG,aAAa,CAAC;;AAErD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,eAAe,CAAC;EAC3B;;EAGAE,WAAWA,CAACC,MAA6B,EAAE;IACzC,IAAI,CAACC,KAAK,GAAGN,qBAAqB,CAACO,SAAS,CAACF,MAAM,CAAC;EACtD;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEG,OAAOA,CAACC,IAAc,EAAQ;IAC5BT,qBAAqB,CAACQ,OAAO,CAACC,IAAI,CAAC;EACrC;;EAEA;AACF;AACA;AACA;AACA;EACEC,YAAYA,CAACC,aAAqB,EAAQ;IACxCX,qBAAqB,CAACQ,OAAO,CAAC;MAAEI,YAAY,EAAE,UAAU;MAAED;IAAc,CAAC,CAAC;EAC5E;;EAEA;AACF;AACA;AACA;AACA;EACEE,UAAUA,CAAA,EAAkB;IAC1B,OAAOb,qBAAqB,CAACa,UAAU,CAAC,CAAC;EAC3C;;EAEA;EACAC,QAAQA,CAAA,EAAS;IACfd,qBAAqB,CAACc,QAAQ,CAAC,CAAC;EAClC;;EAEA;EACAC,SAASA,CAAA,EAAS;IAChBf,qBAAqB,CAACe,SAAS,CAAC,CAAC;EACnC;EAEAC,WAAWA,CAACC,IAAY,EAAQ;IAC9BjB,qBAAqB,CAACgB,WAAW,CAACC,IAAI,CAAC;EACzC;EAEAC,YAAYA,CAACC,SAAiB,EAAQ;IACpCnB,qBAAqB,CAACkB,YAAY,CAACC,SAAS,CAAC;EAC/C;;EAEA;AACF;AACA;AACA;AACA;EACEC,UAAUA,CAACC,IAAqB,EAAmB;IACjD,IAAI,CAACA,IAAI,CAACC,MAAM,IAAI,CAACD,IAAI,CAACE,GAAG,EAAE;MAC7B,OAAOC,OAAO,CAACC,MAAM,CAAC,IAAIC,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxF;IACA,OAAO1B,qBAAqB,CAACoB,UAAU,CAACC,IAAI,CAAC;EAC/C;;EAEA;EACAM,gBAAgBA,CAACC,EAAU,EAAQ;IACjC5B,qBAAqB,CAAC2B,gBAAgB,CAACC,EAAE,CAAC;EAC5C;;EAEA;EACAC,gBAAgBA,CAAA,EAAS;IACvB7B,qBAAqB,CAAC6B,gBAAgB,CAAC,CAAC;EAC1C;;EAEA;AACF;AACA;AACA;EACEC,WAAWA,CACTC,KAAQ,EACRC,OAAwB,EACZ;IACZ,MAAMC,GAAwB,GAAG9B,OAAO,CAAC2B,WAAW,CAClDC,KAAK,EACLC,OACF,CAAC;IACD,OAAO,MAAMC,GAAG,CAACC,MAAM,CAAC,CAAC;EAC3B;;EAEA;AACF;AACA;AACA;EACEC,OAAOA,CAAA,EAAS;IACdnC,qBAAqB,CAACmC,OAAO,CAAC,CAAC;EACjC;AACF","ignoreList":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AttachmentInput, ChatUser, EventHandler, EventName, NewinstanceChatConfig } from './types';
|
|
2
|
-
export type { AttachmentInput, ChatMessage, ChatUser, ConnectionState, EventMap, EventName, NewinstanceChatConfig, NewinstanceChatError, NewinstanceChatErrorType, } from './types';
|
|
2
|
+
export type { AttachmentInput, AttachmentUpdate, ChatClosedEvent, ChatMessage, ChatThemeOverride, ChatUser, ConnectionState, EventMap, EventName, NewinstanceChatConfig, NewinstanceChatError, NewinstanceChatErrorCode, NewinstanceChatErrorType, } from './types';
|
|
3
3
|
/**
|
|
4
4
|
* React Native binding for the native LiveAndAiChat iOS / Android SDKs.
|
|
5
5
|
*
|
|
@@ -18,8 +18,18 @@ export declare class NewinstanceChat {
|
|
|
18
18
|
* Identify the customer. Safe to call before or after `initialize()`. If
|
|
19
19
|
* called before `configure()` resolves, the user is queued and applied
|
|
20
20
|
* once the native instance exists.
|
|
21
|
+
*
|
|
22
|
+
* Prefer `customerToken`: it is minted by your backend, so the server can
|
|
23
|
+
* verify who the customer is. `customerName` / `customerEmail` /
|
|
24
|
+
* `customerId` alone are client-asserted and are not trusted as identity.
|
|
21
25
|
*/
|
|
22
26
|
setUser(user: ChatUser): void;
|
|
27
|
+
/**
|
|
28
|
+
* Identify the customer with a backend-minted chat identity token only.
|
|
29
|
+
* Nothing else needs to be supplied: the server derives the name, email and
|
|
30
|
+
* customer id from the token's signed claims.
|
|
31
|
+
*/
|
|
32
|
+
setUserToken(customerToken: string): void;
|
|
23
33
|
/**
|
|
24
34
|
* Fetch org config, restore the saved conversation, and connect the
|
|
25
35
|
* subscription transport in the background. Concurrent callers share
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,eAAe,EACf,WAAW,EACX,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,SAAS,CAAC;AASjB;;;;;;;;;GASG;AACH,qBAAa,eAAe;IAC1B,kDAAkD;IAClD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;gBAElB,MAAM,EAAE,qBAAqB;IAIzC
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,SAAS,CAAC;AASjB;;;;;;;;;GASG;AACH,qBAAa,eAAe;IAC1B,kDAAkD;IAClD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;gBAElB,MAAM,EAAE,qBAAqB;IAIzC;;;;;;;;OAQG;IACH,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAI7B;;;;OAIG;IACH,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;IAIzC;;;;OAIG;IACH,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,uEAAuE;IACvE,QAAQ,IAAI,IAAI;IAIhB,sCAAsC;IACtC,SAAS,IAAI,IAAI;IAIjB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI/B,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIrC;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;IAOlD,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIlC,mEAAmE;IACnE,gBAAgB,IAAI,IAAI;IAIxB;;;OAGG;IACH,WAAW,CAAC,CAAC,SAAS,SAAS,EAC7B,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GACvB,MAAM,IAAI;IAQb;;;OAGG;IACH,OAAO,IAAI,IAAI;CAGhB"}
|
|
@@ -14,11 +14,66 @@ export interface NewinstanceChatConfig {
|
|
|
14
14
|
transport?: 'sse' | 'ws';
|
|
15
15
|
/** Optional message pre-seeded as the first outbound message. */
|
|
16
16
|
initialMessage?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Local theme. Ranked BELOW whatever the merchant configured in the
|
|
19
|
+
* dashboard and ABOVE the SDK's built-in palette, merged per property, so a
|
|
20
|
+
* token you set here applies only where the dashboard did not set one.
|
|
21
|
+
*/
|
|
22
|
+
theme?: ChatThemeOverride;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Local theme tokens. Every field is optional; colours are hex strings
|
|
26
|
+
* (`#RRGGBB` or `#AARRGGBB`). An unparseable value is ignored rather than
|
|
27
|
+
* throwing, so a bad colour can never crash the app.
|
|
28
|
+
*/
|
|
29
|
+
export interface ChatThemeOverride {
|
|
30
|
+
/**
|
|
31
|
+
* Force light or dark. Omit for "no opinion": the dashboard's mode wins if
|
|
32
|
+
* it set one, otherwise the device setting.
|
|
33
|
+
*/
|
|
34
|
+
mode?: 'light' | 'dark';
|
|
35
|
+
chatBackground?: string;
|
|
36
|
+
headerBackground?: string;
|
|
37
|
+
headerPrimaryText?: string;
|
|
38
|
+
headerSecondaryText?: string;
|
|
39
|
+
headerIcon?: string;
|
|
40
|
+
closeButton?: string;
|
|
41
|
+
receivedBubble?: string;
|
|
42
|
+
receivedText?: string;
|
|
43
|
+
receivedTimestamp?: string;
|
|
44
|
+
sentBubble?: string;
|
|
45
|
+
sentText?: string;
|
|
46
|
+
sentTimestamp?: string;
|
|
47
|
+
systemMessageText?: string;
|
|
48
|
+
daySeparatorBackground?: string;
|
|
49
|
+
daySeparatorText?: string;
|
|
50
|
+
footerContainer?: string;
|
|
51
|
+
chatInputBackground?: string;
|
|
52
|
+
chatInputText?: string;
|
|
53
|
+
chatInputPlaceholder?: string;
|
|
54
|
+
chatInputBorder?: string;
|
|
55
|
+
sendButtonBackground?: string;
|
|
56
|
+
sendButtonIcon?: string;
|
|
57
|
+
attachmentButton?: string;
|
|
58
|
+
unreadBadgeBackground?: string;
|
|
59
|
+
unreadBadgeText?: string;
|
|
17
60
|
}
|
|
18
61
|
export interface ChatUser {
|
|
19
62
|
customerName: string;
|
|
20
63
|
customerEmail?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Your reference for this customer. Sent for agent context but NOT trusted
|
|
66
|
+
* as identity: an id asserted by app code cannot be verified. For a trusted
|
|
67
|
+
* identity use `customerToken`.
|
|
68
|
+
*/
|
|
21
69
|
customerId?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Chat identity token minted by YOUR backend with `createCsCustomerToken`
|
|
72
|
+
* and handed to the app. When set it is the authoritative identity: the
|
|
73
|
+
* server derives name, email and customer id from its signed claims, so a
|
|
74
|
+
* tampered app cannot impersonate another customer.
|
|
75
|
+
*/
|
|
76
|
+
customerToken?: string;
|
|
22
77
|
}
|
|
23
78
|
export type AttachmentSourceType = 'auto' | 'base64' | 'dataUri' | 'file' | 'contentUri' | 'url';
|
|
24
79
|
/**
|
|
@@ -101,9 +156,54 @@ export interface ChatMessage {
|
|
|
101
156
|
totalMessages?: number;
|
|
102
157
|
}
|
|
103
158
|
export type NewinstanceChatErrorType = 'network' | 'validation' | 'auth' | 'system';
|
|
159
|
+
/**
|
|
160
|
+
* Stable, cross-platform diagnostic codes. The same strings are emitted by the
|
|
161
|
+
* web, Android, iOS and Flutter SDKs, so `code` is the value to branch on and
|
|
162
|
+
* to quote in a support request.
|
|
163
|
+
*/
|
|
164
|
+
export type NewinstanceChatErrorCode =
|
|
165
|
+
/** The API key was rejected: wrong key, wrong environment, revoked, or expired. */
|
|
166
|
+
'INVALID_PUBLIC_KEY'
|
|
167
|
+
/** No API key was supplied. */
|
|
168
|
+
| 'MISSING_WIDGET_KEY'
|
|
169
|
+
/** The key is valid but no chat configuration exists for the organization. */
|
|
170
|
+
| 'CHAT_CONFIG_UNAVAILABLE'
|
|
171
|
+
/** The key and config are fine, but chat is switched off in the dashboard. */
|
|
172
|
+
| 'CHAT_DISABLED'
|
|
173
|
+
/** Remote configuration could not be fetched; the built-in theme is in use. */
|
|
174
|
+
| 'CONFIG_FETCH_FAILED'
|
|
175
|
+
/** The chat identity token was malformed, expired, or signed for another organization. */
|
|
176
|
+
| 'INVALID_IDENTITY_TOKEN'
|
|
177
|
+
/** A request could not reach the backend at all. */
|
|
178
|
+
| 'NETWORK_ERROR'
|
|
179
|
+
/** The realtime transport dropped and could not be re-established. */
|
|
180
|
+
| 'TRANSPORT_ERROR'
|
|
181
|
+
/** Starting a conversation failed. */
|
|
182
|
+
| 'CHAT_INITIALIZATION_FAILED'
|
|
183
|
+
/** A message could not be delivered. */
|
|
184
|
+
| 'MESSAGE_SEND_FAILED'
|
|
185
|
+
/** An attachment could not be uploaded. */
|
|
186
|
+
| 'ATTACHMENT_FAILED'
|
|
187
|
+
/** The backend answered, but not with anything the SDK could use. */
|
|
188
|
+
| 'SERVER_ERROR';
|
|
189
|
+
/**
|
|
190
|
+
* Delivered on the `error` event. This is the channel for "why is my chat not
|
|
191
|
+
* working": it is never rendered inside the chat interface, and it never
|
|
192
|
+
* carries the API key, the identity token, or customer personal data.
|
|
193
|
+
*/
|
|
104
194
|
export interface NewinstanceChatError {
|
|
195
|
+
/** Stable code to branch on. Undefined only from SDK versions older than 0.3.0. */
|
|
196
|
+
code?: NewinstanceChatErrorCode;
|
|
197
|
+
/** Broad category, kept for backwards compatibility with 0.2.x handlers. */
|
|
105
198
|
type: NewinstanceChatErrorType;
|
|
199
|
+
/** Safe to log and to show a developer. Not written for end users. */
|
|
106
200
|
message: string;
|
|
201
|
+
/**
|
|
202
|
+
* Extra detail for developers, when the SDK had any that was safe to
|
|
203
|
+
* expose. Never a raw server response body.
|
|
204
|
+
*/
|
|
205
|
+
developerMessage?: string;
|
|
206
|
+
/** False when the SDK has given up until the host fixes something. */
|
|
107
207
|
recoverable: boolean;
|
|
108
208
|
}
|
|
109
209
|
/** Native event names. Subscribe with `sdk.addListener(event, handler)`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,qBAAqB;IACpC,qFAAqF;IACrF,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yGAAyG;IACzG,SAAS,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACzB,iEAAiE;IACjE,cAAc,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-newinstance-chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "New instance LiveAndAiChat React Native SDK \u2014 AI + live-agent chat, drop-in native chat screen for iOS and Android.",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
package/src/index.tsx
CHANGED
|
@@ -15,13 +15,17 @@ import type {
|
|
|
15
15
|
|
|
16
16
|
export type {
|
|
17
17
|
AttachmentInput,
|
|
18
|
+
AttachmentUpdate,
|
|
19
|
+
ChatClosedEvent,
|
|
18
20
|
ChatMessage,
|
|
21
|
+
ChatThemeOverride,
|
|
19
22
|
ChatUser,
|
|
20
23
|
ConnectionState,
|
|
21
24
|
EventMap,
|
|
22
25
|
EventName,
|
|
23
26
|
NewinstanceChatConfig,
|
|
24
27
|
NewinstanceChatError,
|
|
28
|
+
NewinstanceChatErrorCode,
|
|
25
29
|
NewinstanceChatErrorType,
|
|
26
30
|
} from './types';
|
|
27
31
|
|
|
@@ -54,11 +58,24 @@ export class NewinstanceChat {
|
|
|
54
58
|
* Identify the customer. Safe to call before or after `initialize()`. If
|
|
55
59
|
* called before `configure()` resolves, the user is queued and applied
|
|
56
60
|
* once the native instance exists.
|
|
61
|
+
*
|
|
62
|
+
* Prefer `customerToken`: it is minted by your backend, so the server can
|
|
63
|
+
* verify who the customer is. `customerName` / `customerEmail` /
|
|
64
|
+
* `customerId` alone are client-asserted and are not trusted as identity.
|
|
57
65
|
*/
|
|
58
66
|
setUser(user: ChatUser): void {
|
|
59
67
|
NativeNewinstanceChat.setUser(user);
|
|
60
68
|
}
|
|
61
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Identify the customer with a backend-minted chat identity token only.
|
|
72
|
+
* Nothing else needs to be supplied: the server derives the name, email and
|
|
73
|
+
* customer id from the token's signed claims.
|
|
74
|
+
*/
|
|
75
|
+
setUserToken(customerToken: string): void {
|
|
76
|
+
NativeNewinstanceChat.setUser({ customerName: 'Customer', customerToken });
|
|
77
|
+
}
|
|
78
|
+
|
|
62
79
|
/**
|
|
63
80
|
* Fetch org config, restore the saved conversation, and connect the
|
|
64
81
|
* subscription transport in the background. Concurrent callers share
|
package/src/types.ts
CHANGED
|
@@ -15,12 +15,68 @@ export interface NewinstanceChatConfig {
|
|
|
15
15
|
transport?: 'sse' | 'ws';
|
|
16
16
|
/** Optional message pre-seeded as the first outbound message. */
|
|
17
17
|
initialMessage?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Local theme. Ranked BELOW whatever the merchant configured in the
|
|
20
|
+
* dashboard and ABOVE the SDK's built-in palette, merged per property, so a
|
|
21
|
+
* token you set here applies only where the dashboard did not set one.
|
|
22
|
+
*/
|
|
23
|
+
theme?: ChatThemeOverride;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Local theme tokens. Every field is optional; colours are hex strings
|
|
28
|
+
* (`#RRGGBB` or `#AARRGGBB`). An unparseable value is ignored rather than
|
|
29
|
+
* throwing, so a bad colour can never crash the app.
|
|
30
|
+
*/
|
|
31
|
+
export interface ChatThemeOverride {
|
|
32
|
+
/**
|
|
33
|
+
* Force light or dark. Omit for "no opinion": the dashboard's mode wins if
|
|
34
|
+
* it set one, otherwise the device setting.
|
|
35
|
+
*/
|
|
36
|
+
mode?: 'light' | 'dark';
|
|
37
|
+
chatBackground?: string;
|
|
38
|
+
headerBackground?: string;
|
|
39
|
+
headerPrimaryText?: string;
|
|
40
|
+
headerSecondaryText?: string;
|
|
41
|
+
headerIcon?: string;
|
|
42
|
+
closeButton?: string;
|
|
43
|
+
receivedBubble?: string;
|
|
44
|
+
receivedText?: string;
|
|
45
|
+
receivedTimestamp?: string;
|
|
46
|
+
sentBubble?: string;
|
|
47
|
+
sentText?: string;
|
|
48
|
+
sentTimestamp?: string;
|
|
49
|
+
systemMessageText?: string;
|
|
50
|
+
daySeparatorBackground?: string;
|
|
51
|
+
daySeparatorText?: string;
|
|
52
|
+
footerContainer?: string;
|
|
53
|
+
chatInputBackground?: string;
|
|
54
|
+
chatInputText?: string;
|
|
55
|
+
chatInputPlaceholder?: string;
|
|
56
|
+
chatInputBorder?: string;
|
|
57
|
+
sendButtonBackground?: string;
|
|
58
|
+
sendButtonIcon?: string;
|
|
59
|
+
attachmentButton?: string;
|
|
60
|
+
unreadBadgeBackground?: string;
|
|
61
|
+
unreadBadgeText?: string;
|
|
18
62
|
}
|
|
19
63
|
|
|
20
64
|
export interface ChatUser {
|
|
21
65
|
customerName: string;
|
|
22
66
|
customerEmail?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Your reference for this customer. Sent for agent context but NOT trusted
|
|
69
|
+
* as identity: an id asserted by app code cannot be verified. For a trusted
|
|
70
|
+
* identity use `customerToken`.
|
|
71
|
+
*/
|
|
23
72
|
customerId?: string;
|
|
73
|
+
/**
|
|
74
|
+
* Chat identity token minted by YOUR backend with `createCsCustomerToken`
|
|
75
|
+
* and handed to the app. When set it is the authoritative identity: the
|
|
76
|
+
* server derives name, email and customer id from its signed claims, so a
|
|
77
|
+
* tampered app cannot impersonate another customer.
|
|
78
|
+
*/
|
|
79
|
+
customerToken?: string;
|
|
24
80
|
}
|
|
25
81
|
|
|
26
82
|
export type AttachmentSourceType =
|
|
@@ -139,9 +195,55 @@ export type NewinstanceChatErrorType =
|
|
|
139
195
|
| 'auth'
|
|
140
196
|
| 'system';
|
|
141
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Stable, cross-platform diagnostic codes. The same strings are emitted by the
|
|
200
|
+
* web, Android, iOS and Flutter SDKs, so `code` is the value to branch on and
|
|
201
|
+
* to quote in a support request.
|
|
202
|
+
*/
|
|
203
|
+
export type NewinstanceChatErrorCode =
|
|
204
|
+
/** The API key was rejected: wrong key, wrong environment, revoked, or expired. */
|
|
205
|
+
| 'INVALID_PUBLIC_KEY'
|
|
206
|
+
/** No API key was supplied. */
|
|
207
|
+
| 'MISSING_WIDGET_KEY'
|
|
208
|
+
/** The key is valid but no chat configuration exists for the organization. */
|
|
209
|
+
| 'CHAT_CONFIG_UNAVAILABLE'
|
|
210
|
+
/** The key and config are fine, but chat is switched off in the dashboard. */
|
|
211
|
+
| 'CHAT_DISABLED'
|
|
212
|
+
/** Remote configuration could not be fetched; the built-in theme is in use. */
|
|
213
|
+
| 'CONFIG_FETCH_FAILED'
|
|
214
|
+
/** The chat identity token was malformed, expired, or signed for another organization. */
|
|
215
|
+
| 'INVALID_IDENTITY_TOKEN'
|
|
216
|
+
/** A request could not reach the backend at all. */
|
|
217
|
+
| 'NETWORK_ERROR'
|
|
218
|
+
/** The realtime transport dropped and could not be re-established. */
|
|
219
|
+
| 'TRANSPORT_ERROR'
|
|
220
|
+
/** Starting a conversation failed. */
|
|
221
|
+
| 'CHAT_INITIALIZATION_FAILED'
|
|
222
|
+
/** A message could not be delivered. */
|
|
223
|
+
| 'MESSAGE_SEND_FAILED'
|
|
224
|
+
/** An attachment could not be uploaded. */
|
|
225
|
+
| 'ATTACHMENT_FAILED'
|
|
226
|
+
/** The backend answered, but not with anything the SDK could use. */
|
|
227
|
+
| 'SERVER_ERROR';
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Delivered on the `error` event. This is the channel for "why is my chat not
|
|
231
|
+
* working": it is never rendered inside the chat interface, and it never
|
|
232
|
+
* carries the API key, the identity token, or customer personal data.
|
|
233
|
+
*/
|
|
142
234
|
export interface NewinstanceChatError {
|
|
235
|
+
/** Stable code to branch on. Undefined only from SDK versions older than 0.3.0. */
|
|
236
|
+
code?: NewinstanceChatErrorCode;
|
|
237
|
+
/** Broad category, kept for backwards compatibility with 0.2.x handlers. */
|
|
143
238
|
type: NewinstanceChatErrorType;
|
|
239
|
+
/** Safe to log and to show a developer. Not written for end users. */
|
|
144
240
|
message: string;
|
|
241
|
+
/**
|
|
242
|
+
* Extra detail for developers, when the SDK had any that was safe to
|
|
243
|
+
* expose. Never a raw server response body.
|
|
244
|
+
*/
|
|
245
|
+
developerMessage?: string;
|
|
246
|
+
/** False when the SDK has given up until the host fixes something. */
|
|
145
247
|
recoverable: boolean;
|
|
146
248
|
}
|
|
147
249
|
|