@kindly-ai/react-native 0.1.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.
Files changed (63) hide show
  1. package/KindlyReactNative.podspec +36 -0
  2. package/LICENSE +20 -0
  3. package/README.md +127 -0
  4. package/android/build.gradle +113 -0
  5. package/android/maven-repo/ai/kindly/sdk/1.0.93/sdk-1.0.93.aar +0 -0
  6. package/android/maven-repo/ai/kindly/sdk/1.0.93/sdk-1.0.93.pom +125 -0
  7. package/android/src/main/AndroidManifest.xml +2 -0
  8. package/android/src/main/java/com/kindlyai/reactnative/KindlyReactNativeModule.kt +445 -0
  9. package/android/src/main/java/com/kindlyai/reactnative/KindlyReactNativePackage.kt +38 -0
  10. package/ios/Frameworks/Kindly.xcframework/Info.plist +44 -0
  11. package/ios/Frameworks/Kindly.xcframework/_CodeSignature/CodeDirectory +0 -0
  12. package/ios/Frameworks/Kindly.xcframework/_CodeSignature/CodeRequirements +0 -0
  13. package/ios/Frameworks/Kindly.xcframework/_CodeSignature/CodeRequirements-1 +0 -0
  14. package/ios/Frameworks/Kindly.xcframework/_CodeSignature/CodeResources +578 -0
  15. package/ios/Frameworks/Kindly.xcframework/_CodeSignature/CodeSignature +0 -0
  16. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/Assets.car +0 -0
  17. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/Config.plist +0 -0
  18. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/ConfirmationWindow.nib +0 -0
  19. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/Headers/Kindly-Swift.h +331 -0
  20. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/Headers/Kindly.h +18 -0
  21. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/Info.plist +0 -0
  22. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/Kindly +0 -0
  23. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/Modules/Kindly.swiftmodule/arm64-apple-ios.abi.json +28769 -0
  24. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/Modules/Kindly.swiftmodule/arm64-apple-ios.private.swiftinterface +547 -0
  25. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/Modules/Kindly.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  26. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/Modules/Kindly.swiftmodule/arm64-apple-ios.swiftinterface +543 -0
  27. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/Modules/module.modulemap +11 -0
  28. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/PrivacyInfo.xcprivacy +83 -0
  29. package/ios/Frameworks/Kindly.xcframework/ios-arm64/Kindly.framework/_CodeSignature/CodeResources +223 -0
  30. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Assets.car +0 -0
  31. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Config.plist +0 -0
  32. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/ConfirmationWindow.nib +0 -0
  33. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Headers/Kindly-Swift.h +658 -0
  34. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Headers/Kindly.h +18 -0
  35. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Info.plist +0 -0
  36. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Kindly +0 -0
  37. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Modules/Kindly.swiftmodule/arm64-apple-ios-simulator.abi.json +28769 -0
  38. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Modules/Kindly.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +547 -0
  39. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Modules/Kindly.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  40. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Modules/Kindly.swiftmodule/arm64-apple-ios-simulator.swiftinterface +543 -0
  41. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Modules/Kindly.swiftmodule/x86_64-apple-ios-simulator.abi.json +28769 -0
  42. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Modules/Kindly.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +547 -0
  43. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Modules/Kindly.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  44. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Modules/Kindly.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +543 -0
  45. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/Modules/module.modulemap +11 -0
  46. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/PrivacyInfo.xcprivacy +83 -0
  47. package/ios/Frameworks/Kindly.xcframework/ios-arm64_x86_64-simulator/Kindly.framework/_CodeSignature/CodeResources +267 -0
  48. package/ios/KindlyReactNative.h +18 -0
  49. package/ios/KindlyReactNative.mm +234 -0
  50. package/ios/KindlyReactNativeImpl.swift +410 -0
  51. package/lib/module/NativeKindlyReactNative.js +22 -0
  52. package/lib/module/NativeKindlyReactNative.js.map +1 -0
  53. package/lib/module/index.js +280 -0
  54. package/lib/module/index.js.map +1 -0
  55. package/lib/module/package.json +1 -0
  56. package/lib/typescript/package.json +1 -0
  57. package/lib/typescript/src/NativeKindlyReactNative.d.ts +47 -0
  58. package/lib/typescript/src/NativeKindlyReactNative.d.ts.map +1 -0
  59. package/lib/typescript/src/index.d.ts +150 -0
  60. package/lib/typescript/src/index.d.ts.map +1 -0
  61. package/package.json +121 -0
  62. package/src/NativeKindlyReactNative.ts +80 -0
  63. package/src/index.tsx +353 -0
@@ -0,0 +1,80 @@
1
+ // TurboModule spec for the @kindly-ai/react-native package.
2
+ //
3
+ // Codegen INPUT — `react-native` reads this at build time and generates the
4
+ // abstract Spec class on iOS (Obj-C++ header) and Android (Kotlin abstract
5
+ // class). The native module classes extend those.
6
+ //
7
+ // Convention used here: every method takes flat primitive parameters and
8
+ // returns either a primitive or a Promise. We deliberately avoid nested
9
+ // struct args (`(args: { ... })`) because codegen generates JS::Native*Args
10
+ // C++ structs for those, which add fragility without buying anything for
11
+ // our use case. This matches the scaffolded `multiply()` example pattern.
12
+ //
13
+ // Filename MUST match `Native<ModuleName>.ts`. ModuleName here is
14
+ // `KindlyReactNative` — this becomes the native module name returned by
15
+ // `getName()` and the registry key. Customer-facing imports come from the
16
+ // package, not the module name.
17
+ import type { TurboModule } from 'react-native';
18
+ import { TurboModuleRegistry } from 'react-native';
19
+
20
+ export interface Spec extends TurboModule {
21
+ // Lifecycle
22
+ start(botKey: string, languageCode: string | null, hasAuthCallback: boolean): void;
23
+ displayChat(languageCode: string | null, triggerDialogueId: string | null): void;
24
+ launchChat(triggerDialogueId: string | null): void;
25
+ closeChat(): void;
26
+ endChat(): Promise<void>;
27
+ kill(): Promise<void>;
28
+ setLanguage(languageCode: string): Promise<void>;
29
+
30
+ // Messaging — newContext map shape: { [key: string]: string }
31
+ sendMessage(
32
+ message: string,
33
+ newContext: { [key: string]: string } | null
34
+ ): Promise<{ [key: string]: unknown } | null>;
35
+ setNewContext(context: { [key: string]: string }): void;
36
+ clearNewContext(): void;
37
+ triggerDialogue(dialogueId: string): void;
38
+ clearTriggerDialogue(): void;
39
+ handleUrl(url: string): Promise<boolean>;
40
+
41
+ // Theme — colors map shape: { [key: string]: number | null }
42
+ setCustomTheme(colors: { [key: string]: number | null }): void;
43
+ clearCustomTheme(): void;
44
+
45
+ // Push
46
+ setAPNSDeviceToken(token: string): void;
47
+ saveNotificationToken(token: string): void;
48
+ handleNotification(data: { [key: string]: unknown }): void;
49
+ isKindlyNotification(data: { [key: string]: unknown }): boolean;
50
+
51
+ // State / settings
52
+ saveAuthToken(token: string): Promise<boolean>;
53
+ isChatDisplayed(): Promise<boolean>;
54
+ setVerboseLogging(enabled: boolean): void;
55
+ setCrashReporting(enabled: boolean): void;
56
+
57
+ // Round-trips for sync-style native→JS→native callbacks.
58
+ // Native fires events ('KindlyGetAuthToken', 'KindlyShouldHandle*') with
59
+ // a requestId; JS replies via these methods. Native blocks on a
60
+ // Map<requestId, Deferred> with a 5-second timeout, falling back to a
61
+ // safe default if JS is silent.
62
+ respondToAuthToken(requestId: string, token: string | null): void;
63
+ respondToShouldHandle(requestId: string, value: boolean): void;
64
+
65
+ // Delegate gating — flips on/off the bridge-level routing for each callback.
66
+ setDelegate(
67
+ onButtonPressed: boolean,
68
+ shouldHandleLink: boolean,
69
+ shouldHandleNotification: boolean,
70
+ onHandover: boolean
71
+ ): void;
72
+ callHandover(): void;
73
+
74
+ // RN bridge bookkeeping — required when the module emits events (iOS only
75
+ // looks at this; on Android RCTDeviceEventEmitter manages itself).
76
+ addListener(eventName: string): void;
77
+ removeListeners(count: number): void;
78
+ }
79
+
80
+ export default TurboModuleRegistry.getEnforcing<Spec>('KindlyReactNative');
package/src/index.tsx ADDED
@@ -0,0 +1,353 @@
1
+ // Kindly Chat SDK — public React Native surface.
2
+ //
3
+ // Thin TS facade over the native TurboModule (`KindlyReactNative`). Mirrors
4
+ // the Flutter SDK's public API 1:1. Each method delegates to one or more
5
+ // methods on the spec, plus a tiny amount of bookkeeping in JS for the
6
+ // auth-token + delegate round-trips (the native side has no way to call
7
+ // JS synchronously, so we pair `*Request` events with a `respondTo*` method).
8
+ //
9
+ // Customers do `import { KindlySDK } from '@kindly-ai/react-native'`. The
10
+ // internal native-module name `KindlyReactNative` is intentionally not
11
+ // exported — it's an implementation detail.
12
+ import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
13
+ import NativeKindly from './NativeKindlyReactNative';
14
+
15
+ /** Callback invoked by the SDK when it needs a fresh JWT auth token. */
16
+ export type AuthTokenCallback = () => Promise<string | null>;
17
+
18
+ /** Callback invoked when a handover to a human agent is initiated. */
19
+ export type HandoverCallback = () => void;
20
+
21
+ /**
22
+ * Fired by the SDK when the user taps a chat button.
23
+ *
24
+ * `button` keys: `id`, `type`, `label`, `value`, `index`, `hasBeenSelected`.
25
+ * `chatLog` is the full conversation up to this point.
26
+ */
27
+ export type KindlyButtonPressedCallback = (
28
+ button: { [key: string]: unknown },
29
+ chatLog: Array<{ [key: string]: unknown }>
30
+ ) => void;
31
+
32
+ /**
33
+ * Asked by the SDK before opening a link the user tapped inside chat.
34
+ *
35
+ * Return `true` to let the SDK open it (default), or `false` to take over.
36
+ */
37
+ export type KindlyLinkInterceptCallback = (url: string) => boolean;
38
+
39
+ /**
40
+ * Asked by the SDK before presenting an incoming Kindly silent push.
41
+ *
42
+ * Return `true` to let the SDK present it (default), or `false` to take over.
43
+ */
44
+ export type KindlyNotificationInterceptCallback = (notification: {
45
+ [key: string]: unknown;
46
+ }) => boolean;
47
+
48
+ /** Typed bag of theme colors (ARGB ints — use the helpers below). */
49
+ export interface KindlyTheme {
50
+ background?: number;
51
+ botMessageBackground?: number;
52
+ botMessageText?: number;
53
+ buttonBackground?: number;
54
+ buttonOutline?: number;
55
+ buttonSelectedBackground?: number;
56
+ buttonText?: number;
57
+ defaultShadow?: number;
58
+ inputBackground?: number;
59
+ inputCursor?: number;
60
+ inputText?: number;
61
+ navBarBackground?: number;
62
+ navBarText?: number;
63
+ userMessageBackground?: number;
64
+ userMessageText?: number;
65
+ chatLogElements?: number;
66
+ maintenanceHeaderBackground?: number;
67
+ }
68
+
69
+ /**
70
+ * Convert a `#RRGGBB` or `#AARRGGBB` hex string to the ARGB int form the
71
+ * SDK expects. Equivalent to Flutter's `Color.value`.
72
+ */
73
+ export function hexColor(hex: string): number {
74
+ const cleaned = hex.replace(/^#/, '');
75
+ const v = parseInt(cleaned, 16);
76
+ if (cleaned.length === 6) {
77
+ return (0xff000000 | v) >>> 0;
78
+ }
79
+ if (cleaned.length === 8) {
80
+ return v >>> 0;
81
+ }
82
+ throw new Error(`hexColor: expected #RRGGBB or #AARRGGBB, got "${hex}"`);
83
+ }
84
+
85
+ // ────────────────────────────────────────────────────────────────────────────
86
+ // Native-event wiring for native→JS callbacks.
87
+ //
88
+ // Native fires events via RCTDeviceEventEmitter; JS attaches once on first use
89
+ // and dispatches to the registered callbacks. Sync-bool answers
90
+ // (`shouldHandleLink` / `shouldHandleNotification`) are returned via a
91
+ // `respondToShouldHandle` round-trip — native blocks on a Map<requestId,
92
+ // Deferred> with a 5s timeout, falling back to `true` if JS is slow or
93
+ // silent. Same semantics as the Flutter SDK's blocking-bool pattern.
94
+ // ────────────────────────────────────────────────────────────────────────────
95
+ const eventEmitter = new NativeEventEmitter(
96
+ Platform.OS === 'ios'
97
+ ? (NativeModules.KindlyReactNative as unknown as undefined)
98
+ : undefined
99
+ );
100
+
101
+ let authTokenCallback: AuthTokenCallback | null = null;
102
+ let handoverCallback: HandoverCallback | null = null;
103
+ let onButtonPressed: KindlyButtonPressedCallback | null = null;
104
+ let shouldHandleLink: KindlyLinkInterceptCallback | null = null;
105
+ let shouldHandleNotification: KindlyNotificationInterceptCallback | null = null;
106
+
107
+ let listenersAttached = false;
108
+
109
+ function attachListeners(): void {
110
+ if (listenersAttached) return;
111
+ listenersAttached = true;
112
+
113
+ // RN's NativeEventEmitter.addListener types its callback as
114
+ // `(...args: readonly Object[]) => unknown` — we widen each event-shape
115
+ // type inside the handler instead of trying to fight the parameter type.
116
+ eventEmitter.addListener('KindlyGetAuthToken', async (raw: unknown) => {
117
+ const event = raw as { requestId: string };
118
+ if (authTokenCallback == null) {
119
+ NativeKindly.respondToAuthToken(event.requestId, null);
120
+ return;
121
+ }
122
+ try {
123
+ const token = await authTokenCallback();
124
+ NativeKindly.respondToAuthToken(event.requestId, token);
125
+ } catch {
126
+ NativeKindly.respondToAuthToken(event.requestId, null);
127
+ }
128
+ });
129
+
130
+ eventEmitter.addListener('KindlyOnHandover', () => {
131
+ handoverCallback?.();
132
+ });
133
+
134
+ eventEmitter.addListener('KindlyOnButtonPressed', (raw: unknown) => {
135
+ const event = raw as {
136
+ button: { [key: string]: unknown };
137
+ chatLog: Array<{ [key: string]: unknown }>;
138
+ };
139
+ onButtonPressed?.(event.button, event.chatLog);
140
+ });
141
+
142
+ eventEmitter.addListener('KindlyShouldHandleLink', (raw: unknown) => {
143
+ const event = raw as { requestId: string; url: string };
144
+ const value = shouldHandleLink ? shouldHandleLink(event.url) : true;
145
+ NativeKindly.respondToShouldHandle(event.requestId, value);
146
+ });
147
+
148
+ eventEmitter.addListener(
149
+ 'KindlyShouldHandleNotification',
150
+ (raw: unknown) => {
151
+ const event = raw as {
152
+ requestId: string;
153
+ notification: { [key: string]: unknown };
154
+ };
155
+ const value = shouldHandleNotification
156
+ ? shouldHandleNotification(event.notification)
157
+ : true;
158
+ NativeKindly.respondToShouldHandle(event.requestId, value);
159
+ }
160
+ );
161
+ }
162
+
163
+ /**
164
+ * Main Kindly SDK entry point.
165
+ *
166
+ * Thin facade over the public `EntryPoint` API of the native iOS
167
+ * (`KindlyChatClient`) and Android (`ChatKindlySDK`) SDKs.
168
+ */
169
+ export class KindlySDK {
170
+ /** Initialize the SDK. Must be called before any other method. */
171
+ static start(args: {
172
+ botKey: string;
173
+ languageCode?: string;
174
+ authTokenCallback?: AuthTokenCallback;
175
+ }): void {
176
+ attachListeners();
177
+ authTokenCallback = args.authTokenCallback ?? null;
178
+ NativeKindly.start(
179
+ args.botKey,
180
+ args.languageCode ?? null,
181
+ args.authTokenCallback != null
182
+ );
183
+ }
184
+
185
+ /** Show the chat UI. */
186
+ static displayChat(
187
+ args: { languageCode?: string; triggerDialogueId?: string } = {}
188
+ ): void {
189
+ NativeKindly.displayChat(
190
+ args.languageCode ?? null,
191
+ args.triggerDialogueId ?? null
192
+ );
193
+ }
194
+
195
+ /** Connect (if needed) and show chat. Recommended on Android. */
196
+ static launchChat(args: { triggerDialogueId?: string } = {}): void {
197
+ NativeKindly.launchChat(args.triggerDialogueId ?? null);
198
+ }
199
+
200
+ /** Dismiss the chat UI without ending the session. */
201
+ static closeChat(): void {
202
+ NativeKindly.closeChat();
203
+ }
204
+
205
+ /** End the chat session: clears messages, token, dismisses UI. */
206
+ static endChat(): Promise<void> {
207
+ return NativeKindly.endChat();
208
+ }
209
+
210
+ /** Tear the SDK down completely; call start() again before reuse. */
211
+ static kill(): Promise<void> {
212
+ return NativeKindly.kill();
213
+ }
214
+
215
+ /** Update the language for the current session. */
216
+ static setLanguage(languageCode: string): Promise<void> {
217
+ return NativeKindly.setLanguage(languageCode);
218
+ }
219
+
220
+ /**
221
+ * Send a message programmatically. Returns the reconciled message map
222
+ * (id, text, created, sender, …) or rejects on failure.
223
+ */
224
+ static sendMessage(
225
+ text: string,
226
+ options?: { newContext?: { [key: string]: string } }
227
+ ): Promise<{ [key: string]: unknown } | null> {
228
+ return NativeKindly.sendMessage(text, options?.newContext ?? null);
229
+ }
230
+
231
+ /** Apply a custom theme. Pass undefined fields to keep the default. */
232
+ static setCustomTheme(theme: KindlyTheme): void {
233
+ const colors: { [key: string]: number | null } = {};
234
+ (Object.keys(theme) as Array<keyof KindlyTheme>).forEach((k) => {
235
+ colors[k] = theme[k] ?? null;
236
+ });
237
+ NativeKindly.setCustomTheme(colors);
238
+ }
239
+
240
+ /** Clear custom theme; revert to default / API-supplied theme. */
241
+ static clearCustomTheme(): void {
242
+ NativeKindly.clearCustomTheme();
243
+ }
244
+
245
+ /** Stage context attached to the next message or button click. */
246
+ static setNewContext(context: { [key: string]: string }): void {
247
+ NativeKindly.setNewContext(context);
248
+ }
249
+
250
+ /** Clear any context staged via setNewContext. */
251
+ static clearNewContext(): void {
252
+ NativeKindly.clearNewContext();
253
+ }
254
+
255
+ /** Save a JWT auth token (iOS keychain). On Android always returns true. */
256
+ static saveAuthToken(token: string): Promise<boolean> {
257
+ return NativeKindly.saveAuthToken(token);
258
+ }
259
+
260
+ /** Register the APNS device token. iOS only — no-op on Android. */
261
+ static setAPNSDeviceToken(token: string): void {
262
+ if (Platform.OS === 'ios') {
263
+ NativeKindly.setAPNSDeviceToken(token);
264
+ }
265
+ }
266
+
267
+ /** Register the FCM token. Android only — no-op on iOS. */
268
+ static saveNotificationToken(token: string): void {
269
+ if (Platform.OS === 'android') {
270
+ NativeKindly.saveNotificationToken(token);
271
+ }
272
+ }
273
+
274
+ /** Forward an incoming push notification to the SDK. */
275
+ static handleNotification(data: { [key: string]: unknown }): void {
276
+ NativeKindly.handleNotification(data);
277
+ }
278
+
279
+ /** Returns true if the given push payload originated from Kindly. */
280
+ static isKindlyNotification(data: { [key: string]: unknown }): boolean {
281
+ return NativeKindly.isKindlyNotification(data);
282
+ }
283
+
284
+ /** Trigger a specific dialogue by id. The SDK must be connected. */
285
+ static triggerDialogue(dialogueId: string): void {
286
+ NativeKindly.triggerDialogue(dialogueId);
287
+ }
288
+
289
+ /** Clear any pending trigger-dialogue request (Android only). */
290
+ static clearTriggerDialogue(): void {
291
+ NativeKindly.clearTriggerDialogue();
292
+ }
293
+
294
+ /** Handle a Kindly deep-link URL (e.g. `kindly://chat/dialogue/{id}`). */
295
+ static handleUrl(url: string): Promise<boolean> {
296
+ return NativeKindly.handleUrl(url);
297
+ }
298
+
299
+ /** Initiate a handover to a human agent. */
300
+ static callHandover(callback: HandoverCallback): void {
301
+ attachListeners();
302
+ handoverCallback = callback;
303
+ NativeKindly.callHandover();
304
+ }
305
+
306
+ /** Whether the chat UI is currently displayed (iOS only — Android always false). */
307
+ static isChatDisplayed(): Promise<boolean> {
308
+ return NativeKindly.isChatDisplayed();
309
+ }
310
+
311
+ /** Toggle verbose SDK logging. */
312
+ static setVerboseLogging(enabled: boolean): void {
313
+ NativeKindly.setVerboseLogging(enabled);
314
+ }
315
+
316
+ /** Toggle Sentry crash reporting from inside the SDK. */
317
+ static setCrashReporting(enabled: boolean): void {
318
+ NativeKindly.setCrashReporting(enabled);
319
+ }
320
+
321
+ /**
322
+ * Register host-app callbacks for chat-button presses, link interception,
323
+ * and notification interception. Mirrors the native delegate protocols.
324
+ *
325
+ * `shouldHandleLink` / `shouldHandleNotification` have a 5-second native
326
+ * timeout — return quickly. After timeout the SDK falls back to its
327
+ * default `true` so the UI doesn't hang on a slow JS callback.
328
+ */
329
+ static setDelegate(args: {
330
+ onButtonPressed?: KindlyButtonPressedCallback;
331
+ shouldHandleLink?: KindlyLinkInterceptCallback;
332
+ shouldHandleNotification?: KindlyNotificationInterceptCallback;
333
+ }): void {
334
+ attachListeners();
335
+ onButtonPressed = args.onButtonPressed ?? null;
336
+ shouldHandleLink = args.shouldHandleLink ?? null;
337
+ shouldHandleNotification = args.shouldHandleNotification ?? null;
338
+ NativeKindly.setDelegate(
339
+ onButtonPressed != null,
340
+ shouldHandleLink != null,
341
+ shouldHandleNotification != null,
342
+ handoverCallback != null
343
+ );
344
+ }
345
+
346
+ /** Clear all delegate callbacks set via setDelegate. */
347
+ static clearDelegate(): void {
348
+ onButtonPressed = null;
349
+ shouldHandleLink = null;
350
+ shouldHandleNotification = null;
351
+ NativeKindly.setDelegate(false, false, false, handoverCallback != null);
352
+ }
353
+ }