@sagepilot-ai/react-native-sdk 0.2.3 → 0.2.4
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 +24 -1
- package/dist/index.d.mts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +101 -6
- package/dist/index.mjs +101 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -313,12 +313,34 @@ SagepilotChat.present();
|
|
|
313
313
|
SagepilotChat.presentMessages();
|
|
314
314
|
SagepilotChat.presentMessageComposer("I need help with my order");
|
|
315
315
|
SagepilotChat.presentMessageComposer("Start a new request", { mode: "new" });
|
|
316
|
+
SagepilotChat.presentMessageComposer("I need help with this order", { chatId: savedChatId });
|
|
316
317
|
```
|
|
317
318
|
|
|
318
319
|
`presentMessageComposer(message)` pre-fills the composer and lets Sagepilot reuse an existing conversation when one is available. If there is no existing conversation, Sagepilot starts a new one when the customer sends the message.
|
|
319
320
|
|
|
320
321
|
Use `{ mode: "new" }` only when the button or workflow should always start a fresh conversation.
|
|
321
322
|
|
|
323
|
+
Pass `{ chatId }` when an app-owned surface should reopen a specific conversation, such as an order help button. The SDK sends this as the hosted widget `chat_id` and keeps the existing no-`chatId` behavior unchanged.
|
|
324
|
+
|
|
325
|
+
To store the chat id when a customer creates a conversation from a screen-specific composer:
|
|
326
|
+
|
|
327
|
+
```ts
|
|
328
|
+
SagepilotChat.presentMessageComposer("I need help with this order", {
|
|
329
|
+
metadata: { orderId: "10212984" },
|
|
330
|
+
onConversationCreated: ({ chat_id, metadata }) => {
|
|
331
|
+
// Store metadata.orderId -> chat_id in your app.
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
You can also subscribe globally:
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
const unsubscribe = SagepilotChat.onConversationCreated(({ chat_id }) => {
|
|
340
|
+
// Persist chat_id for later use.
|
|
341
|
+
});
|
|
342
|
+
```
|
|
343
|
+
|
|
322
344
|
## Identity
|
|
323
345
|
|
|
324
346
|
Call `identify()` when you know the signed-in app user.
|
|
@@ -380,11 +402,12 @@ await SagepilotChat.destroy();
|
|
|
380
402
|
|
|
381
403
|
- `SagepilotChat.present()`: opens the hosted chat home screen.
|
|
382
404
|
- `SagepilotChat.presentMessages()`: opens the hosted conversations/messages screen.
|
|
383
|
-
- `SagepilotChat.presentMessageComposer(message?, options?)`: opens the message composer and optionally pre-fills the composer text. By default, Sagepilot reuses an existing conversation when one is available. Pass `{ mode: "new" }` to force a fresh conversation. It does not auto-send.
|
|
405
|
+
- `SagepilotChat.presentMessageComposer(message?, options?)`: opens the message composer and optionally pre-fills the composer text. By default, Sagepilot reuses an existing conversation when one is available. Pass `{ mode: "new" }` to force a fresh conversation, or `{ chatId }` to open a specific conversation. It does not auto-send.
|
|
384
406
|
- `SagepilotChat.dismiss()`: closes the hosted chat modal.
|
|
385
407
|
- `SagepilotChat.hide()`: alias for `dismiss()`.
|
|
386
408
|
- `SagepilotChat.toggle()`: opens the chat when closed and closes it when open.
|
|
387
409
|
- `SagepilotChat.isPresented()`: returns whether the hosted chat modal is open.
|
|
410
|
+
- `SagepilotChat.onConversationCreated(callback)`: subscribes to hosted conversations created from the React Native widget and returns `chat_id` plus any composer metadata.
|
|
388
411
|
- `SagepilotChatProvider`: renders the hosted Sagepilot chat inside a React Native modal WebView.
|
|
389
412
|
|
|
390
413
|
When `SagepilotChatProvider` is mounted, the SDK preloads a hidden hosted WebView after `configure()` so the first visible open can reuse warmed network/cache state. Disable this with `behavior.preloadWebView: false`.
|
package/dist/index.d.mts
CHANGED
|
@@ -217,6 +217,16 @@ type SagepilotMobileState = SagepilotLifecycleState & {
|
|
|
217
217
|
};
|
|
218
218
|
type SagepilotMobileSubscription = () => void;
|
|
219
219
|
type SagepilotMessageComposerMode = "auto" | "new";
|
|
220
|
+
type SagepilotConversationCreatedEvent = {
|
|
221
|
+
chat_id: string;
|
|
222
|
+
workspace_id?: string;
|
|
223
|
+
channel_id?: string;
|
|
224
|
+
session_id?: string;
|
|
225
|
+
customer_id?: string;
|
|
226
|
+
message_id?: string;
|
|
227
|
+
created_at?: string;
|
|
228
|
+
metadata?: Record<string, unknown>;
|
|
229
|
+
};
|
|
220
230
|
type SagepilotMessageComposerOptions = {
|
|
221
231
|
/**
|
|
222
232
|
* auto: prefill the composer and let the hosted widget reuse an existing
|
|
@@ -224,6 +234,20 @@ type SagepilotMessageComposerOptions = {
|
|
|
224
234
|
* new: force the hosted widget to start a fresh conversation.
|
|
225
235
|
*/
|
|
226
236
|
mode?: SagepilotMessageComposerMode;
|
|
237
|
+
/**
|
|
238
|
+
* Opens a specific hosted conversation. This value is treated as an opaque
|
|
239
|
+
* conversation handle and is verified by the hosted customer session.
|
|
240
|
+
*/
|
|
241
|
+
chatId?: string;
|
|
242
|
+
/**
|
|
243
|
+
* App-owned metadata returned to the conversation-created callback so callers
|
|
244
|
+
* can persist mappings such as order_id -> chat_id.
|
|
245
|
+
*/
|
|
246
|
+
metadata?: Record<string, unknown>;
|
|
247
|
+
/**
|
|
248
|
+
* Fires when this composer invocation creates a new conversation.
|
|
249
|
+
*/
|
|
250
|
+
onConversationCreated?: (event: SagepilotConversationCreatedEvent) => void;
|
|
227
251
|
};
|
|
228
252
|
type SagepilotChatHookState = {
|
|
229
253
|
configured: boolean;
|
|
@@ -240,6 +264,7 @@ type SagepilotChatHookState = {
|
|
|
240
264
|
identify: (identity: SagepilotIdentity) => Promise<SagepilotIdentifyResult>;
|
|
241
265
|
logout: () => Promise<SagepilotLogoutResponse>;
|
|
242
266
|
getUnreadCount: () => Promise<number>;
|
|
267
|
+
onConversationCreated: (callback: (event: SagepilotConversationCreatedEvent) => void) => SagepilotMobileSubscription;
|
|
243
268
|
};
|
|
244
269
|
type SagepilotChatProviderProps = {
|
|
245
270
|
children?: ReactNode;
|
|
@@ -259,6 +284,7 @@ declare const SagepilotChat: {
|
|
|
259
284
|
pending: boolean;
|
|
260
285
|
};
|
|
261
286
|
onIdentify: (callback: Callback<SagepilotIdentifyResult>) => SagepilotMobileSubscription;
|
|
287
|
+
onConversationCreated: (callback: Callback<SagepilotConversationCreatedEvent>) => SagepilotMobileSubscription;
|
|
262
288
|
getUnreadCount: () => Promise<number>;
|
|
263
289
|
onUnreadChange: (callback: Callback<SagepilotUnreadState>) => SagepilotMobileSubscription;
|
|
264
290
|
startUnreadPolling: (intervalMs?: number) => () => void;
|
|
@@ -316,4 +342,4 @@ declare function SagepilotChatProvider({ children, closeLabel, loadingLabel }: S
|
|
|
316
342
|
|
|
317
343
|
declare function useSagepilotChat(): SagepilotChatHookState;
|
|
318
344
|
|
|
319
|
-
export { type SagepilotBiometricsAdapter, type SagepilotBootstrapChannelResponse, type SagepilotCacheStorage, SagepilotChat, SagepilotChatError, type SagepilotChatErrorCode, type SagepilotChatHookState, SagepilotChatProvider, type SagepilotChatProviderProps, type SagepilotDeviceInfo, type SagepilotDeviceInfoAdapter, type SagepilotIdentifyResult, type SagepilotIdentity, type SagepilotIdentityState, type SagepilotLifecycleState, type SagepilotLogoutResponse, type SagepilotMobileBehaviorConfig, type SagepilotMobileColorScheme, type SagepilotMobileConfig, type SagepilotMobileConfigureResult, type SagepilotMobileLauncherConfig, type SagepilotMobilePresentationConfig, type SagepilotMobilePresentationStyle, type SagepilotMobileResolvedLauncherConfig, type SagepilotMobileState, type SagepilotMobileSubscription, type SagepilotMobileThemeConfig, type SagepilotMobileThemeState, type SagepilotSessionState, type SagepilotTokenStorage, type SagepilotUnreadState, createAsyncStorageCacheStorage, createKeychainTokenStorage, useSagepilotChat };
|
|
345
|
+
export { type SagepilotBiometricsAdapter, type SagepilotBootstrapChannelResponse, type SagepilotCacheStorage, SagepilotChat, SagepilotChatError, type SagepilotChatErrorCode, type SagepilotChatHookState, SagepilotChatProvider, type SagepilotChatProviderProps, type SagepilotConversationCreatedEvent, type SagepilotDeviceInfo, type SagepilotDeviceInfoAdapter, type SagepilotIdentifyResult, type SagepilotIdentity, type SagepilotIdentityState, type SagepilotLifecycleState, type SagepilotLogoutResponse, type SagepilotMessageComposerOptions, type SagepilotMobileBehaviorConfig, type SagepilotMobileColorScheme, type SagepilotMobileConfig, type SagepilotMobileConfigureResult, type SagepilotMobileLauncherConfig, type SagepilotMobilePresentationConfig, type SagepilotMobilePresentationStyle, type SagepilotMobileResolvedLauncherConfig, type SagepilotMobileState, type SagepilotMobileSubscription, type SagepilotMobileThemeConfig, type SagepilotMobileThemeState, type SagepilotSessionState, type SagepilotTokenStorage, type SagepilotUnreadState, createAsyncStorageCacheStorage, createKeychainTokenStorage, useSagepilotChat };
|
package/dist/index.d.ts
CHANGED
|
@@ -217,6 +217,16 @@ type SagepilotMobileState = SagepilotLifecycleState & {
|
|
|
217
217
|
};
|
|
218
218
|
type SagepilotMobileSubscription = () => void;
|
|
219
219
|
type SagepilotMessageComposerMode = "auto" | "new";
|
|
220
|
+
type SagepilotConversationCreatedEvent = {
|
|
221
|
+
chat_id: string;
|
|
222
|
+
workspace_id?: string;
|
|
223
|
+
channel_id?: string;
|
|
224
|
+
session_id?: string;
|
|
225
|
+
customer_id?: string;
|
|
226
|
+
message_id?: string;
|
|
227
|
+
created_at?: string;
|
|
228
|
+
metadata?: Record<string, unknown>;
|
|
229
|
+
};
|
|
220
230
|
type SagepilotMessageComposerOptions = {
|
|
221
231
|
/**
|
|
222
232
|
* auto: prefill the composer and let the hosted widget reuse an existing
|
|
@@ -224,6 +234,20 @@ type SagepilotMessageComposerOptions = {
|
|
|
224
234
|
* new: force the hosted widget to start a fresh conversation.
|
|
225
235
|
*/
|
|
226
236
|
mode?: SagepilotMessageComposerMode;
|
|
237
|
+
/**
|
|
238
|
+
* Opens a specific hosted conversation. This value is treated as an opaque
|
|
239
|
+
* conversation handle and is verified by the hosted customer session.
|
|
240
|
+
*/
|
|
241
|
+
chatId?: string;
|
|
242
|
+
/**
|
|
243
|
+
* App-owned metadata returned to the conversation-created callback so callers
|
|
244
|
+
* can persist mappings such as order_id -> chat_id.
|
|
245
|
+
*/
|
|
246
|
+
metadata?: Record<string, unknown>;
|
|
247
|
+
/**
|
|
248
|
+
* Fires when this composer invocation creates a new conversation.
|
|
249
|
+
*/
|
|
250
|
+
onConversationCreated?: (event: SagepilotConversationCreatedEvent) => void;
|
|
227
251
|
};
|
|
228
252
|
type SagepilotChatHookState = {
|
|
229
253
|
configured: boolean;
|
|
@@ -240,6 +264,7 @@ type SagepilotChatHookState = {
|
|
|
240
264
|
identify: (identity: SagepilotIdentity) => Promise<SagepilotIdentifyResult>;
|
|
241
265
|
logout: () => Promise<SagepilotLogoutResponse>;
|
|
242
266
|
getUnreadCount: () => Promise<number>;
|
|
267
|
+
onConversationCreated: (callback: (event: SagepilotConversationCreatedEvent) => void) => SagepilotMobileSubscription;
|
|
243
268
|
};
|
|
244
269
|
type SagepilotChatProviderProps = {
|
|
245
270
|
children?: ReactNode;
|
|
@@ -259,6 +284,7 @@ declare const SagepilotChat: {
|
|
|
259
284
|
pending: boolean;
|
|
260
285
|
};
|
|
261
286
|
onIdentify: (callback: Callback<SagepilotIdentifyResult>) => SagepilotMobileSubscription;
|
|
287
|
+
onConversationCreated: (callback: Callback<SagepilotConversationCreatedEvent>) => SagepilotMobileSubscription;
|
|
262
288
|
getUnreadCount: () => Promise<number>;
|
|
263
289
|
onUnreadChange: (callback: Callback<SagepilotUnreadState>) => SagepilotMobileSubscription;
|
|
264
290
|
startUnreadPolling: (intervalMs?: number) => () => void;
|
|
@@ -316,4 +342,4 @@ declare function SagepilotChatProvider({ children, closeLabel, loadingLabel }: S
|
|
|
316
342
|
|
|
317
343
|
declare function useSagepilotChat(): SagepilotChatHookState;
|
|
318
344
|
|
|
319
|
-
export { type SagepilotBiometricsAdapter, type SagepilotBootstrapChannelResponse, type SagepilotCacheStorage, SagepilotChat, SagepilotChatError, type SagepilotChatErrorCode, type SagepilotChatHookState, SagepilotChatProvider, type SagepilotChatProviderProps, type SagepilotDeviceInfo, type SagepilotDeviceInfoAdapter, type SagepilotIdentifyResult, type SagepilotIdentity, type SagepilotIdentityState, type SagepilotLifecycleState, type SagepilotLogoutResponse, type SagepilotMobileBehaviorConfig, type SagepilotMobileColorScheme, type SagepilotMobileConfig, type SagepilotMobileConfigureResult, type SagepilotMobileLauncherConfig, type SagepilotMobilePresentationConfig, type SagepilotMobilePresentationStyle, type SagepilotMobileResolvedLauncherConfig, type SagepilotMobileState, type SagepilotMobileSubscription, type SagepilotMobileThemeConfig, type SagepilotMobileThemeState, type SagepilotSessionState, type SagepilotTokenStorage, type SagepilotUnreadState, createAsyncStorageCacheStorage, createKeychainTokenStorage, useSagepilotChat };
|
|
345
|
+
export { type SagepilotBiometricsAdapter, type SagepilotBootstrapChannelResponse, type SagepilotCacheStorage, SagepilotChat, SagepilotChatError, type SagepilotChatErrorCode, type SagepilotChatHookState, SagepilotChatProvider, type SagepilotChatProviderProps, type SagepilotConversationCreatedEvent, type SagepilotDeviceInfo, type SagepilotDeviceInfoAdapter, type SagepilotIdentifyResult, type SagepilotIdentity, type SagepilotIdentityState, type SagepilotLifecycleState, type SagepilotLogoutResponse, type SagepilotMessageComposerOptions, type SagepilotMobileBehaviorConfig, type SagepilotMobileColorScheme, type SagepilotMobileConfig, type SagepilotMobileConfigureResult, type SagepilotMobileLauncherConfig, type SagepilotMobilePresentationConfig, type SagepilotMobilePresentationStyle, type SagepilotMobileResolvedLauncherConfig, type SagepilotMobileState, type SagepilotMobileSubscription, type SagepilotMobileThemeConfig, type SagepilotMobileThemeState, type SagepilotSessionState, type SagepilotTokenStorage, type SagepilotUnreadState, createAsyncStorageCacheStorage, createKeychainTokenStorage, useSagepilotChat };
|
package/dist/index.js
CHANGED
|
@@ -56,7 +56,7 @@ var SagepilotChatError = class extends Error {
|
|
|
56
56
|
|
|
57
57
|
// src/core/config/constants.ts
|
|
58
58
|
var SDK_NAME = "@sagepilot-ai/react-native-sdk";
|
|
59
|
-
var SDK_VERSION = "0.2.
|
|
59
|
+
var SDK_VERSION = "0.2.4";
|
|
60
60
|
var DEFAULT_HOST = "https://app.sagepilot.ai";
|
|
61
61
|
var DEFAULT_WIDGET_HOST = "https://app.sagepilot.ai";
|
|
62
62
|
var CUSTOMER_API_PREFIX = "/customer-api/v1";
|
|
@@ -505,6 +505,18 @@ function normalizeIdentity(identity) {
|
|
|
505
505
|
user_hash: identity.userHash ?? identity.user_hash
|
|
506
506
|
};
|
|
507
507
|
}
|
|
508
|
+
function readStringField(input, key) {
|
|
509
|
+
const value = input[key];
|
|
510
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
511
|
+
}
|
|
512
|
+
function normalizeOptionalString(value) {
|
|
513
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
514
|
+
}
|
|
515
|
+
function readRecordField(input, key) {
|
|
516
|
+
const value = input[key];
|
|
517
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
518
|
+
return value;
|
|
519
|
+
}
|
|
508
520
|
function toPublicSessionState(session) {
|
|
509
521
|
return {
|
|
510
522
|
session_id: session.session_id,
|
|
@@ -538,6 +550,7 @@ var SagepilotReactNativeChat = class {
|
|
|
538
550
|
this.unreadPollTimer = null;
|
|
539
551
|
this.stateCallbacks = /* @__PURE__ */ new Set();
|
|
540
552
|
this.identifyCallbacks = /* @__PURE__ */ new Set();
|
|
553
|
+
this.conversationCreatedCallbacks = /* @__PURE__ */ new Set();
|
|
541
554
|
this.unreadCallbacks = /* @__PURE__ */ new Set();
|
|
542
555
|
this.readyCallbacks = /* @__PURE__ */ new Set();
|
|
543
556
|
this.presentCallbacks = /* @__PURE__ */ new Set();
|
|
@@ -744,7 +757,15 @@ var SagepilotReactNativeChat = class {
|
|
|
744
757
|
}
|
|
745
758
|
presentMessageComposer(message, options) {
|
|
746
759
|
this.requireConfigured();
|
|
747
|
-
|
|
760
|
+
const chatId = normalizeOptionalString(options?.chatId);
|
|
761
|
+
this.hostedChatView = {
|
|
762
|
+
screen: "composer",
|
|
763
|
+
message,
|
|
764
|
+
mode: options?.mode ?? "auto",
|
|
765
|
+
chatId,
|
|
766
|
+
metadata: options?.metadata,
|
|
767
|
+
onConversationCreated: options?.onConversationCreated
|
|
768
|
+
};
|
|
748
769
|
return this.showHostedChat();
|
|
749
770
|
}
|
|
750
771
|
dismiss() {
|
|
@@ -793,6 +814,13 @@ var SagepilotReactNativeChat = class {
|
|
|
793
814
|
this.dismissCallbacks.delete(callback);
|
|
794
815
|
};
|
|
795
816
|
}
|
|
817
|
+
onConversationCreated(callback) {
|
|
818
|
+
if (typeof callback !== "function") return () => void 0;
|
|
819
|
+
this.conversationCreatedCallbacks.add(callback);
|
|
820
|
+
return () => {
|
|
821
|
+
this.conversationCreatedCallbacks.delete(callback);
|
|
822
|
+
};
|
|
823
|
+
}
|
|
796
824
|
onError(callback) {
|
|
797
825
|
if (typeof callback !== "function") return () => void 0;
|
|
798
826
|
this.errorCallbacks.add(callback);
|
|
@@ -844,7 +872,10 @@ var SagepilotReactNativeChat = class {
|
|
|
844
872
|
url.searchParams.set("jwt", this.legacyWidgetJwt);
|
|
845
873
|
}
|
|
846
874
|
if (this.hostedChatView.screen === "composer") {
|
|
847
|
-
if (this.hostedChatView.
|
|
875
|
+
if (this.hostedChatView.chatId) {
|
|
876
|
+
url.searchParams.set("chat_id", this.hostedChatView.chatId);
|
|
877
|
+
}
|
|
878
|
+
if (this.hostedChatView.mode === "new" && !this.hostedChatView.chatId) {
|
|
848
879
|
url.searchParams.set("new", "true");
|
|
849
880
|
}
|
|
850
881
|
if (this.hostedChatView.message) {
|
|
@@ -872,13 +903,19 @@ var SagepilotReactNativeChat = class {
|
|
|
872
903
|
"})();"
|
|
873
904
|
].join("\n");
|
|
874
905
|
}
|
|
906
|
+
getActiveHostedChatId() {
|
|
907
|
+
if (this.hostedChatView.screen === "composer" && this.hostedChatView.chatId) {
|
|
908
|
+
return this.hostedChatView.chatId;
|
|
909
|
+
}
|
|
910
|
+
return this.session?.conversation_id ?? void 0;
|
|
911
|
+
}
|
|
875
912
|
getHostedIdentityMessage() {
|
|
876
913
|
if (!this.legacyWidgetJwt) return null;
|
|
877
914
|
return {
|
|
878
915
|
type: "identity_update",
|
|
879
916
|
data: {
|
|
880
917
|
jwt: this.legacyWidgetJwt,
|
|
881
|
-
chat_id: this.
|
|
918
|
+
chat_id: this.getActiveHostedChatId()
|
|
882
919
|
}
|
|
883
920
|
};
|
|
884
921
|
}
|
|
@@ -897,17 +934,62 @@ var SagepilotReactNativeChat = class {
|
|
|
897
934
|
}
|
|
898
935
|
return true;
|
|
899
936
|
}
|
|
937
|
+
if (message.type === "sagepilot:conversation_created") {
|
|
938
|
+
this.handleConversationCreated(message);
|
|
939
|
+
return true;
|
|
940
|
+
}
|
|
900
941
|
if (message.type === "sagepilot:error") {
|
|
901
942
|
this.emitError(message);
|
|
902
943
|
return true;
|
|
903
944
|
}
|
|
904
945
|
return true;
|
|
905
946
|
}
|
|
947
|
+
handleConversationCreated(message) {
|
|
948
|
+
const chatId = readStringField(message, "chat_id") ?? readStringField(message, "conversation_id");
|
|
949
|
+
if (!chatId) return;
|
|
950
|
+
void this.persistConversationId(chatId).catch((error) => this.emitError(error));
|
|
951
|
+
const bridgeMetadata = readRecordField(message, "metadata");
|
|
952
|
+
const composerMetadata = this.hostedChatView.screen === "composer" ? this.hostedChatView.metadata : void 0;
|
|
953
|
+
const metadata = {
|
|
954
|
+
...composerMetadata ?? {},
|
|
955
|
+
...bridgeMetadata ?? {}
|
|
956
|
+
};
|
|
957
|
+
const workspaceId = readStringField(message, "workspace_id") ?? this.workspaceId;
|
|
958
|
+
const channelId = readStringField(message, "channel_id") ?? this.channelId;
|
|
959
|
+
const sessionId = readStringField(message, "session_id") ?? this.session?.session_id;
|
|
960
|
+
const customerId = readStringField(message, "customer_id");
|
|
961
|
+
const messageId = readStringField(message, "message_id");
|
|
962
|
+
const createdAt = readStringField(message, "created_at");
|
|
963
|
+
const event = {
|
|
964
|
+
chat_id: chatId,
|
|
965
|
+
...workspaceId ? { workspace_id: workspaceId } : {},
|
|
966
|
+
...channelId ? { channel_id: channelId } : {},
|
|
967
|
+
...sessionId ? { session_id: sessionId } : {},
|
|
968
|
+
...customerId ? { customer_id: customerId } : {},
|
|
969
|
+
...messageId ? { message_id: messageId } : {},
|
|
970
|
+
...createdAt ? { created_at: createdAt } : {},
|
|
971
|
+
...Object.keys(metadata).length > 0 ? { metadata } : {}
|
|
972
|
+
};
|
|
973
|
+
if (this.hostedChatView.screen === "composer") {
|
|
974
|
+
this.hostedChatView.onConversationCreated?.(event);
|
|
975
|
+
}
|
|
976
|
+
this.conversationCreatedCallbacks.forEach((callback) => callback(event));
|
|
977
|
+
}
|
|
978
|
+
async persistConversationId(conversationId) {
|
|
979
|
+
if (!this.session || !this.sessionManager) return;
|
|
980
|
+
if (this.session.conversation_id === conversationId) return;
|
|
981
|
+
this.session = await this.sessionManager.setSession({
|
|
982
|
+
...this.session,
|
|
983
|
+
conversation_id: conversationId
|
|
984
|
+
});
|
|
985
|
+
this.emitState();
|
|
986
|
+
}
|
|
906
987
|
destroy() {
|
|
907
988
|
this.stopUnreadPolling();
|
|
908
989
|
this.resetRuntimeState();
|
|
909
990
|
this.emitState();
|
|
910
991
|
this.identifyCallbacks.clear();
|
|
992
|
+
this.conversationCreatedCallbacks.clear();
|
|
911
993
|
this.unreadCallbacks.clear();
|
|
912
994
|
this.readyCallbacks.clear();
|
|
913
995
|
this.presentCallbacks.clear();
|
|
@@ -1070,6 +1152,9 @@ var SagepilotChat = {
|
|
|
1070
1152
|
logout: () => internalSagepilotChat.logout(),
|
|
1071
1153
|
getIdentityState: () => internalSagepilotChat.getIdentityState(),
|
|
1072
1154
|
onIdentify: (callback) => internalSagepilotChat.onIdentify(callback),
|
|
1155
|
+
onConversationCreated: (callback) => {
|
|
1156
|
+
return internalSagepilotChat.onConversationCreated(callback);
|
|
1157
|
+
},
|
|
1073
1158
|
getUnreadCount: () => internalSagepilotChat.getUnreadCount(),
|
|
1074
1159
|
onUnreadChange: (callback) => internalSagepilotChat.onUnreadChange(callback),
|
|
1075
1160
|
startUnreadPolling: (intervalMs) => internalSagepilotChat.startUnreadPolling(intervalMs),
|
|
@@ -1262,11 +1347,17 @@ function readUrlOrigin(url) {
|
|
|
1262
1347
|
var hostedChatWebViewProps = {
|
|
1263
1348
|
allowFileAccess: true,
|
|
1264
1349
|
allowFileAccessFromFileURLs: true,
|
|
1350
|
+
...import_react_native.Platform.OS === "ios" ? {
|
|
1351
|
+
automaticallyAdjustContentInsets: false,
|
|
1352
|
+
contentInsetAdjustmentBehavior: "never",
|
|
1353
|
+
hideKeyboardAccessoryView: true
|
|
1354
|
+
} : null,
|
|
1265
1355
|
bounces: false,
|
|
1266
1356
|
domStorageEnabled: true,
|
|
1267
1357
|
javaScriptEnabled: true,
|
|
1268
1358
|
overScrollMode: "never",
|
|
1269
|
-
|
|
1359
|
+
// The hosted widget owns feed scrolling internally; outer WebView scrolling lets iOS focus-scroll the page over the keyboard.
|
|
1360
|
+
scrollEnabled: false,
|
|
1270
1361
|
setSupportMultipleWindows: false,
|
|
1271
1362
|
sharedCookiesEnabled: true,
|
|
1272
1363
|
thirdPartyCookiesEnabled: true
|
|
@@ -1580,6 +1671,9 @@ function useSagepilotChat() {
|
|
|
1580
1671
|
}, []);
|
|
1581
1672
|
const logout = (0, import_react2.useCallback)(() => SagepilotChat.logout(), []);
|
|
1582
1673
|
const getUnreadCount = (0, import_react2.useCallback)(() => SagepilotChat.getUnreadCount(), []);
|
|
1674
|
+
const onConversationCreated = (0, import_react2.useCallback)((callback) => {
|
|
1675
|
+
return SagepilotChat.onConversationCreated(callback);
|
|
1676
|
+
}, []);
|
|
1583
1677
|
return {
|
|
1584
1678
|
...state,
|
|
1585
1679
|
present,
|
|
@@ -1590,7 +1684,8 @@ function useSagepilotChat() {
|
|
|
1590
1684
|
toggle,
|
|
1591
1685
|
identify,
|
|
1592
1686
|
logout,
|
|
1593
|
-
getUnreadCount
|
|
1687
|
+
getUnreadCount,
|
|
1688
|
+
onConversationCreated
|
|
1594
1689
|
};
|
|
1595
1690
|
}
|
|
1596
1691
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.mjs
CHANGED
|
@@ -15,7 +15,7 @@ var SagepilotChatError = class extends Error {
|
|
|
15
15
|
|
|
16
16
|
// src/core/config/constants.ts
|
|
17
17
|
var SDK_NAME = "@sagepilot-ai/react-native-sdk";
|
|
18
|
-
var SDK_VERSION = "0.2.
|
|
18
|
+
var SDK_VERSION = "0.2.4";
|
|
19
19
|
var DEFAULT_HOST = "https://app.sagepilot.ai";
|
|
20
20
|
var DEFAULT_WIDGET_HOST = "https://app.sagepilot.ai";
|
|
21
21
|
var CUSTOMER_API_PREFIX = "/customer-api/v1";
|
|
@@ -464,6 +464,18 @@ function normalizeIdentity(identity) {
|
|
|
464
464
|
user_hash: identity.userHash ?? identity.user_hash
|
|
465
465
|
};
|
|
466
466
|
}
|
|
467
|
+
function readStringField(input, key) {
|
|
468
|
+
const value = input[key];
|
|
469
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
470
|
+
}
|
|
471
|
+
function normalizeOptionalString(value) {
|
|
472
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
473
|
+
}
|
|
474
|
+
function readRecordField(input, key) {
|
|
475
|
+
const value = input[key];
|
|
476
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
477
|
+
return value;
|
|
478
|
+
}
|
|
467
479
|
function toPublicSessionState(session) {
|
|
468
480
|
return {
|
|
469
481
|
session_id: session.session_id,
|
|
@@ -497,6 +509,7 @@ var SagepilotReactNativeChat = class {
|
|
|
497
509
|
this.unreadPollTimer = null;
|
|
498
510
|
this.stateCallbacks = /* @__PURE__ */ new Set();
|
|
499
511
|
this.identifyCallbacks = /* @__PURE__ */ new Set();
|
|
512
|
+
this.conversationCreatedCallbacks = /* @__PURE__ */ new Set();
|
|
500
513
|
this.unreadCallbacks = /* @__PURE__ */ new Set();
|
|
501
514
|
this.readyCallbacks = /* @__PURE__ */ new Set();
|
|
502
515
|
this.presentCallbacks = /* @__PURE__ */ new Set();
|
|
@@ -703,7 +716,15 @@ var SagepilotReactNativeChat = class {
|
|
|
703
716
|
}
|
|
704
717
|
presentMessageComposer(message, options) {
|
|
705
718
|
this.requireConfigured();
|
|
706
|
-
|
|
719
|
+
const chatId = normalizeOptionalString(options?.chatId);
|
|
720
|
+
this.hostedChatView = {
|
|
721
|
+
screen: "composer",
|
|
722
|
+
message,
|
|
723
|
+
mode: options?.mode ?? "auto",
|
|
724
|
+
chatId,
|
|
725
|
+
metadata: options?.metadata,
|
|
726
|
+
onConversationCreated: options?.onConversationCreated
|
|
727
|
+
};
|
|
707
728
|
return this.showHostedChat();
|
|
708
729
|
}
|
|
709
730
|
dismiss() {
|
|
@@ -752,6 +773,13 @@ var SagepilotReactNativeChat = class {
|
|
|
752
773
|
this.dismissCallbacks.delete(callback);
|
|
753
774
|
};
|
|
754
775
|
}
|
|
776
|
+
onConversationCreated(callback) {
|
|
777
|
+
if (typeof callback !== "function") return () => void 0;
|
|
778
|
+
this.conversationCreatedCallbacks.add(callback);
|
|
779
|
+
return () => {
|
|
780
|
+
this.conversationCreatedCallbacks.delete(callback);
|
|
781
|
+
};
|
|
782
|
+
}
|
|
755
783
|
onError(callback) {
|
|
756
784
|
if (typeof callback !== "function") return () => void 0;
|
|
757
785
|
this.errorCallbacks.add(callback);
|
|
@@ -803,7 +831,10 @@ var SagepilotReactNativeChat = class {
|
|
|
803
831
|
url.searchParams.set("jwt", this.legacyWidgetJwt);
|
|
804
832
|
}
|
|
805
833
|
if (this.hostedChatView.screen === "composer") {
|
|
806
|
-
if (this.hostedChatView.
|
|
834
|
+
if (this.hostedChatView.chatId) {
|
|
835
|
+
url.searchParams.set("chat_id", this.hostedChatView.chatId);
|
|
836
|
+
}
|
|
837
|
+
if (this.hostedChatView.mode === "new" && !this.hostedChatView.chatId) {
|
|
807
838
|
url.searchParams.set("new", "true");
|
|
808
839
|
}
|
|
809
840
|
if (this.hostedChatView.message) {
|
|
@@ -831,13 +862,19 @@ var SagepilotReactNativeChat = class {
|
|
|
831
862
|
"})();"
|
|
832
863
|
].join("\n");
|
|
833
864
|
}
|
|
865
|
+
getActiveHostedChatId() {
|
|
866
|
+
if (this.hostedChatView.screen === "composer" && this.hostedChatView.chatId) {
|
|
867
|
+
return this.hostedChatView.chatId;
|
|
868
|
+
}
|
|
869
|
+
return this.session?.conversation_id ?? void 0;
|
|
870
|
+
}
|
|
834
871
|
getHostedIdentityMessage() {
|
|
835
872
|
if (!this.legacyWidgetJwt) return null;
|
|
836
873
|
return {
|
|
837
874
|
type: "identity_update",
|
|
838
875
|
data: {
|
|
839
876
|
jwt: this.legacyWidgetJwt,
|
|
840
|
-
chat_id: this.
|
|
877
|
+
chat_id: this.getActiveHostedChatId()
|
|
841
878
|
}
|
|
842
879
|
};
|
|
843
880
|
}
|
|
@@ -856,17 +893,62 @@ var SagepilotReactNativeChat = class {
|
|
|
856
893
|
}
|
|
857
894
|
return true;
|
|
858
895
|
}
|
|
896
|
+
if (message.type === "sagepilot:conversation_created") {
|
|
897
|
+
this.handleConversationCreated(message);
|
|
898
|
+
return true;
|
|
899
|
+
}
|
|
859
900
|
if (message.type === "sagepilot:error") {
|
|
860
901
|
this.emitError(message);
|
|
861
902
|
return true;
|
|
862
903
|
}
|
|
863
904
|
return true;
|
|
864
905
|
}
|
|
906
|
+
handleConversationCreated(message) {
|
|
907
|
+
const chatId = readStringField(message, "chat_id") ?? readStringField(message, "conversation_id");
|
|
908
|
+
if (!chatId) return;
|
|
909
|
+
void this.persistConversationId(chatId).catch((error) => this.emitError(error));
|
|
910
|
+
const bridgeMetadata = readRecordField(message, "metadata");
|
|
911
|
+
const composerMetadata = this.hostedChatView.screen === "composer" ? this.hostedChatView.metadata : void 0;
|
|
912
|
+
const metadata = {
|
|
913
|
+
...composerMetadata ?? {},
|
|
914
|
+
...bridgeMetadata ?? {}
|
|
915
|
+
};
|
|
916
|
+
const workspaceId = readStringField(message, "workspace_id") ?? this.workspaceId;
|
|
917
|
+
const channelId = readStringField(message, "channel_id") ?? this.channelId;
|
|
918
|
+
const sessionId = readStringField(message, "session_id") ?? this.session?.session_id;
|
|
919
|
+
const customerId = readStringField(message, "customer_id");
|
|
920
|
+
const messageId = readStringField(message, "message_id");
|
|
921
|
+
const createdAt = readStringField(message, "created_at");
|
|
922
|
+
const event = {
|
|
923
|
+
chat_id: chatId,
|
|
924
|
+
...workspaceId ? { workspace_id: workspaceId } : {},
|
|
925
|
+
...channelId ? { channel_id: channelId } : {},
|
|
926
|
+
...sessionId ? { session_id: sessionId } : {},
|
|
927
|
+
...customerId ? { customer_id: customerId } : {},
|
|
928
|
+
...messageId ? { message_id: messageId } : {},
|
|
929
|
+
...createdAt ? { created_at: createdAt } : {},
|
|
930
|
+
...Object.keys(metadata).length > 0 ? { metadata } : {}
|
|
931
|
+
};
|
|
932
|
+
if (this.hostedChatView.screen === "composer") {
|
|
933
|
+
this.hostedChatView.onConversationCreated?.(event);
|
|
934
|
+
}
|
|
935
|
+
this.conversationCreatedCallbacks.forEach((callback) => callback(event));
|
|
936
|
+
}
|
|
937
|
+
async persistConversationId(conversationId) {
|
|
938
|
+
if (!this.session || !this.sessionManager) return;
|
|
939
|
+
if (this.session.conversation_id === conversationId) return;
|
|
940
|
+
this.session = await this.sessionManager.setSession({
|
|
941
|
+
...this.session,
|
|
942
|
+
conversation_id: conversationId
|
|
943
|
+
});
|
|
944
|
+
this.emitState();
|
|
945
|
+
}
|
|
865
946
|
destroy() {
|
|
866
947
|
this.stopUnreadPolling();
|
|
867
948
|
this.resetRuntimeState();
|
|
868
949
|
this.emitState();
|
|
869
950
|
this.identifyCallbacks.clear();
|
|
951
|
+
this.conversationCreatedCallbacks.clear();
|
|
870
952
|
this.unreadCallbacks.clear();
|
|
871
953
|
this.readyCallbacks.clear();
|
|
872
954
|
this.presentCallbacks.clear();
|
|
@@ -1029,6 +1111,9 @@ var SagepilotChat = {
|
|
|
1029
1111
|
logout: () => internalSagepilotChat.logout(),
|
|
1030
1112
|
getIdentityState: () => internalSagepilotChat.getIdentityState(),
|
|
1031
1113
|
onIdentify: (callback) => internalSagepilotChat.onIdentify(callback),
|
|
1114
|
+
onConversationCreated: (callback) => {
|
|
1115
|
+
return internalSagepilotChat.onConversationCreated(callback);
|
|
1116
|
+
},
|
|
1032
1117
|
getUnreadCount: () => internalSagepilotChat.getUnreadCount(),
|
|
1033
1118
|
onUnreadChange: (callback) => internalSagepilotChat.onUnreadChange(callback),
|
|
1034
1119
|
startUnreadPolling: (intervalMs) => internalSagepilotChat.startUnreadPolling(intervalMs),
|
|
@@ -1231,11 +1316,17 @@ function readUrlOrigin(url) {
|
|
|
1231
1316
|
var hostedChatWebViewProps = {
|
|
1232
1317
|
allowFileAccess: true,
|
|
1233
1318
|
allowFileAccessFromFileURLs: true,
|
|
1319
|
+
...Platform.OS === "ios" ? {
|
|
1320
|
+
automaticallyAdjustContentInsets: false,
|
|
1321
|
+
contentInsetAdjustmentBehavior: "never",
|
|
1322
|
+
hideKeyboardAccessoryView: true
|
|
1323
|
+
} : null,
|
|
1234
1324
|
bounces: false,
|
|
1235
1325
|
domStorageEnabled: true,
|
|
1236
1326
|
javaScriptEnabled: true,
|
|
1237
1327
|
overScrollMode: "never",
|
|
1238
|
-
|
|
1328
|
+
// The hosted widget owns feed scrolling internally; outer WebView scrolling lets iOS focus-scroll the page over the keyboard.
|
|
1329
|
+
scrollEnabled: false,
|
|
1239
1330
|
setSupportMultipleWindows: false,
|
|
1240
1331
|
sharedCookiesEnabled: true,
|
|
1241
1332
|
thirdPartyCookiesEnabled: true
|
|
@@ -1549,6 +1640,9 @@ function useSagepilotChat() {
|
|
|
1549
1640
|
}, []);
|
|
1550
1641
|
const logout = useCallback2(() => SagepilotChat.logout(), []);
|
|
1551
1642
|
const getUnreadCount = useCallback2(() => SagepilotChat.getUnreadCount(), []);
|
|
1643
|
+
const onConversationCreated = useCallback2((callback) => {
|
|
1644
|
+
return SagepilotChat.onConversationCreated(callback);
|
|
1645
|
+
}, []);
|
|
1552
1646
|
return {
|
|
1553
1647
|
...state,
|
|
1554
1648
|
present,
|
|
@@ -1559,7 +1653,8 @@ function useSagepilotChat() {
|
|
|
1559
1653
|
toggle,
|
|
1560
1654
|
identify,
|
|
1561
1655
|
logout,
|
|
1562
|
-
getUnreadCount
|
|
1656
|
+
getUnreadCount,
|
|
1657
|
+
onConversationCreated
|
|
1563
1658
|
};
|
|
1564
1659
|
}
|
|
1565
1660
|
export {
|