@sagepilot-ai/react-native-sdk 0.2.0 → 0.2.2

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/dist/index.cjs CHANGED
@@ -830,6 +830,9 @@ var SagepilotReactNativeChat = class {
830
830
  }
831
831
  url.searchParams.set("session_id", session.session_id);
832
832
  url.searchParams.set("wid", this.workspaceId);
833
+ if (this.legacyWidgetJwt) {
834
+ url.searchParams.set("jwt", this.legacyWidgetJwt);
835
+ }
833
836
  if (this.hostedChatView.screen === "composer") {
834
837
  url.searchParams.set("new", "true");
835
838
  if (this.hostedChatView.message) {
@@ -857,6 +860,16 @@ var SagepilotReactNativeChat = class {
857
860
  "})();"
858
861
  ].join("\n");
859
862
  }
863
+ getHostedIdentityMessage() {
864
+ if (!this.legacyWidgetJwt) return null;
865
+ return {
866
+ type: "identity_update",
867
+ data: {
868
+ jwt: this.legacyWidgetJwt,
869
+ chat_id: this.session?.conversation_id ?? void 0
870
+ }
871
+ };
872
+ }
860
873
  handleHostedBridgeMessage(message) {
861
874
  if (!message) return false;
862
875
  if (message.type === "close_widget") {
@@ -1184,6 +1197,20 @@ function getInjectedWebViewScript() {
1184
1197
  mobileWebViewBridgeScript
1185
1198
  ].filter(Boolean).join("\n");
1186
1199
  }
1200
+ function getHostedIdentityDispatchScript() {
1201
+ const message = internalSagepilotChat.getHostedIdentityMessage();
1202
+ if (!message) return "";
1203
+ return [
1204
+ internalSagepilotChat.getHostedAuthScript(),
1205
+ "(function(){",
1206
+ "try {",
1207
+ `var message = ${JSON.stringify(message)};`,
1208
+ "window.dispatchEvent(new MessageEvent('message', { data: message, origin: window.location.origin, source: window.parent || window }));",
1209
+ "} catch (_) {}",
1210
+ "true;",
1211
+ "})();"
1212
+ ].filter(Boolean).join("\n");
1213
+ }
1187
1214
  function readUrlOrigin(url) {
1188
1215
  if (!url) return null;
1189
1216
  try {
@@ -1207,6 +1234,8 @@ function SagepilotChatProvider({
1207
1234
  loadingLabel = "Loading chat"
1208
1235
  }) {
1209
1236
  const [state, setState] = (0, import_react.useState)(readPresentationState);
1237
+ const webFrameRef = (0, import_react.useRef)(null);
1238
+ const nativeWebViewRef = (0, import_react.useRef)(null);
1210
1239
  (0, import_react.useEffect)(() => {
1211
1240
  return internalSagepilotChat.onStateChange(() => {
1212
1241
  setState(readPresentationState());
@@ -1214,10 +1243,23 @@ function SagepilotChatProvider({
1214
1243
  }, []);
1215
1244
  const showCloseButton = state.presentation?.showCloseButton ?? false;
1216
1245
  const presentationStyle = state.presentation?.style ?? "sheet";
1246
+ const isFullScreenModal = presentationStyle === "fullScreen";
1217
1247
  const animationType = presentationStyle === "fullScreen" || presentationStyle === "push" ? "slide" : "fade";
1248
+ const ModalContainer = import_react_native.Platform.OS === "ios" && isFullScreenModal ? import_react_native.SafeAreaView : import_react_native.View;
1218
1249
  const handleWebViewMessage = (event) => {
1219
1250
  internalSagepilotChat.handleHostedBridgeMessage(parseHostedBridgeMessage(event.nativeEvent?.data));
1220
1251
  };
1252
+ const postIdentityToWebFrame = () => {
1253
+ const message = internalSagepilotChat.getHostedIdentityMessage();
1254
+ const targetOrigin = readUrlOrigin(state.conversationUrl);
1255
+ if (!message || !targetOrigin) return;
1256
+ webFrameRef.current?.contentWindow?.postMessage(message, targetOrigin);
1257
+ };
1258
+ const postIdentityToNativeWebView = () => {
1259
+ const script = getHostedIdentityDispatchScript();
1260
+ if (!script || !nativeWebViewRef.current) return;
1261
+ nativeWebViewRef.current.injectJavaScript(script);
1262
+ };
1221
1263
  (0, import_react.useEffect)(() => {
1222
1264
  if (import_react_native.Platform.OS !== "web" || typeof window === "undefined") return;
1223
1265
  const trustedWidgetOrigin = readUrlOrigin(state.conversationUrl);
@@ -1229,6 +1271,14 @@ function SagepilotChatProvider({
1229
1271
  window.addEventListener("message", handleWindowMessage);
1230
1272
  return () => window.removeEventListener("message", handleWindowMessage);
1231
1273
  }, [state.conversationUrl]);
1274
+ (0, import_react.useEffect)(() => {
1275
+ if (import_react_native.Platform.OS !== "web" || !state.isPresented) return;
1276
+ postIdentityToWebFrame();
1277
+ }, [state.isPresented, state.conversationUrl, state.configured]);
1278
+ (0, import_react.useEffect)(() => {
1279
+ if (import_react_native.Platform.OS === "web" || !state.isPresented) return;
1280
+ postIdentityToNativeWebView();
1281
+ }, [state.isPresented, state.conversationUrl, state.configured]);
1232
1282
  if (import_react_native.Platform.OS === "web") {
1233
1283
  return (0, import_react.createElement)(
1234
1284
  import_react_native.View,
@@ -1256,9 +1306,11 @@ function SagepilotChatProvider({
1256
1306
  (0, import_react.createElement)(import_react_native.Text, { style: styles.closeText }, closeLabel)
1257
1307
  ) : null,
1258
1308
  (0, import_react.createElement)("iframe", {
1309
+ ref: webFrameRef,
1259
1310
  src: state.conversationUrl,
1260
1311
  style: styles.webFrame,
1261
- title: "Sagepilot chat"
1312
+ title: "Sagepilot chat",
1313
+ onLoad: postIdentityToWebFrame
1262
1314
  })
1263
1315
  )
1264
1316
  ) : null
@@ -1280,11 +1332,11 @@ function SagepilotChatProvider({
1280
1332
  {
1281
1333
  visible: state.configured && state.isPresented,
1282
1334
  animationType,
1283
- presentationStyle: presentationStyle === "fullScreen" ? "fullScreen" : "pageSheet",
1335
+ presentationStyle: isFullScreenModal ? "fullScreen" : "pageSheet",
1284
1336
  onRequestClose: () => internalSagepilotChat.dismiss()
1285
1337
  },
1286
1338
  (0, import_react.createElement)(
1287
- import_react_native.View,
1339
+ ModalContainer,
1288
1340
  { style: styles.container },
1289
1341
  showCloseButton ? (0, import_react.createElement)(
1290
1342
  import_react_native.View,
@@ -1302,11 +1354,13 @@ function SagepilotChatProvider({
1302
1354
  ) : null,
1303
1355
  state.conversationUrl ? (0, import_react.createElement)(import_react_native_webview.WebView, {
1304
1356
  ...hostedChatWebViewProps,
1357
+ ref: nativeWebViewRef,
1305
1358
  source: { uri: state.conversationUrl },
1306
1359
  style: styles.webview,
1307
1360
  startInLoadingState: true,
1308
1361
  injectedJavaScriptBeforeContentLoaded: getInjectedWebViewScript(),
1309
1362
  onMessage: handleWebViewMessage,
1363
+ onLoadEnd: postIdentityToNativeWebView,
1310
1364
  renderLoading: () => (0, import_react.createElement)(
1311
1365
  import_react_native.View,
1312
1366
  { style: styles.loading },
package/dist/index.js CHANGED
@@ -799,6 +799,9 @@ var SagepilotReactNativeChat = class {
799
799
  }
800
800
  url.searchParams.set("session_id", session.session_id);
801
801
  url.searchParams.set("wid", this.workspaceId);
802
+ if (this.legacyWidgetJwt) {
803
+ url.searchParams.set("jwt", this.legacyWidgetJwt);
804
+ }
802
805
  if (this.hostedChatView.screen === "composer") {
803
806
  url.searchParams.set("new", "true");
804
807
  if (this.hostedChatView.message) {
@@ -826,6 +829,16 @@ var SagepilotReactNativeChat = class {
826
829
  "})();"
827
830
  ].join("\n");
828
831
  }
832
+ getHostedIdentityMessage() {
833
+ if (!this.legacyWidgetJwt) return null;
834
+ return {
835
+ type: "identity_update",
836
+ data: {
837
+ jwt: this.legacyWidgetJwt,
838
+ chat_id: this.session?.conversation_id ?? void 0
839
+ }
840
+ };
841
+ }
829
842
  handleHostedBridgeMessage(message) {
830
843
  if (!message) return false;
831
844
  if (message.type === "close_widget") {
@@ -1046,12 +1059,13 @@ function createAsyncStorageCacheStorage(asyncStorage) {
1046
1059
  }
1047
1060
 
1048
1061
  // src/ui/SagepilotChatProvider.ts
1049
- import { createElement, useEffect, useState } from "react";
1062
+ import { createElement, useEffect, useRef, useState } from "react";
1050
1063
  import {
1051
1064
  ActivityIndicator,
1052
1065
  Modal,
1053
1066
  Platform,
1054
1067
  Pressable,
1068
+ SafeAreaView,
1055
1069
  StyleSheet,
1056
1070
  Text,
1057
1071
  View
@@ -1161,6 +1175,20 @@ function getInjectedWebViewScript() {
1161
1175
  mobileWebViewBridgeScript
1162
1176
  ].filter(Boolean).join("\n");
1163
1177
  }
1178
+ function getHostedIdentityDispatchScript() {
1179
+ const message = internalSagepilotChat.getHostedIdentityMessage();
1180
+ if (!message) return "";
1181
+ return [
1182
+ internalSagepilotChat.getHostedAuthScript(),
1183
+ "(function(){",
1184
+ "try {",
1185
+ `var message = ${JSON.stringify(message)};`,
1186
+ "window.dispatchEvent(new MessageEvent('message', { data: message, origin: window.location.origin, source: window.parent || window }));",
1187
+ "} catch (_) {}",
1188
+ "true;",
1189
+ "})();"
1190
+ ].filter(Boolean).join("\n");
1191
+ }
1164
1192
  function readUrlOrigin(url) {
1165
1193
  if (!url) return null;
1166
1194
  try {
@@ -1184,6 +1212,8 @@ function SagepilotChatProvider({
1184
1212
  loadingLabel = "Loading chat"
1185
1213
  }) {
1186
1214
  const [state, setState] = useState(readPresentationState);
1215
+ const webFrameRef = useRef(null);
1216
+ const nativeWebViewRef = useRef(null);
1187
1217
  useEffect(() => {
1188
1218
  return internalSagepilotChat.onStateChange(() => {
1189
1219
  setState(readPresentationState());
@@ -1191,10 +1221,23 @@ function SagepilotChatProvider({
1191
1221
  }, []);
1192
1222
  const showCloseButton = state.presentation?.showCloseButton ?? false;
1193
1223
  const presentationStyle = state.presentation?.style ?? "sheet";
1224
+ const isFullScreenModal = presentationStyle === "fullScreen";
1194
1225
  const animationType = presentationStyle === "fullScreen" || presentationStyle === "push" ? "slide" : "fade";
1226
+ const ModalContainer = Platform.OS === "ios" && isFullScreenModal ? SafeAreaView : View;
1195
1227
  const handleWebViewMessage = (event) => {
1196
1228
  internalSagepilotChat.handleHostedBridgeMessage(parseHostedBridgeMessage(event.nativeEvent?.data));
1197
1229
  };
1230
+ const postIdentityToWebFrame = () => {
1231
+ const message = internalSagepilotChat.getHostedIdentityMessage();
1232
+ const targetOrigin = readUrlOrigin(state.conversationUrl);
1233
+ if (!message || !targetOrigin) return;
1234
+ webFrameRef.current?.contentWindow?.postMessage(message, targetOrigin);
1235
+ };
1236
+ const postIdentityToNativeWebView = () => {
1237
+ const script = getHostedIdentityDispatchScript();
1238
+ if (!script || !nativeWebViewRef.current) return;
1239
+ nativeWebViewRef.current.injectJavaScript(script);
1240
+ };
1198
1241
  useEffect(() => {
1199
1242
  if (Platform.OS !== "web" || typeof window === "undefined") return;
1200
1243
  const trustedWidgetOrigin = readUrlOrigin(state.conversationUrl);
@@ -1206,6 +1249,14 @@ function SagepilotChatProvider({
1206
1249
  window.addEventListener("message", handleWindowMessage);
1207
1250
  return () => window.removeEventListener("message", handleWindowMessage);
1208
1251
  }, [state.conversationUrl]);
1252
+ useEffect(() => {
1253
+ if (Platform.OS !== "web" || !state.isPresented) return;
1254
+ postIdentityToWebFrame();
1255
+ }, [state.isPresented, state.conversationUrl, state.configured]);
1256
+ useEffect(() => {
1257
+ if (Platform.OS === "web" || !state.isPresented) return;
1258
+ postIdentityToNativeWebView();
1259
+ }, [state.isPresented, state.conversationUrl, state.configured]);
1209
1260
  if (Platform.OS === "web") {
1210
1261
  return createElement(
1211
1262
  View,
@@ -1233,9 +1284,11 @@ function SagepilotChatProvider({
1233
1284
  createElement(Text, { style: styles.closeText }, closeLabel)
1234
1285
  ) : null,
1235
1286
  createElement("iframe", {
1287
+ ref: webFrameRef,
1236
1288
  src: state.conversationUrl,
1237
1289
  style: styles.webFrame,
1238
- title: "Sagepilot chat"
1290
+ title: "Sagepilot chat",
1291
+ onLoad: postIdentityToWebFrame
1239
1292
  })
1240
1293
  )
1241
1294
  ) : null
@@ -1257,11 +1310,11 @@ function SagepilotChatProvider({
1257
1310
  {
1258
1311
  visible: state.configured && state.isPresented,
1259
1312
  animationType,
1260
- presentationStyle: presentationStyle === "fullScreen" ? "fullScreen" : "pageSheet",
1313
+ presentationStyle: isFullScreenModal ? "fullScreen" : "pageSheet",
1261
1314
  onRequestClose: () => internalSagepilotChat.dismiss()
1262
1315
  },
1263
1316
  createElement(
1264
- View,
1317
+ ModalContainer,
1265
1318
  { style: styles.container },
1266
1319
  showCloseButton ? createElement(
1267
1320
  View,
@@ -1279,11 +1332,13 @@ function SagepilotChatProvider({
1279
1332
  ) : null,
1280
1333
  state.conversationUrl ? createElement(WebView, {
1281
1334
  ...hostedChatWebViewProps,
1335
+ ref: nativeWebViewRef,
1282
1336
  source: { uri: state.conversationUrl },
1283
1337
  style: styles.webview,
1284
1338
  startInLoadingState: true,
1285
1339
  injectedJavaScriptBeforeContentLoaded: getInjectedWebViewScript(),
1286
1340
  onMessage: handleWebViewMessage,
1341
+ onLoadEnd: postIdentityToNativeWebView,
1287
1342
  renderLoading: () => createElement(
1288
1343
  View,
1289
1344
  { style: styles.loading },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sagepilot-ai/react-native-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Sagepilot AI React Native chat SDK",
5
5
  "keywords": [
6
6
  "sagepilot",
package/LICENSE.md DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Sagepilot AI
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.