@unith-ai/react-native 0.0.13 → 0.0.14

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,IAAI,IAAI,QAAQ,EAAE,kBAAkB,IAAI,sBAAsB,EAAG,MAAM,uBAAuB,CAAC;AAC9H,OAAO,KAAwC,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAGF,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAClC,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AA4PF,wBAAgB,eAAe,CAC7B,OAAO,EAAE,mBAAmB,EAC5B,MAAM,EAAE,sBAAsB,GAC7B,qBAAqB,CAEvB;AAGD,MAAM,MAAM,0BAA0B,GAAG,sBAAsB,GAC3D;IACA,OAAO,EAAE,mBAAmB,CAAC;IAC7B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAGJ,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC;AAChC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC;AAC5B,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,CAAC;AAGxD,wBAAgB,qBAAqB,CAAC,EACpC,OAAO,EACP,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,GAAG,MAAM,EACV,EAAE,0BAA0B,qBAW5B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,IAAI,IAAI,QAAQ,EAAE,kBAAkB,IAAI,sBAAsB,EAAG,MAAM,uBAAuB,CAAC;AAC9H,OAAO,KAAwC,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAGF,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAClC,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAwPF,wBAAgB,eAAe,CAC7B,OAAO,EAAE,mBAAmB,EAC5B,MAAM,EAAE,sBAAsB,GAC7B,qBAAqB,CAEvB;AAGD,MAAM,MAAM,0BAA0B,GAAG,sBAAsB,GAC3D;IACA,OAAO,EAAE,mBAAmB,CAAC;IAC7B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAGJ,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC;AAChC,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC;AAC5B,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,CAAC;AAGxD,wBAAgB,qBAAqB,CAAC,EACpC,OAAO,EACP,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,GAAG,MAAM,EACV,EAAE,0BAA0B,qBAW5B"}
package/dist/lib.js CHANGED
@@ -1,2 +1,2 @@
1
- var n=require("react"),e=require("react-native-webview");function a(n){return n&&"object"==typeof n&&"default"in n?n:{default:n}}var t=/*#__PURE__*/a(n);function o(){return o=Object.assign?Object.assign.bind():function(n){for(var e=1;e<arguments.length;e++){var a=arguments[e];for(var t in a)({}).hasOwnProperty.call(a,t)&&(n[t]=a[t])}return n},o.apply(null,arguments)}var s=["options","style","webviewProps","webClientUrl"];function r(e,a){return function(e,a){var t=n.useRef(null),s=n.useRef(!1),r=n.useState(!1),i=r[0],d=r[1],l=n.useCallback(function(n,e){var a;null==(a=t.current)||a.postMessage(JSON.stringify({type:n,payload:e}))},[]),c=n.useCallback(function(){s.current||(s.current=!0,d(!0),setTimeout(function(){l("INIT",o({},e))},100))},[e,l]),u=n.useCallback(function(n){var e=null;try{e=JSON.parse(n.nativeEvent.data)}catch(n){return}if(e)switch(e.type){case"STATUS_CHANGE":null==a.onStatusChange||a.onStatusChange(e.payload);break;case"CONNECT":null==a.onConnect||a.onConnect(e.payload);break;case"DISCONNECT":null==a.onDisconnect||a.onDisconnect(e.payload);break;case"MESSAGE":null==a.onMessage||a.onMessage(e.payload);break;case"SUGGESTIONS":null==a.onSuggestions||a.onSuggestions(e.payload);break;case"SPEAKING_START":null==a.onSpeakingStart||a.onSpeakingStart();break;case"SPEAKING_END":null==a.onSpeakingEnd||a.onSpeakingEnd();break;case"TIMEOUT_WARNING":null==a.onTimeoutWarning||a.onTimeoutWarning();break;case"TIMEOUT":null==a.onTimeout||a.onTimeout();break;case"KEEP_SESSION":null==a.onKeepSession||a.onKeepSession(e.payload);break;case"MUTE_STATUS":null==a.onMuteStatusChange||a.onMuteStatusChange(e.payload);break;case"ERROR":null==a.onError||a.onError(e.payload)}},[a]);return{webViewRef:t,webViewProps:{source:{html:'<!doctype html>\n<html>\n <head>\n <meta charset="utf-8" />\n <meta name="viewport" content="width=device-width, initial-scale=1" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id="root"></div>\n <script type="module">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === "INIT") {\n try {\n const { Conversation } = await import("https://unpkg.com/@unith-ai/core-client@2.0.3-beta.2/dist/lib.web.js");\n\n if (!("VideoDecoder" in window)) {\n send("ERROR", {\n message: "WebCodecs VideoDecoder is not supported on this device.",\n type: "modal",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById("root");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: \'custom\',\n onStatusChange: (data) => send("STATUS_CHANGE", data),\n onConnect: (data) => send("CONNECT", data),\n onDisconnect: (data) => send("DISCONNECT", data),\n onMessage: (data) => send("MESSAGE", data),\n onSuggestions: (data) => send("SUGGESTIONS", data),\n onSpeakingStart: () => send("SPEAKING_START"),\n onSpeakingEnd: () => send("SPEAKING_END"),\n onTimeoutWarning: () => send("TIMEOUT_WARNING"),\n onTimeout: () => send("TIMEOUT"),\n onKeepSession: (data) => send("KEEP_SESSION", data),\n onMuteStatusChange: (data) => send("MUTE_STATUS", data),\n onError: (data) => send("ERROR", data), \n });\n\n ready = true;\n send("READY");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to process queued message",\n type: "notification",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to initialize conversation",\n type: "modal",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case "START_SESSION":\n await conversation.startSession();\n break;\n case "END_SESSION":\n await conversation.endSession();\n break;\n case "SEND_MESSAGE":\n await conversation.sendMessage(payload?.text || "");\n break; \n case "TOGGLE_MUTE":\n await conversation.toggleMute();\n break;\n case "KEEP_SESSION":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Operation failed",\n type: "notification",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== "INIT") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error("Failed to handle incoming message:", error);\n }\n };\n\n window.addEventListener("message", handleIncoming);\n document.addEventListener("message", handleIncoming);\n <\/script>\n </body>\n</html>',baseUrl:"https://unpkg.com"},onMessage:u,onLoadEnd:c,javaScriptEnabled:!0,allowsInlineMediaPlayback:!0,allowsFileAccess:!0,domStorageEnabled:!0,mediaCapturePermissionGrantType:"grant"},initialized:i,startSession:function(){return l("START_SESSION")},endSession:function(){return l("END_SESSION")},sendMessage:function(n){return l("SEND_MESSAGE",{text:n})},toggleMute:function(){return l("TOGGLE_MUTE")},keepSession:function(){return l("KEEP_SESSION")}}}(e,a)}exports.UnithConversationView=function(n){var a=n.style,i=n.webviewProps,d=r(n.options,function(n,e){if(null==n)return{};var a={};for(var t in n)if({}.hasOwnProperty.call(n,t)){if(-1!==e.indexOf(t))continue;a[t]=n[t]}return a}(n,s));/*#__PURE__*/return t.default.createElement(e.WebView,o({ref:d.webViewRef},d.webViewProps,i,{style:a}))},exports.useConversation=r;
1
+ var n=require("react"),e=require("react-native-webview");function t(n){return n&&"object"==typeof n&&"default"in n?n:{default:n}}var a=/*#__PURE__*/t(n);function o(){return o=Object.assign?Object.assign.bind():function(n){for(var e=1;e<arguments.length;e++){var t=arguments[e];for(var a in t)({}).hasOwnProperty.call(t,a)&&(n[a]=t[a])}return n},o.apply(null,arguments)}var s=["options","style","webviewProps","webClientUrl"];function r(e,t){return function(e,t){var a=n.useRef(null),s=n.useRef(!1),r=n.useState(!1),i=r[0],d=r[1],c=n.useCallback(function(n,e){var t;null==(t=a.current)||t.postMessage(JSON.stringify({type:n,payload:e}))},[]),l=n.useCallback(function(){s.current||(s.current=!0,d(!0),setTimeout(function(){c("INIT",o({},e))},100))},[e,c]),u=n.useCallback(function(n){var e=null;try{e=JSON.parse(n.nativeEvent.data)}catch(n){return}if(e)switch(e.type){case"STATUS_CHANGE":null==t.onStatusChange||t.onStatusChange(e.payload);break;case"CONNECT":null==t.onConnect||t.onConnect(e.payload);break;case"DISCONNECT":null==t.onDisconnect||t.onDisconnect(e.payload);break;case"MESSAGE":null==t.onMessage||t.onMessage(e.payload);break;case"SUGGESTIONS":null==t.onSuggestions||t.onSuggestions(e.payload);break;case"SPEAKING_START":null==t.onSpeakingStart||t.onSpeakingStart();break;case"SPEAKING_END":null==t.onSpeakingEnd||t.onSpeakingEnd();break;case"TIMEOUT_WARNING":null==t.onTimeoutWarning||t.onTimeoutWarning();break;case"TIMEOUT":null==t.onTimeout||t.onTimeout();break;case"KEEP_SESSION":null==t.onKeepSession||t.onKeepSession(e.payload);break;case"MUTE_STATUS":null==t.onMuteStatusChange||t.onMuteStatusChange(e.payload);break;case"ERROR":null==t.onError||t.onError(e.payload)}},[t]);return{webViewRef:a,webViewProps:{source:{html:'<!doctype html>\n<html>\n <head>\n <meta charset="utf-8" />\n <meta name="viewport" content="width=device-width, initial-scale=1" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id="root"></div>\n <script type="module">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === "INIT") {\n try {\n const { Conversation } = await import("https://unpkg.com/@unith-ai/core-client@2.0.3-beta.3/dist/lib.web.js");\n\n if (!("VideoDecoder" in window)) {\n send("ERROR", {\n message: "WebCodecs VideoDecoder is not supported on this device.",\n type: "modal",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById("root");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: \'custom\',\n onStatusChange: (data) => send("STATUS_CHANGE", data),\n onConnect: (data) => send("CONNECT", data),\n onDisconnect: (data) => send("DISCONNECT", data),\n onMessage: (data) => send("MESSAGE", data),\n onSuggestions: (data) => send("SUGGESTIONS", data),\n onSpeakingStart: () => send("SPEAKING_START"),\n onSpeakingEnd: () => send("SPEAKING_END"),\n onTimeoutWarning: () => send("TIMEOUT_WARNING"),\n onTimeout: () => send("TIMEOUT"),\n onKeepSession: (data) => send("KEEP_SESSION", data),\n onMuteStatusChange: (data) => send("MUTE_STATUS", data),\n onError: (data) => send("ERROR", data), \n });\n\n ready = true;\n send("READY");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to process queued message",\n type: "notification",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to initialize conversation",\n type: "modal",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case "START_SESSION":\n await conversation.startSession();\n break;\n case "END_SESSION":\n await conversation.endSession();\n break;\n case "SEND_MESSAGE":\n await conversation.sendMessage(payload?.text || "");\n break; \n case "TOGGLE_MUTE":\n await conversation.toggleMute();\n break;\n case "KEEP_SESSION":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Operation failed",\n type: "notification",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== "INIT") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error("Failed to handle incoming message:", error);\n }\n };\n\n window.addEventListener("message", handleIncoming);\n document.addEventListener("message", handleIncoming);\n <\/script>\n </body>\n</html>',baseUrl:"https://unpkg.com"},onMessage:u,onLoadEnd:l,javaScriptEnabled:!0},initialized:i,startSession:function(){return c("START_SESSION")},endSession:function(){return c("END_SESSION")},sendMessage:function(n){return c("SEND_MESSAGE",{text:n})},toggleMute:function(){return c("TOGGLE_MUTE")},keepSession:function(){return c("KEEP_SESSION")}}}(e,t)}exports.UnithConversationView=function(n){var t=n.style,i=n.webviewProps,d=r(n.options,function(n,e){if(null==n)return{};var t={};for(var a in n)if({}.hasOwnProperty.call(n,a)){if(-1!==e.indexOf(a))continue;t[a]=n[a]}return t}(n,s));/*#__PURE__*/return a.default.createElement(e.WebView,o({ref:d.webViewRef},d.webViewProps,i,{style:t}))},exports.useConversation=r;
2
2
  //# sourceMappingURL=lib.js.map
package/dist/lib.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"lib.js","sources":["../src/index.tsx"],"sourcesContent":["import { Status as StatusType, Mode as ModeType, ConversationEvents as ConversationEventsType, } from \"@unith-ai/core-client\";\nimport React, { useCallback, useRef, useState } from \"react\";\nimport { ViewStyle } from \"react-native\";\nimport { WebView, WebViewMessageEvent } from \"react-native-webview\";\n\nexport type ConversationOptions = {\n orgId: string;\n headId: string;\n apiKey: string;\n language?: string;\n username?: string;\n};\n\n\nexport type BridgeOptions = {\n webClientUrl?: string;\n webViewBaseUrl?: string;\n};\n\nexport type UseConversationResult = {\n webViewRef: React.RefObject<any>;\n webViewProps: Record<string, any>;\n initialized: boolean;\n startSession: () => void;\n endSession: () => void;\n sendMessage: (text: string) => void;\n toggleMute: () => void;\n keepSession: () => void;\n};\n\ntype BridgeMessage = {\n type: string;\n payload?: any;\n};\n\nconst DEFAULT_WEB_CLIENT_URL =\n \"https://unpkg.com/@unith-ai/core-client@2.0.3-beta.2/dist/lib.web.js\";\n\nfunction buildHtml(webClientUrl: string) {\n return `<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === \"INIT\") {\n try {\n const { Conversation } = await import(\"${webClientUrl}\");\n\n if (!(\"VideoDecoder\" in window)) {\n send(\"ERROR\", {\n message: \"WebCodecs VideoDecoder is not supported on this device.\",\n type: \"modal\",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById(\"root\");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: 'custom',\n onStatusChange: (data) => send(\"STATUS_CHANGE\", data),\n onConnect: (data) => send(\"CONNECT\", data),\n onDisconnect: (data) => send(\"DISCONNECT\", data),\n onMessage: (data) => send(\"MESSAGE\", data),\n onSuggestions: (data) => send(\"SUGGESTIONS\", data),\n onSpeakingStart: () => send(\"SPEAKING_START\"),\n onSpeakingEnd: () => send(\"SPEAKING_END\"),\n onTimeoutWarning: () => send(\"TIMEOUT_WARNING\"),\n onTimeout: () => send(\"TIMEOUT\"),\n onKeepSession: (data) => send(\"KEEP_SESSION\", data),\n onMuteStatusChange: (data) => send(\"MUTE_STATUS\", data),\n onError: (data) => send(\"ERROR\", data), \n });\n\n ready = true;\n send(\"READY\");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to process queued message\",\n type: \"notification\",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to initialize conversation\",\n type: \"modal\",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case \"START_SESSION\":\n await conversation.startSession();\n break;\n case \"END_SESSION\":\n await conversation.endSession();\n break;\n case \"SEND_MESSAGE\":\n await conversation.sendMessage(payload?.text || \"\");\n break; \n case \"TOGGLE_MUTE\":\n await conversation.toggleMute();\n break;\n case \"KEEP_SESSION\":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Operation failed\",\n type: \"notification\",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== \"INIT\") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error(\"Failed to handle incoming message:\", error);\n }\n };\n\n window.addEventListener(\"message\", handleIncoming);\n document.addEventListener(\"message\", handleIncoming);\n </script>\n </body>\n</html>`;\n}\n\nfunction useBridge(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n const webViewRef = useRef<any>(null);\n const initializedRef = useRef(false);\n const [initialized, setInitialized] = useState(false);\n\n const html = buildHtml(DEFAULT_WEB_CLIENT_URL)\n\n const post = useCallback((type: string, payload?: any) => {\n const message: BridgeMessage = { type, payload };\n webViewRef.current?.postMessage(JSON.stringify(message));\n }, []);\n\n const handleLoadEnd = useCallback(() => {\n if (initializedRef.current) {\n return;\n }\n\n\n initializedRef.current = true;\n setInitialized(true);\n\n // Add a small delay to ensure WebView is ready to receive messages\n setTimeout(() => {\n post(\"INIT\", {\n ...options,\n });\n }, 100);\n }, [options, post]);\n\n const onMessage = useCallback(\n (event: WebViewMessageEvent) => {\n let data: BridgeMessage | null = null;\n try {\n data = JSON.parse(event.nativeEvent.data);\n } catch (_) {\n return;\n }\n if (!data) return;\n\n switch (data.type) {\n case \"STATUS_CHANGE\":\n events.onStatusChange?.(data.payload);\n break;\n case \"CONNECT\":\n events.onConnect?.(data.payload);\n break;\n case \"DISCONNECT\":\n events.onDisconnect?.(data.payload);\n break;\n case \"MESSAGE\":\n events.onMessage?.(data.payload);\n break;\n case \"SUGGESTIONS\":\n events.onSuggestions?.(data.payload);\n break;\n case \"SPEAKING_START\":\n events.onSpeakingStart?.();\n break;\n case \"SPEAKING_END\":\n events.onSpeakingEnd?.();\n break;\n case \"TIMEOUT_WARNING\":\n events.onTimeoutWarning?.();\n break;\n case \"TIMEOUT\":\n events.onTimeout?.();\n break;\n case \"KEEP_SESSION\":\n events.onKeepSession?.(data.payload);\n break;\n case \"MUTE_STATUS\":\n events.onMuteStatusChange?.(data.payload);\n break;\n case \"ERROR\":\n events.onError?.(data.payload);\n break;\n default:\n break;\n }\n },\n [events]\n );\n\n return {\n webViewRef,\n webViewProps: {\n source: { html, baseUrl: \"https://unpkg.com\" },\n onMessage,\n onLoadEnd: handleLoadEnd,\n javaScriptEnabled: true,\n allowsInlineMediaPlayback: true,\n allowsFileAccess: true,\n domStorageEnabled: true,\n mediaCapturePermissionGrantType: 'grant',\n },\n initialized,\n startSession: () => post(\"START_SESSION\"),\n endSession: () => post(\"END_SESSION\"),\n sendMessage: (text: string) => post(\"SEND_MESSAGE\", { text }),\n toggleMute: () => post(\"TOGGLE_MUTE\"),\n keepSession: () => post(\"KEEP_SESSION\"),\n };\n}\n\nexport function useConversation(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n return useBridge(options, events,);\n}\n\n\nexport type UnithConversationViewProps = ConversationEventsType\n & {\n options: ConversationOptions;\n style?: ViewStyle;\n webviewProps?: Record<string, any>;\n webClientUrl?: string;\n };\n\n\nexport type Status = StatusType;\nexport type Mode = ModeType;\nexport type ConversationEvents = ConversationEventsType;\n\n\nexport function UnithConversationView({\n options,\n style,\n webviewProps,\n webClientUrl,\n ...events\n}: UnithConversationViewProps) {\n const convo = useConversation(options, events);\n\n return (\n <WebView\n ref={convo.webViewRef}\n {...convo.webViewProps}\n {...webviewProps}\n style={style}\n />\n );\n}\n"],"names":["_excluded","useConversation","options","events","webViewRef","useRef","initializedRef","_useState","useState","initialized","setInitialized","post","useCallback","type","payload","_webViewRef$current","current","postMessage","JSON","stringify","handleLoadEnd","setTimeout","_extends","onMessage","event","data","parse","nativeEvent","_","onStatusChange","onConnect","onDisconnect","onSuggestions","onSpeakingStart","onSpeakingEnd","onTimeoutWarning","onTimeout","onKeepSession","onMuteStatusChange","onError","webViewProps","source","html","baseUrl","onLoadEnd","javaScriptEnabled","allowsInlineMediaPlayback","allowsFileAccess","domStorageEnabled","mediaCapturePermissionGrantType","startSession","endSession","sendMessage","text","toggleMute","keepSession","useBridge","_ref","style","webviewProps","convo","_objectWithoutPropertiesLoose","React","WebView","ref"],"mappings":"iXACA,IAAAA,EAAA,CAAA,UAAA,QAAA,eAAA,gBAuRgB,SAAAC,EACdC,EACAC,GAEA,OA/GF,SACED,EACAC,GAEA,IAAMC,EAAaC,EAAAA,OAAY,MACzBC,EAAiBD,EAAAA,QAAO,GAC9BE,EAAsCC,EAAAA,UAAS,GAAxCC,EAAWF,EAAA,GAAEG,EAAcH,KAI5BI,EAAOC,EAAWA,YAAC,SAACC,EAAcC,GAAiBC,IAAAA,SAEvDA,EAAAX,EAAWY,UAAXD,EAAoBE,YAAYC,KAAKC,UADN,CAAEN,KAAAA,EAAMC,QAAAA,IAEzC,EAAG,IAEGM,EAAgBR,cAAY,WAC5BN,EAAeU,UAKnBV,EAAeU,SAAU,EACzBN,GAAe,GAGfW,WAAW,WACTV,EAAK,OAAMW,EACNpB,CAAAA,EAAAA,GAEP,EAAG,KACL,EAAG,CAACA,EAASS,IAEPY,EAAYX,EAAAA,YAChB,SAACY,GACC,IAAIC,EAA6B,KACjC,IACEA,EAAOP,KAAKQ,MAAMF,EAAMG,YAAYF,KACtC,CAAE,MAAOG,GACP,MACF,CACA,GAAKH,EAEL,OAAQA,EAAKZ,MACX,IAAK,gBACHV,MAAAA,EAAO0B,gBAAP1B,EAAO0B,eAAiBJ,EAAKX,SAC7B,MACF,IAAK,gBACHX,EAAO2B,WAAP3B,EAAO2B,UAAYL,EAAKX,SACxB,MACF,IAAK,aACHX,MAAAA,EAAO4B,cAAP5B,EAAO4B,aAAeN,EAAKX,SAC3B,MACF,IAAK,UACa,MAAhBX,EAAOoB,WAAPpB,EAAOoB,UAAYE,EAAKX,SACxB,MACF,IAAK,cACHX,MAAAA,EAAO6B,eAAP7B,EAAO6B,cAAgBP,EAAKX,SAC5B,MACF,IAAK,iBACmB,MAAtBX,EAAO8B,iBAAP9B,EAAO8B,kBACP,MACF,IAAK,eACH9B,MAAAA,EAAO+B,eAAP/B,EAAO+B,gBACP,MACF,IAAK,kBACoB,MAAvB/B,EAAOgC,kBAAPhC,EAAOgC,mBACP,MACF,IAAK,gBACHhC,EAAOiC,WAAPjC,EAAOiC,YACP,MACF,IAAK,eACiB,MAApBjC,EAAOkC,eAAPlC,EAAOkC,cAAgBZ,EAAKX,SAC5B,MACF,IAAK,oBACHX,EAAOmC,oBAAPnC,EAAOmC,mBAAqBb,EAAKX,SACjC,MACF,IAAK,QACHX,MAAAA,EAAOoC,SAAPpC,EAAOoC,QAAUd,EAAKX,SAK5B,EACA,CAACX,IAGH,MAAO,CACLC,WAAAA,EACAoC,aAAc,CACZC,OAAQ,CAAEC,KA/Nd,23IA+NoBC,QAAS,qBACzBpB,UAAAA,EACAqB,UAAWxB,EACXyB,mBAAmB,EACnBC,2BAA2B,EAC3BC,kBAAkB,EAClBC,mBAAmB,EACnBC,gCAAiC,SAEnCxC,YAAAA,EACAyC,aAAc,WAAF,OAAQvC,EAAK,gBAAgB,EACzCwC,WAAY,WAAF,OAAQxC,EAAK,cAAc,EACrCyC,YAAa,SAACC,GAAiB,OAAA1C,EAAK,eAAgB,CAAE0C,KAAAA,GAAO,EAC7DC,WAAY,WAAF,OAAQ3C,EAAK,cAAc,EACrC4C,YAAa,WAAM,OAAA5C,EAAK,eAAe,EAE3C,CAMS6C,CAAUtD,EAASC,EAC5B,+BAiBgB,SAAqBsD,GACnC,IACAC,EAAKD,EAALC,MACAC,EAAYF,EAAZE,aAIMC,EAAQ3D,EANPwD,EAAPvD,mJAIS2D,CAAAJ,EAAAzD,iBAIT,OACE8D,wBAACC,EAAAA,QAAOzC,GACN0C,IAAKJ,EAAMxD,YACPwD,EAAMpB,aACNmB,EAAY,CAChBD,MAAOA,IAGb"}
1
+ {"version":3,"file":"lib.js","sources":["../src/index.tsx"],"sourcesContent":["import { Status as StatusType, Mode as ModeType, ConversationEvents as ConversationEventsType, } from \"@unith-ai/core-client\";\nimport React, { useCallback, useRef, useState } from \"react\";\nimport { ViewStyle } from \"react-native\";\nimport { WebView, WebViewMessageEvent } from \"react-native-webview\";\n\nexport type ConversationOptions = {\n orgId: string;\n headId: string;\n apiKey: string;\n language?: string;\n username?: string;\n};\n\n\nexport type BridgeOptions = {\n webClientUrl?: string;\n webViewBaseUrl?: string;\n};\n\nexport type UseConversationResult = {\n webViewRef: React.RefObject<any>;\n webViewProps: Record<string, any>;\n initialized: boolean;\n startSession: () => void;\n endSession: () => void;\n sendMessage: (text: string) => void;\n toggleMute: () => void;\n keepSession: () => void;\n};\n\ntype BridgeMessage = {\n type: string;\n payload?: any;\n};\n\nconst DEFAULT_WEB_CLIENT_URL =\n \"https://unpkg.com/@unith-ai/core-client@2.0.3-beta.3/dist/lib.web.js\";\n\nfunction buildHtml(webClientUrl: string) {\n return `<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === \"INIT\") {\n try {\n const { Conversation } = await import(\"${webClientUrl}\");\n\n if (!(\"VideoDecoder\" in window)) {\n send(\"ERROR\", {\n message: \"WebCodecs VideoDecoder is not supported on this device.\",\n type: \"modal\",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById(\"root\");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: 'custom',\n onStatusChange: (data) => send(\"STATUS_CHANGE\", data),\n onConnect: (data) => send(\"CONNECT\", data),\n onDisconnect: (data) => send(\"DISCONNECT\", data),\n onMessage: (data) => send(\"MESSAGE\", data),\n onSuggestions: (data) => send(\"SUGGESTIONS\", data),\n onSpeakingStart: () => send(\"SPEAKING_START\"),\n onSpeakingEnd: () => send(\"SPEAKING_END\"),\n onTimeoutWarning: () => send(\"TIMEOUT_WARNING\"),\n onTimeout: () => send(\"TIMEOUT\"),\n onKeepSession: (data) => send(\"KEEP_SESSION\", data),\n onMuteStatusChange: (data) => send(\"MUTE_STATUS\", data),\n onError: (data) => send(\"ERROR\", data), \n });\n\n ready = true;\n send(\"READY\");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to process queued message\",\n type: \"notification\",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to initialize conversation\",\n type: \"modal\",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case \"START_SESSION\":\n await conversation.startSession();\n break;\n case \"END_SESSION\":\n await conversation.endSession();\n break;\n case \"SEND_MESSAGE\":\n await conversation.sendMessage(payload?.text || \"\");\n break; \n case \"TOGGLE_MUTE\":\n await conversation.toggleMute();\n break;\n case \"KEEP_SESSION\":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Operation failed\",\n type: \"notification\",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== \"INIT\") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error(\"Failed to handle incoming message:\", error);\n }\n };\n\n window.addEventListener(\"message\", handleIncoming);\n document.addEventListener(\"message\", handleIncoming);\n </script>\n </body>\n</html>`;\n}\n\nfunction useBridge(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n const webViewRef = useRef<any>(null);\n const initializedRef = useRef(false);\n const [initialized, setInitialized] = useState(false);\n\n const html = buildHtml(DEFAULT_WEB_CLIENT_URL)\n\n const post = useCallback((type: string, payload?: any) => {\n const message: BridgeMessage = { type, payload };\n webViewRef.current?.postMessage(JSON.stringify(message));\n }, []);\n\n const handleLoadEnd = useCallback(() => {\n if (initializedRef.current) {\n return;\n }\n\n\n initializedRef.current = true;\n setInitialized(true);\n\n // Add a small delay to ensure WebView is ready to receive messages\n setTimeout(() => {\n post(\"INIT\", {\n ...options,\n });\n }, 100);\n }, [options, post]);\n\n const onMessage = useCallback(\n (event: WebViewMessageEvent) => {\n let data: BridgeMessage | null = null;\n try {\n data = JSON.parse(event.nativeEvent.data);\n } catch (_) {\n return;\n }\n if (!data) return;\n\n switch (data.type) {\n case \"STATUS_CHANGE\":\n events.onStatusChange?.(data.payload);\n break;\n case \"CONNECT\":\n events.onConnect?.(data.payload);\n break;\n case \"DISCONNECT\":\n events.onDisconnect?.(data.payload);\n break;\n case \"MESSAGE\":\n events.onMessage?.(data.payload);\n break;\n case \"SUGGESTIONS\":\n events.onSuggestions?.(data.payload);\n break;\n case \"SPEAKING_START\":\n events.onSpeakingStart?.();\n break;\n case \"SPEAKING_END\":\n events.onSpeakingEnd?.();\n break;\n case \"TIMEOUT_WARNING\":\n events.onTimeoutWarning?.();\n break;\n case \"TIMEOUT\":\n events.onTimeout?.();\n break;\n case \"KEEP_SESSION\":\n events.onKeepSession?.(data.payload);\n break;\n case \"MUTE_STATUS\":\n events.onMuteStatusChange?.(data.payload);\n break;\n case \"ERROR\":\n events.onError?.(data.payload);\n break;\n default:\n break;\n }\n },\n [events]\n );\n\n return {\n webViewRef,\n webViewProps: {\n source: { html, baseUrl: \"https://unpkg.com\" },\n onMessage,\n onLoadEnd: handleLoadEnd,\n javaScriptEnabled: true,\n },\n initialized,\n startSession: () => post(\"START_SESSION\"),\n endSession: () => post(\"END_SESSION\"),\n sendMessage: (text: string) => post(\"SEND_MESSAGE\", { text }),\n toggleMute: () => post(\"TOGGLE_MUTE\"),\n keepSession: () => post(\"KEEP_SESSION\"),\n };\n}\n\nexport function useConversation(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n return useBridge(options, events,);\n}\n\n\nexport type UnithConversationViewProps = ConversationEventsType\n & {\n options: ConversationOptions;\n style?: ViewStyle;\n webviewProps?: Record<string, any>;\n webClientUrl?: string;\n };\n\n\nexport type Status = StatusType;\nexport type Mode = ModeType;\nexport type ConversationEvents = ConversationEventsType;\n\n\nexport function UnithConversationView({\n options,\n style,\n webviewProps,\n webClientUrl,\n ...events\n}: UnithConversationViewProps) {\n const convo = useConversation(options, events);\n\n return (\n <WebView\n ref={convo.webViewRef}\n {...convo.webViewProps}\n {...webviewProps}\n style={style}\n />\n );\n}\n"],"names":["_excluded","useConversation","options","events","webViewRef","useRef","initializedRef","_useState","useState","initialized","setInitialized","post","useCallback","type","payload","_webViewRef$current","current","postMessage","JSON","stringify","handleLoadEnd","setTimeout","_extends","onMessage","event","data","parse","nativeEvent","_","onStatusChange","onConnect","onDisconnect","onSuggestions","onSpeakingStart","onSpeakingEnd","onTimeoutWarning","onTimeout","onKeepSession","onMuteStatusChange","onError","webViewProps","source","html","baseUrl","onLoadEnd","javaScriptEnabled","startSession","endSession","sendMessage","text","toggleMute","keepSession","useBridge","_ref","style","webviewProps","convo","_objectWithoutPropertiesLoose","React","WebView","ref"],"mappings":"iXACA,IAAAA,EAAA,CAAA,UAAA,QAAA,eAAA,gBAmRgB,SAAAC,EACdC,EACAC,GAEA,OA3GF,SACED,EACAC,GAEA,IAAMC,EAAaC,SAAY,MACzBC,EAAiBD,EAAMA,QAAC,GAC9BE,EAAsCC,EAAQA,UAAC,GAAxCC,EAAWF,EAAEG,GAAAA,EAAcH,EAAA,GAI5BI,EAAOC,cAAY,SAACC,EAAcC,OAAiBC,EAEvDA,OAAAA,EAAAX,EAAWY,UAAXD,EAAoBE,YAAYC,KAAKC,UADN,CAAEN,KAAAA,EAAMC,QAAAA,IAEzC,EAAG,IAEGM,EAAgBR,EAAWA,YAAC,WAC5BN,EAAeU,UAKnBV,EAAeU,SAAU,EACzBN,GAAe,GAGfW,WAAW,WACTV,EAAK,OAAMW,KACNpB,GAEP,EAAG,KACL,EAAG,CAACA,EAASS,IAEPY,EAAYX,EAAAA,YAChB,SAACY,GACC,IAAIC,EAA6B,KACjC,IACEA,EAAOP,KAAKQ,MAAMF,EAAMG,YAAYF,KACtC,CAAE,MAAOG,GACP,MACF,CACA,GAAKH,EAEL,OAAQA,EAAKZ,MACX,IAAK,gBACkB,MAArBV,EAAO0B,gBAAP1B,EAAO0B,eAAiBJ,EAAKX,SAC7B,MACF,IAAK,UACHX,MAAAA,EAAO2B,WAAP3B,EAAO2B,UAAYL,EAAKX,SACxB,MACF,IAAK,mBACHX,EAAO4B,cAAP5B,EAAO4B,aAAeN,EAAKX,SAC3B,MACF,IAAK,UACa,MAAhBX,EAAOoB,WAAPpB,EAAOoB,UAAYE,EAAKX,SACxB,MACF,IAAK,cACHX,MAAAA,EAAO6B,eAAP7B,EAAO6B,cAAgBP,EAAKX,SAC5B,MACF,IAAK,iBACmB,MAAtBX,EAAO8B,iBAAP9B,EAAO8B,kBACP,MACF,IAAK,eACH9B,MAAAA,EAAO+B,eAAP/B,EAAO+B,gBACP,MACF,IAAK,wBACH/B,EAAOgC,kBAAPhC,EAAOgC,mBACP,MACF,IAAK,UACa,MAAhBhC,EAAOiC,WAAPjC,EAAOiC,YACP,MACF,IAAK,eACHjC,MAAAA,EAAOkC,eAAPlC,EAAOkC,cAAgBZ,EAAKX,SAC5B,MACF,IAAK,cACsB,MAAzBX,EAAOmC,oBAAPnC,EAAOmC,mBAAqBb,EAAKX,SACjC,MACF,IAAK,QACHX,MAAAA,EAAOoC,SAAPpC,EAAOoC,QAAUd,EAAKX,SAK5B,EACA,CAACX,IAGH,MAAO,CACLC,WAAAA,EACAoC,aAAc,CACZC,OAAQ,CAAEC,KA/Nd,23IA+NoBC,QAAS,qBACzBpB,UAAAA,EACAqB,UAAWxB,EACXyB,mBAAmB,GAErBpC,YAAAA,EACAqC,aAAc,kBAAMnC,EAAK,gBAAgB,EACzCoC,WAAY,WAAM,OAAApC,EAAK,cAAc,EACrCqC,YAAa,SAACC,GAAY,OAAKtC,EAAK,eAAgB,CAAEsC,KAAAA,GAAO,EAC7DC,WAAY,WAAM,OAAAvC,EAAK,cAAc,EACrCwC,YAAa,WAAF,OAAQxC,EAAK,eAAe,EAE3C,CAMSyC,CAAUlD,EAASC,EAC5B,+BAiBgB,SAAqBkD,GACnC,IACAC,EAAKD,EAALC,MACAC,EAAYF,EAAZE,aAIMC,EAAQvD,EANPoD,EAAPnD,mJAISuD,CAAAJ,EAAArD,iBAIT,OACE0D,wBAACC,EAAOA,QAAArC,GACNsC,IAAKJ,EAAMpD,YACPoD,EAAMhB,aACNe,EAAY,CAChBD,MAAOA,IAGb"}
@@ -1,2 +1,2 @@
1
- import n,{useRef as e,useState as a,useCallback as t}from"react";import{WebView as o}from"react-native-webview";function s(){return s=Object.assign?Object.assign.bind():function(n){for(var e=1;e<arguments.length;e++){var a=arguments[e];for(var t in a)({}).hasOwnProperty.call(a,t)&&(n[t]=a[t])}return n},s.apply(null,arguments)}const r=["options","style","webviewProps","webClientUrl"];function i(n,o){return function(n,o){const r=e(null),i=e(!1),[d,l]=a(!1),c=t((n,e)=>{var a;null==(a=r.current)||a.postMessage(JSON.stringify({type:n,payload:e}))},[]),S=t(()=>{i.current||(i.current=!0,l(!0),setTimeout(()=>{c("INIT",s({},n))},100))},[n,c]),u=t(n=>{let e=null;try{e=JSON.parse(n.nativeEvent.data)}catch(n){return}if(e)switch(e.type){case"STATUS_CHANGE":null==o.onStatusChange||o.onStatusChange(e.payload);break;case"CONNECT":null==o.onConnect||o.onConnect(e.payload);break;case"DISCONNECT":null==o.onDisconnect||o.onDisconnect(e.payload);break;case"MESSAGE":null==o.onMessage||o.onMessage(e.payload);break;case"SUGGESTIONS":null==o.onSuggestions||o.onSuggestions(e.payload);break;case"SPEAKING_START":null==o.onSpeakingStart||o.onSpeakingStart();break;case"SPEAKING_END":null==o.onSpeakingEnd||o.onSpeakingEnd();break;case"TIMEOUT_WARNING":null==o.onTimeoutWarning||o.onTimeoutWarning();break;case"TIMEOUT":null==o.onTimeout||o.onTimeout();break;case"KEEP_SESSION":null==o.onKeepSession||o.onKeepSession(e.payload);break;case"MUTE_STATUS":null==o.onMuteStatusChange||o.onMuteStatusChange(e.payload);break;case"ERROR":null==o.onError||o.onError(e.payload)}},[o]);return{webViewRef:r,webViewProps:{source:{html:'<!doctype html>\n<html>\n <head>\n <meta charset="utf-8" />\n <meta name="viewport" content="width=device-width, initial-scale=1" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id="root"></div>\n <script type="module">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === "INIT") {\n try {\n const { Conversation } = await import("https://unpkg.com/@unith-ai/core-client@2.0.3-beta.2/dist/lib.web.js");\n\n if (!("VideoDecoder" in window)) {\n send("ERROR", {\n message: "WebCodecs VideoDecoder is not supported on this device.",\n type: "modal",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById("root");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: \'custom\',\n onStatusChange: (data) => send("STATUS_CHANGE", data),\n onConnect: (data) => send("CONNECT", data),\n onDisconnect: (data) => send("DISCONNECT", data),\n onMessage: (data) => send("MESSAGE", data),\n onSuggestions: (data) => send("SUGGESTIONS", data),\n onSpeakingStart: () => send("SPEAKING_START"),\n onSpeakingEnd: () => send("SPEAKING_END"),\n onTimeoutWarning: () => send("TIMEOUT_WARNING"),\n onTimeout: () => send("TIMEOUT"),\n onKeepSession: (data) => send("KEEP_SESSION", data),\n onMuteStatusChange: (data) => send("MUTE_STATUS", data),\n onError: (data) => send("ERROR", data), \n });\n\n ready = true;\n send("READY");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to process queued message",\n type: "notification",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to initialize conversation",\n type: "modal",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case "START_SESSION":\n await conversation.startSession();\n break;\n case "END_SESSION":\n await conversation.endSession();\n break;\n case "SEND_MESSAGE":\n await conversation.sendMessage(payload?.text || "");\n break; \n case "TOGGLE_MUTE":\n await conversation.toggleMute();\n break;\n case "KEEP_SESSION":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Operation failed",\n type: "notification",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== "INIT") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error("Failed to handle incoming message:", error);\n }\n };\n\n window.addEventListener("message", handleIncoming);\n document.addEventListener("message", handleIncoming);\n <\/script>\n </body>\n</html>',baseUrl:"https://unpkg.com"},onMessage:u,onLoadEnd:S,javaScriptEnabled:!0,allowsInlineMediaPlayback:!0,allowsFileAccess:!0,domStorageEnabled:!0,mediaCapturePermissionGrantType:"grant"},initialized:d,startSession:()=>c("START_SESSION"),endSession:()=>c("END_SESSION"),sendMessage:n=>c("SEND_MESSAGE",{text:n}),toggleMute:()=>c("TOGGLE_MUTE"),keepSession:()=>c("KEEP_SESSION")}}(n,o)}function d(e){let{options:a,style:t,webviewProps:d}=e;const l=i(a,function(n,e){if(null==n)return{};var a={};for(var t in n)if({}.hasOwnProperty.call(n,t)){if(-1!==e.indexOf(t))continue;a[t]=n[t]}return a}(e,r));/*#__PURE__*/return n.createElement(o,s({ref:l.webViewRef},l.webViewProps,d,{style:t}))}export{d as UnithConversationView,i as useConversation};
1
+ import n,{useRef as e,useState as t,useCallback as a}from"react";import{WebView as o}from"react-native-webview";function s(){return s=Object.assign?Object.assign.bind():function(n){for(var e=1;e<arguments.length;e++){var t=arguments[e];for(var a in t)({}).hasOwnProperty.call(t,a)&&(n[a]=t[a])}return n},s.apply(null,arguments)}const r=["options","style","webviewProps","webClientUrl"];function i(n,o){return function(n,o){const r=e(null),i=e(!1),[d,l]=t(!1),c=a((n,e)=>{var t;null==(t=r.current)||t.postMessage(JSON.stringify({type:n,payload:e}))},[]),S=a(()=>{i.current||(i.current=!0,l(!0),setTimeout(()=>{c("INIT",s({},n))},100))},[n,c]),u=a(n=>{let e=null;try{e=JSON.parse(n.nativeEvent.data)}catch(n){return}if(e)switch(e.type){case"STATUS_CHANGE":null==o.onStatusChange||o.onStatusChange(e.payload);break;case"CONNECT":null==o.onConnect||o.onConnect(e.payload);break;case"DISCONNECT":null==o.onDisconnect||o.onDisconnect(e.payload);break;case"MESSAGE":null==o.onMessage||o.onMessage(e.payload);break;case"SUGGESTIONS":null==o.onSuggestions||o.onSuggestions(e.payload);break;case"SPEAKING_START":null==o.onSpeakingStart||o.onSpeakingStart();break;case"SPEAKING_END":null==o.onSpeakingEnd||o.onSpeakingEnd();break;case"TIMEOUT_WARNING":null==o.onTimeoutWarning||o.onTimeoutWarning();break;case"TIMEOUT":null==o.onTimeout||o.onTimeout();break;case"KEEP_SESSION":null==o.onKeepSession||o.onKeepSession(e.payload);break;case"MUTE_STATUS":null==o.onMuteStatusChange||o.onMuteStatusChange(e.payload);break;case"ERROR":null==o.onError||o.onError(e.payload)}},[o]);return{webViewRef:r,webViewProps:{source:{html:'<!doctype html>\n<html>\n <head>\n <meta charset="utf-8" />\n <meta name="viewport" content="width=device-width, initial-scale=1" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id="root"></div>\n <script type="module">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === "INIT") {\n try {\n const { Conversation } = await import("https://unpkg.com/@unith-ai/core-client@2.0.3-beta.3/dist/lib.web.js");\n\n if (!("VideoDecoder" in window)) {\n send("ERROR", {\n message: "WebCodecs VideoDecoder is not supported on this device.",\n type: "modal",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById("root");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: \'custom\',\n onStatusChange: (data) => send("STATUS_CHANGE", data),\n onConnect: (data) => send("CONNECT", data),\n onDisconnect: (data) => send("DISCONNECT", data),\n onMessage: (data) => send("MESSAGE", data),\n onSuggestions: (data) => send("SUGGESTIONS", data),\n onSpeakingStart: () => send("SPEAKING_START"),\n onSpeakingEnd: () => send("SPEAKING_END"),\n onTimeoutWarning: () => send("TIMEOUT_WARNING"),\n onTimeout: () => send("TIMEOUT"),\n onKeepSession: (data) => send("KEEP_SESSION", data),\n onMuteStatusChange: (data) => send("MUTE_STATUS", data),\n onError: (data) => send("ERROR", data), \n });\n\n ready = true;\n send("READY");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to process queued message",\n type: "notification",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to initialize conversation",\n type: "modal",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case "START_SESSION":\n await conversation.startSession();\n break;\n case "END_SESSION":\n await conversation.endSession();\n break;\n case "SEND_MESSAGE":\n await conversation.sendMessage(payload?.text || "");\n break; \n case "TOGGLE_MUTE":\n await conversation.toggleMute();\n break;\n case "KEEP_SESSION":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Operation failed",\n type: "notification",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== "INIT") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error("Failed to handle incoming message:", error);\n }\n };\n\n window.addEventListener("message", handleIncoming);\n document.addEventListener("message", handleIncoming);\n <\/script>\n </body>\n</html>',baseUrl:"https://unpkg.com"},onMessage:u,onLoadEnd:S,javaScriptEnabled:!0},initialized:d,startSession:()=>c("START_SESSION"),endSession:()=>c("END_SESSION"),sendMessage:n=>c("SEND_MESSAGE",{text:n}),toggleMute:()=>c("TOGGLE_MUTE"),keepSession:()=>c("KEEP_SESSION")}}(n,o)}function d(e){let{options:t,style:a,webviewProps:d}=e;const l=i(t,function(n,e){if(null==n)return{};var t={};for(var a in n)if({}.hasOwnProperty.call(n,a)){if(-1!==e.indexOf(a))continue;t[a]=n[a]}return t}(e,r));/*#__PURE__*/return n.createElement(o,s({ref:l.webViewRef},l.webViewProps,d,{style:a}))}export{d as UnithConversationView,i as useConversation};
2
2
  //# sourceMappingURL=lib.modern.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"lib.modern.mjs","sources":["../src/index.tsx"],"sourcesContent":["import { Status as StatusType, Mode as ModeType, ConversationEvents as ConversationEventsType, } from \"@unith-ai/core-client\";\nimport React, { useCallback, useRef, useState } from \"react\";\nimport { ViewStyle } from \"react-native\";\nimport { WebView, WebViewMessageEvent } from \"react-native-webview\";\n\nexport type ConversationOptions = {\n orgId: string;\n headId: string;\n apiKey: string;\n language?: string;\n username?: string;\n};\n\n\nexport type BridgeOptions = {\n webClientUrl?: string;\n webViewBaseUrl?: string;\n};\n\nexport type UseConversationResult = {\n webViewRef: React.RefObject<any>;\n webViewProps: Record<string, any>;\n initialized: boolean;\n startSession: () => void;\n endSession: () => void;\n sendMessage: (text: string) => void;\n toggleMute: () => void;\n keepSession: () => void;\n};\n\ntype BridgeMessage = {\n type: string;\n payload?: any;\n};\n\nconst DEFAULT_WEB_CLIENT_URL =\n \"https://unpkg.com/@unith-ai/core-client@2.0.3-beta.2/dist/lib.web.js\";\n\nfunction buildHtml(webClientUrl: string) {\n return `<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === \"INIT\") {\n try {\n const { Conversation } = await import(\"${webClientUrl}\");\n\n if (!(\"VideoDecoder\" in window)) {\n send(\"ERROR\", {\n message: \"WebCodecs VideoDecoder is not supported on this device.\",\n type: \"modal\",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById(\"root\");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: 'custom',\n onStatusChange: (data) => send(\"STATUS_CHANGE\", data),\n onConnect: (data) => send(\"CONNECT\", data),\n onDisconnect: (data) => send(\"DISCONNECT\", data),\n onMessage: (data) => send(\"MESSAGE\", data),\n onSuggestions: (data) => send(\"SUGGESTIONS\", data),\n onSpeakingStart: () => send(\"SPEAKING_START\"),\n onSpeakingEnd: () => send(\"SPEAKING_END\"),\n onTimeoutWarning: () => send(\"TIMEOUT_WARNING\"),\n onTimeout: () => send(\"TIMEOUT\"),\n onKeepSession: (data) => send(\"KEEP_SESSION\", data),\n onMuteStatusChange: (data) => send(\"MUTE_STATUS\", data),\n onError: (data) => send(\"ERROR\", data), \n });\n\n ready = true;\n send(\"READY\");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to process queued message\",\n type: \"notification\",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to initialize conversation\",\n type: \"modal\",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case \"START_SESSION\":\n await conversation.startSession();\n break;\n case \"END_SESSION\":\n await conversation.endSession();\n break;\n case \"SEND_MESSAGE\":\n await conversation.sendMessage(payload?.text || \"\");\n break; \n case \"TOGGLE_MUTE\":\n await conversation.toggleMute();\n break;\n case \"KEEP_SESSION\":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Operation failed\",\n type: \"notification\",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== \"INIT\") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error(\"Failed to handle incoming message:\", error);\n }\n };\n\n window.addEventListener(\"message\", handleIncoming);\n document.addEventListener(\"message\", handleIncoming);\n </script>\n </body>\n</html>`;\n}\n\nfunction useBridge(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n const webViewRef = useRef<any>(null);\n const initializedRef = useRef(false);\n const [initialized, setInitialized] = useState(false);\n\n const html = buildHtml(DEFAULT_WEB_CLIENT_URL)\n\n const post = useCallback((type: string, payload?: any) => {\n const message: BridgeMessage = { type, payload };\n webViewRef.current?.postMessage(JSON.stringify(message));\n }, []);\n\n const handleLoadEnd = useCallback(() => {\n if (initializedRef.current) {\n return;\n }\n\n\n initializedRef.current = true;\n setInitialized(true);\n\n // Add a small delay to ensure WebView is ready to receive messages\n setTimeout(() => {\n post(\"INIT\", {\n ...options,\n });\n }, 100);\n }, [options, post]);\n\n const onMessage = useCallback(\n (event: WebViewMessageEvent) => {\n let data: BridgeMessage | null = null;\n try {\n data = JSON.parse(event.nativeEvent.data);\n } catch (_) {\n return;\n }\n if (!data) return;\n\n switch (data.type) {\n case \"STATUS_CHANGE\":\n events.onStatusChange?.(data.payload);\n break;\n case \"CONNECT\":\n events.onConnect?.(data.payload);\n break;\n case \"DISCONNECT\":\n events.onDisconnect?.(data.payload);\n break;\n case \"MESSAGE\":\n events.onMessage?.(data.payload);\n break;\n case \"SUGGESTIONS\":\n events.onSuggestions?.(data.payload);\n break;\n case \"SPEAKING_START\":\n events.onSpeakingStart?.();\n break;\n case \"SPEAKING_END\":\n events.onSpeakingEnd?.();\n break;\n case \"TIMEOUT_WARNING\":\n events.onTimeoutWarning?.();\n break;\n case \"TIMEOUT\":\n events.onTimeout?.();\n break;\n case \"KEEP_SESSION\":\n events.onKeepSession?.(data.payload);\n break;\n case \"MUTE_STATUS\":\n events.onMuteStatusChange?.(data.payload);\n break;\n case \"ERROR\":\n events.onError?.(data.payload);\n break;\n default:\n break;\n }\n },\n [events]\n );\n\n return {\n webViewRef,\n webViewProps: {\n source: { html, baseUrl: \"https://unpkg.com\" },\n onMessage,\n onLoadEnd: handleLoadEnd,\n javaScriptEnabled: true,\n allowsInlineMediaPlayback: true,\n allowsFileAccess: true,\n domStorageEnabled: true,\n mediaCapturePermissionGrantType: 'grant',\n },\n initialized,\n startSession: () => post(\"START_SESSION\"),\n endSession: () => post(\"END_SESSION\"),\n sendMessage: (text: string) => post(\"SEND_MESSAGE\", { text }),\n toggleMute: () => post(\"TOGGLE_MUTE\"),\n keepSession: () => post(\"KEEP_SESSION\"),\n };\n}\n\nexport function useConversation(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n return useBridge(options, events,);\n}\n\n\nexport type UnithConversationViewProps = ConversationEventsType\n & {\n options: ConversationOptions;\n style?: ViewStyle;\n webviewProps?: Record<string, any>;\n webClientUrl?: string;\n };\n\n\nexport type Status = StatusType;\nexport type Mode = ModeType;\nexport type ConversationEvents = ConversationEventsType;\n\n\nexport function UnithConversationView({\n options,\n style,\n webviewProps,\n webClientUrl,\n ...events\n}: UnithConversationViewProps) {\n const convo = useConversation(options, events);\n\n return (\n <WebView\n ref={convo.webViewRef}\n {...convo.webViewProps}\n {...webviewProps}\n style={style}\n />\n );\n}\n"],"names":["_excluded","useConversation","options","events","webViewRef","useRef","initializedRef","initialized","setInitialized","useState","post","useCallback","type","payload","_webViewRef$current","current","postMessage","JSON","stringify","handleLoadEnd","setTimeout","_extends","onMessage","event","data","parse","nativeEvent","_","onStatusChange","onConnect","onDisconnect","onSuggestions","onSpeakingStart","onSpeakingEnd","onTimeoutWarning","onTimeout","onKeepSession","onMuteStatusChange","onError","webViewProps","source","html","baseUrl","onLoadEnd","javaScriptEnabled","allowsInlineMediaPlayback","allowsFileAccess","domStorageEnabled","mediaCapturePermissionGrantType","startSession","endSession","sendMessage","text","toggleMute","keepSession","useBridge","UnithConversationView","_ref","style","webviewProps","convo","_objectWithoutPropertiesLoose","React","WebView","ref"],"mappings":"wUACA,MAAAA,EAAA,CAAA,UAAA,QAAA,eAAA,gBAuRgB,SAAAC,EACdC,EACAC,GAEA,OA/GF,SACED,EACAC,GAEA,MAAMC,EAAaC,EAAY,MACzBC,EAAiBD,GAAO,IACvBE,EAAaC,GAAkBC,GAAS,GAIzCC,EAAOC,EAAY,CAACC,EAAcC,KAAiB,IAAAC,EAEvDA,OAAAA,EAAAV,EAAWW,UAAXD,EAAoBE,YAAYC,KAAKC,UADN,CAAEN,OAAMC,cAEtC,IAEGM,EAAgBR,EAAY,KAC5BL,EAAeS,UAKnBT,EAAeS,SAAU,EACzBP,GAAe,GAGfY,WAAW,KACTV,EAAK,OAAMW,EAAA,CAAA,EACNnB,KAEJ,OACF,CAACA,EAASQ,IAEPY,EAAYX,EACfY,IACC,IAAIC,EAA6B,KACjC,IACEA,EAAOP,KAAKQ,MAAMF,EAAMG,YAAYF,KACtC,CAAE,MAAOG,GACP,MACF,CACA,GAAKH,EAEL,OAAQA,EAAKZ,MACX,IAAK,gBACkB,MAArBT,EAAOyB,gBAAPzB,EAAOyB,eAAiBJ,EAAKX,SAC7B,MACF,IAAK,UACHV,MAAAA,EAAO0B,WAAP1B,EAAO0B,UAAYL,EAAKX,SACxB,MACF,IAAK,aACgB,MAAnBV,EAAO2B,cAAP3B,EAAO2B,aAAeN,EAAKX,SAC3B,MACF,IAAK,UACHV,MAAAA,EAAOmB,WAAPnB,EAAOmB,UAAYE,EAAKX,SACxB,MACF,IAAK,cACiB,MAApBV,EAAO4B,eAAP5B,EAAO4B,cAAgBP,EAAKX,SAC5B,MACF,IAAK,iBACmB,MAAtBV,EAAO6B,iBAAP7B,EAAO6B,kBACP,MACF,IAAK,eACH7B,MAAAA,EAAO8B,eAAP9B,EAAO8B,gBACP,MACF,IAAK,kBACH9B,MAAAA,EAAO+B,kBAAP/B,EAAO+B,mBACP,MACF,IAAK,UACa,MAAhB/B,EAAOgC,WAAPhC,EAAOgC,YACP,MACF,IAAK,eACiB,MAApBhC,EAAOiC,eAAPjC,EAAOiC,cAAgBZ,EAAKX,SAC5B,MACF,IAAK,cACHV,MAAAA,EAAOkC,oBAAPlC,EAAOkC,mBAAqBb,EAAKX,SACjC,MACF,IAAK,QACW,MAAdV,EAAOmC,SAAPnC,EAAOmC,QAAUd,EAAKX,WAM5B,CAACV,IAGH,MAAO,CACLC,aACAmC,aAAc,CACZC,OAAQ,CAAEC,KA/NP,23IA+NaC,QAAS,qBACzBpB,YACAqB,UAAWxB,EACXyB,mBAAmB,EACnBC,2BAA2B,EAC3BC,kBAAkB,EAClBC,mBAAmB,EACnBC,gCAAiC,SAEnCzC,cACA0C,aAAcA,IAAMvC,EAAK,iBACzBwC,WAAYA,IAAMxC,EAAK,eACvByC,YAAcC,GAAiB1C,EAAK,eAAgB,CAAE0C,SACtDC,WAAYA,IAAM3C,EAAK,eACvB4C,YAAaA,IAAM5C,EAAK,gBAE5B,CAMS6C,CAAUrD,EAASC,EAC5B,CAiBgB,SAAAqD,EAAqBC,GAAC,IAAAvD,QACpCA,EAAOwD,MACPA,EAAKC,aACLA,GAG2BF,EAC3B,MAAMG,EAAQ3D,EAAgBC,6IAFrB2D,CAAAJ,EAAAzD,iBAIT,OACE8D,gBAACC,EAAO1C,EACN2C,CAAAA,IAAKJ,EAAMxD,YACPwD,EAAMrB,aACNoB,EACJD,CAAAA,MAAOA,IAGb"}
1
+ {"version":3,"file":"lib.modern.mjs","sources":["../src/index.tsx"],"sourcesContent":["import { Status as StatusType, Mode as ModeType, ConversationEvents as ConversationEventsType, } from \"@unith-ai/core-client\";\nimport React, { useCallback, useRef, useState } from \"react\";\nimport { ViewStyle } from \"react-native\";\nimport { WebView, WebViewMessageEvent } from \"react-native-webview\";\n\nexport type ConversationOptions = {\n orgId: string;\n headId: string;\n apiKey: string;\n language?: string;\n username?: string;\n};\n\n\nexport type BridgeOptions = {\n webClientUrl?: string;\n webViewBaseUrl?: string;\n};\n\nexport type UseConversationResult = {\n webViewRef: React.RefObject<any>;\n webViewProps: Record<string, any>;\n initialized: boolean;\n startSession: () => void;\n endSession: () => void;\n sendMessage: (text: string) => void;\n toggleMute: () => void;\n keepSession: () => void;\n};\n\ntype BridgeMessage = {\n type: string;\n payload?: any;\n};\n\nconst DEFAULT_WEB_CLIENT_URL =\n \"https://unpkg.com/@unith-ai/core-client@2.0.3-beta.3/dist/lib.web.js\";\n\nfunction buildHtml(webClientUrl: string) {\n return `<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === \"INIT\") {\n try {\n const { Conversation } = await import(\"${webClientUrl}\");\n\n if (!(\"VideoDecoder\" in window)) {\n send(\"ERROR\", {\n message: \"WebCodecs VideoDecoder is not supported on this device.\",\n type: \"modal\",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById(\"root\");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: 'custom',\n onStatusChange: (data) => send(\"STATUS_CHANGE\", data),\n onConnect: (data) => send(\"CONNECT\", data),\n onDisconnect: (data) => send(\"DISCONNECT\", data),\n onMessage: (data) => send(\"MESSAGE\", data),\n onSuggestions: (data) => send(\"SUGGESTIONS\", data),\n onSpeakingStart: () => send(\"SPEAKING_START\"),\n onSpeakingEnd: () => send(\"SPEAKING_END\"),\n onTimeoutWarning: () => send(\"TIMEOUT_WARNING\"),\n onTimeout: () => send(\"TIMEOUT\"),\n onKeepSession: (data) => send(\"KEEP_SESSION\", data),\n onMuteStatusChange: (data) => send(\"MUTE_STATUS\", data),\n onError: (data) => send(\"ERROR\", data), \n });\n\n ready = true;\n send(\"READY\");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to process queued message\",\n type: \"notification\",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to initialize conversation\",\n type: \"modal\",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case \"START_SESSION\":\n await conversation.startSession();\n break;\n case \"END_SESSION\":\n await conversation.endSession();\n break;\n case \"SEND_MESSAGE\":\n await conversation.sendMessage(payload?.text || \"\");\n break; \n case \"TOGGLE_MUTE\":\n await conversation.toggleMute();\n break;\n case \"KEEP_SESSION\":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Operation failed\",\n type: \"notification\",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== \"INIT\") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error(\"Failed to handle incoming message:\", error);\n }\n };\n\n window.addEventListener(\"message\", handleIncoming);\n document.addEventListener(\"message\", handleIncoming);\n </script>\n </body>\n</html>`;\n}\n\nfunction useBridge(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n const webViewRef = useRef<any>(null);\n const initializedRef = useRef(false);\n const [initialized, setInitialized] = useState(false);\n\n const html = buildHtml(DEFAULT_WEB_CLIENT_URL)\n\n const post = useCallback((type: string, payload?: any) => {\n const message: BridgeMessage = { type, payload };\n webViewRef.current?.postMessage(JSON.stringify(message));\n }, []);\n\n const handleLoadEnd = useCallback(() => {\n if (initializedRef.current) {\n return;\n }\n\n\n initializedRef.current = true;\n setInitialized(true);\n\n // Add a small delay to ensure WebView is ready to receive messages\n setTimeout(() => {\n post(\"INIT\", {\n ...options,\n });\n }, 100);\n }, [options, post]);\n\n const onMessage = useCallback(\n (event: WebViewMessageEvent) => {\n let data: BridgeMessage | null = null;\n try {\n data = JSON.parse(event.nativeEvent.data);\n } catch (_) {\n return;\n }\n if (!data) return;\n\n switch (data.type) {\n case \"STATUS_CHANGE\":\n events.onStatusChange?.(data.payload);\n break;\n case \"CONNECT\":\n events.onConnect?.(data.payload);\n break;\n case \"DISCONNECT\":\n events.onDisconnect?.(data.payload);\n break;\n case \"MESSAGE\":\n events.onMessage?.(data.payload);\n break;\n case \"SUGGESTIONS\":\n events.onSuggestions?.(data.payload);\n break;\n case \"SPEAKING_START\":\n events.onSpeakingStart?.();\n break;\n case \"SPEAKING_END\":\n events.onSpeakingEnd?.();\n break;\n case \"TIMEOUT_WARNING\":\n events.onTimeoutWarning?.();\n break;\n case \"TIMEOUT\":\n events.onTimeout?.();\n break;\n case \"KEEP_SESSION\":\n events.onKeepSession?.(data.payload);\n break;\n case \"MUTE_STATUS\":\n events.onMuteStatusChange?.(data.payload);\n break;\n case \"ERROR\":\n events.onError?.(data.payload);\n break;\n default:\n break;\n }\n },\n [events]\n );\n\n return {\n webViewRef,\n webViewProps: {\n source: { html, baseUrl: \"https://unpkg.com\" },\n onMessage,\n onLoadEnd: handleLoadEnd,\n javaScriptEnabled: true,\n },\n initialized,\n startSession: () => post(\"START_SESSION\"),\n endSession: () => post(\"END_SESSION\"),\n sendMessage: (text: string) => post(\"SEND_MESSAGE\", { text }),\n toggleMute: () => post(\"TOGGLE_MUTE\"),\n keepSession: () => post(\"KEEP_SESSION\"),\n };\n}\n\nexport function useConversation(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n return useBridge(options, events,);\n}\n\n\nexport type UnithConversationViewProps = ConversationEventsType\n & {\n options: ConversationOptions;\n style?: ViewStyle;\n webviewProps?: Record<string, any>;\n webClientUrl?: string;\n };\n\n\nexport type Status = StatusType;\nexport type Mode = ModeType;\nexport type ConversationEvents = ConversationEventsType;\n\n\nexport function UnithConversationView({\n options,\n style,\n webviewProps,\n webClientUrl,\n ...events\n}: UnithConversationViewProps) {\n const convo = useConversation(options, events);\n\n return (\n <WebView\n ref={convo.webViewRef}\n {...convo.webViewProps}\n {...webviewProps}\n style={style}\n />\n );\n}\n"],"names":["_excluded","useConversation","options","events","webViewRef","useRef","initializedRef","initialized","setInitialized","useState","post","useCallback","type","payload","_webViewRef$current","current","postMessage","JSON","stringify","handleLoadEnd","setTimeout","_extends","onMessage","event","data","parse","nativeEvent","_","onStatusChange","onConnect","onDisconnect","onSuggestions","onSpeakingStart","onSpeakingEnd","onTimeoutWarning","onTimeout","onKeepSession","onMuteStatusChange","onError","webViewProps","source","html","baseUrl","onLoadEnd","javaScriptEnabled","startSession","endSession","sendMessage","text","toggleMute","keepSession","useBridge","UnithConversationView","_ref","style","webviewProps","convo","_objectWithoutPropertiesLoose","React","WebView","ref"],"mappings":"wUACA,MAAAA,EAAA,CAAA,UAAA,QAAA,eAAA,gBAmRgB,SAAAC,EACdC,EACAC,GAEA,OA3GF,SACED,EACAC,GAEA,MAAMC,EAAaC,EAAY,MACzBC,EAAiBD,GAAO,IACvBE,EAAaC,GAAkBC,GAAS,GAIzCC,EAAOC,EAAY,CAACC,EAAcC,KAAiB,IAAAC,EAErC,OAAlBA,EAAAV,EAAWW,UAAXD,EAAoBE,YAAYC,KAAKC,UADN,CAAEN,OAAMC,cAEtC,IAEGM,EAAgBR,EAAY,KAC5BL,EAAeS,UAKnBT,EAAeS,SAAU,EACzBP,GAAe,GAGfY,WAAW,KACTV,EAAK,OAAMW,EAAA,CAAA,EACNnB,KAEJ,OACF,CAACA,EAASQ,IAEPY,EAAYX,EACfY,IACC,IAAIC,EAA6B,KACjC,IACEA,EAAOP,KAAKQ,MAAMF,EAAMG,YAAYF,KACtC,CAAE,MAAOG,GACP,MACF,CACA,GAAKH,EAEL,OAAQA,EAAKZ,MACX,IAAK,gBACHT,MAAAA,EAAOyB,gBAAPzB,EAAOyB,eAAiBJ,EAAKX,SAC7B,MACF,IAAK,UACHV,MAAAA,EAAO0B,WAAP1B,EAAO0B,UAAYL,EAAKX,SACxB,MACF,IAAK,aACgB,MAAnBV,EAAO2B,cAAP3B,EAAO2B,aAAeN,EAAKX,SAC3B,MACF,IAAK,UACHV,MAAAA,EAAOmB,WAAPnB,EAAOmB,UAAYE,EAAKX,SACxB,MACF,IAAK,cACiB,MAApBV,EAAO4B,eAAP5B,EAAO4B,cAAgBP,EAAKX,SAC5B,MACF,IAAK,iBACmB,MAAtBV,EAAO6B,iBAAP7B,EAAO6B,kBACP,MACF,IAAK,eACH7B,MAAAA,EAAO8B,eAAP9B,EAAO8B,gBACP,MACF,IAAK,kBACH9B,MAAAA,EAAO+B,kBAAP/B,EAAO+B,mBACP,MACF,IAAK,gBACH/B,EAAOgC,WAAPhC,EAAOgC,YACP,MACF,IAAK,eACHhC,MAAAA,EAAOiC,eAAPjC,EAAOiC,cAAgBZ,EAAKX,SAC5B,MACF,IAAK,cACHV,MAAAA,EAAOkC,oBAAPlC,EAAOkC,mBAAqBb,EAAKX,SACjC,MACF,IAAK,QACW,MAAdV,EAAOmC,SAAPnC,EAAOmC,QAAUd,EAAKX,WAM5B,CAACV,IAGH,MAAO,CACLC,aACAmC,aAAc,CACZC,OAAQ,CAAEC,KA/NP,23IA+NaC,QAAS,qBACzBpB,YACAqB,UAAWxB,EACXyB,mBAAmB,GAErBrC,cACAsC,aAAcA,IAAMnC,EAAK,iBACzBoC,WAAYA,IAAMpC,EAAK,eACvBqC,YAAcC,GAAiBtC,EAAK,eAAgB,CAAEsC,SACtDC,WAAYA,IAAMvC,EAAK,eACvBwC,YAAaA,IAAMxC,EAAK,gBAE5B,CAMSyC,CAAUjD,EAASC,EAC5B,CAiBgB,SAAAiD,EAAqBC,OAACnD,QACpCA,EAAOoD,MACPA,EAAKC,aACLA,GAG2BF,EAC3B,MAAMG,EAAQvD,EAAgBC,6IAFrBuD,CAAAJ,EAAArD,iBAIT,OACE0D,gBAACC,EAAOtC,EAAA,CACNuC,IAAKJ,EAAMpD,YACPoD,EAAMjB,aACNgB,EACJD,CAAAA,MAAOA,IAGb"}
@@ -1,2 +1,2 @@
1
- import n,{useRef as e,useState as t,useCallback as a}from"react";import{WebView as o}from"react-native-webview";function s(){return s=Object.assign?Object.assign.bind():function(n){for(var e=1;e<arguments.length;e++){var t=arguments[e];for(var a in t)({}).hasOwnProperty.call(t,a)&&(n[a]=t[a])}return n},s.apply(null,arguments)}var r=["options","style","webviewProps","webClientUrl"];function i(n,o){return function(n,o){var r=e(null),i=e(!1),d=t(!1),c=d[0],l=d[1],u=a(function(n,e){var t;null==(t=r.current)||t.postMessage(JSON.stringify({type:n,payload:e}))},[]),S=a(function(){i.current||(i.current=!0,l(!0),setTimeout(function(){u("INIT",s({},n))},100))},[n,u]),p=a(function(n){var e=null;try{e=JSON.parse(n.nativeEvent.data)}catch(n){return}if(e)switch(e.type){case"STATUS_CHANGE":null==o.onStatusChange||o.onStatusChange(e.payload);break;case"CONNECT":null==o.onConnect||o.onConnect(e.payload);break;case"DISCONNECT":null==o.onDisconnect||o.onDisconnect(e.payload);break;case"MESSAGE":null==o.onMessage||o.onMessage(e.payload);break;case"SUGGESTIONS":null==o.onSuggestions||o.onSuggestions(e.payload);break;case"SPEAKING_START":null==o.onSpeakingStart||o.onSpeakingStart();break;case"SPEAKING_END":null==o.onSpeakingEnd||o.onSpeakingEnd();break;case"TIMEOUT_WARNING":null==o.onTimeoutWarning||o.onTimeoutWarning();break;case"TIMEOUT":null==o.onTimeout||o.onTimeout();break;case"KEEP_SESSION":null==o.onKeepSession||o.onKeepSession(e.payload);break;case"MUTE_STATUS":null==o.onMuteStatusChange||o.onMuteStatusChange(e.payload);break;case"ERROR":null==o.onError||o.onError(e.payload)}},[o]);return{webViewRef:r,webViewProps:{source:{html:'<!doctype html>\n<html>\n <head>\n <meta charset="utf-8" />\n <meta name="viewport" content="width=device-width, initial-scale=1" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id="root"></div>\n <script type="module">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === "INIT") {\n try {\n const { Conversation } = await import("https://unpkg.com/@unith-ai/core-client@2.0.3-beta.2/dist/lib.web.js");\n\n if (!("VideoDecoder" in window)) {\n send("ERROR", {\n message: "WebCodecs VideoDecoder is not supported on this device.",\n type: "modal",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById("root");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: \'custom\',\n onStatusChange: (data) => send("STATUS_CHANGE", data),\n onConnect: (data) => send("CONNECT", data),\n onDisconnect: (data) => send("DISCONNECT", data),\n onMessage: (data) => send("MESSAGE", data),\n onSuggestions: (data) => send("SUGGESTIONS", data),\n onSpeakingStart: () => send("SPEAKING_START"),\n onSpeakingEnd: () => send("SPEAKING_END"),\n onTimeoutWarning: () => send("TIMEOUT_WARNING"),\n onTimeout: () => send("TIMEOUT"),\n onKeepSession: (data) => send("KEEP_SESSION", data),\n onMuteStatusChange: (data) => send("MUTE_STATUS", data),\n onError: (data) => send("ERROR", data), \n });\n\n ready = true;\n send("READY");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to process queued message",\n type: "notification",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to initialize conversation",\n type: "modal",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case "START_SESSION":\n await conversation.startSession();\n break;\n case "END_SESSION":\n await conversation.endSession();\n break;\n case "SEND_MESSAGE":\n await conversation.sendMessage(payload?.text || "");\n break; \n case "TOGGLE_MUTE":\n await conversation.toggleMute();\n break;\n case "KEEP_SESSION":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Operation failed",\n type: "notification",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== "INIT") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error("Failed to handle incoming message:", error);\n }\n };\n\n window.addEventListener("message", handleIncoming);\n document.addEventListener("message", handleIncoming);\n <\/script>\n </body>\n</html>',baseUrl:"https://unpkg.com"},onMessage:p,onLoadEnd:S,javaScriptEnabled:!0,allowsInlineMediaPlayback:!0,allowsFileAccess:!0,domStorageEnabled:!0,mediaCapturePermissionGrantType:"grant"},initialized:c,startSession:function(){return u("START_SESSION")},endSession:function(){return u("END_SESSION")},sendMessage:function(n){return u("SEND_MESSAGE",{text:n})},toggleMute:function(){return u("TOGGLE_MUTE")},keepSession:function(){return u("KEEP_SESSION")}}}(n,o)}function d(e){var t=e.style,a=e.webviewProps,d=i(e.options,function(n,e){if(null==n)return{};var t={};for(var a in n)if({}.hasOwnProperty.call(n,a)){if(-1!==e.indexOf(a))continue;t[a]=n[a]}return t}(e,r));/*#__PURE__*/return n.createElement(o,s({ref:d.webViewRef},d.webViewProps,a,{style:t}))}export{d as UnithConversationView,i as useConversation};
1
+ import n,{useRef as e,useState as t,useCallback as a}from"react";import{WebView as o}from"react-native-webview";function s(){return s=Object.assign?Object.assign.bind():function(n){for(var e=1;e<arguments.length;e++){var t=arguments[e];for(var a in t)({}).hasOwnProperty.call(t,a)&&(n[a]=t[a])}return n},s.apply(null,arguments)}var r=["options","style","webviewProps","webClientUrl"];function i(n,o){return function(n,o){var r=e(null),i=e(!1),d=t(!1),c=d[0],l=d[1],u=a(function(n,e){var t;null==(t=r.current)||t.postMessage(JSON.stringify({type:n,payload:e}))},[]),S=a(function(){i.current||(i.current=!0,l(!0),setTimeout(function(){u("INIT",s({},n))},100))},[n,u]),p=a(function(n){var e=null;try{e=JSON.parse(n.nativeEvent.data)}catch(n){return}if(e)switch(e.type){case"STATUS_CHANGE":null==o.onStatusChange||o.onStatusChange(e.payload);break;case"CONNECT":null==o.onConnect||o.onConnect(e.payload);break;case"DISCONNECT":null==o.onDisconnect||o.onDisconnect(e.payload);break;case"MESSAGE":null==o.onMessage||o.onMessage(e.payload);break;case"SUGGESTIONS":null==o.onSuggestions||o.onSuggestions(e.payload);break;case"SPEAKING_START":null==o.onSpeakingStart||o.onSpeakingStart();break;case"SPEAKING_END":null==o.onSpeakingEnd||o.onSpeakingEnd();break;case"TIMEOUT_WARNING":null==o.onTimeoutWarning||o.onTimeoutWarning();break;case"TIMEOUT":null==o.onTimeout||o.onTimeout();break;case"KEEP_SESSION":null==o.onKeepSession||o.onKeepSession(e.payload);break;case"MUTE_STATUS":null==o.onMuteStatusChange||o.onMuteStatusChange(e.payload);break;case"ERROR":null==o.onError||o.onError(e.payload)}},[o]);return{webViewRef:r,webViewProps:{source:{html:'<!doctype html>\n<html>\n <head>\n <meta charset="utf-8" />\n <meta name="viewport" content="width=device-width, initial-scale=1" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id="root"></div>\n <script type="module">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === "INIT") {\n try {\n const { Conversation } = await import("https://unpkg.com/@unith-ai/core-client@2.0.3-beta.3/dist/lib.web.js");\n\n if (!("VideoDecoder" in window)) {\n send("ERROR", {\n message: "WebCodecs VideoDecoder is not supported on this device.",\n type: "modal",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById("root");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: \'custom\',\n onStatusChange: (data) => send("STATUS_CHANGE", data),\n onConnect: (data) => send("CONNECT", data),\n onDisconnect: (data) => send("DISCONNECT", data),\n onMessage: (data) => send("MESSAGE", data),\n onSuggestions: (data) => send("SUGGESTIONS", data),\n onSpeakingStart: () => send("SPEAKING_START"),\n onSpeakingEnd: () => send("SPEAKING_END"),\n onTimeoutWarning: () => send("TIMEOUT_WARNING"),\n onTimeout: () => send("TIMEOUT"),\n onKeepSession: (data) => send("KEEP_SESSION", data),\n onMuteStatusChange: (data) => send("MUTE_STATUS", data),\n onError: (data) => send("ERROR", data), \n });\n\n ready = true;\n send("READY");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to process queued message",\n type: "notification",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to initialize conversation",\n type: "modal",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case "START_SESSION":\n await conversation.startSession();\n break;\n case "END_SESSION":\n await conversation.endSession();\n break;\n case "SEND_MESSAGE":\n await conversation.sendMessage(payload?.text || "");\n break; \n case "TOGGLE_MUTE":\n await conversation.toggleMute();\n break;\n case "KEEP_SESSION":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Operation failed",\n type: "notification",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== "INIT") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error("Failed to handle incoming message:", error);\n }\n };\n\n window.addEventListener("message", handleIncoming);\n document.addEventListener("message", handleIncoming);\n <\/script>\n </body>\n</html>',baseUrl:"https://unpkg.com"},onMessage:p,onLoadEnd:S,javaScriptEnabled:!0},initialized:c,startSession:function(){return u("START_SESSION")},endSession:function(){return u("END_SESSION")},sendMessage:function(n){return u("SEND_MESSAGE",{text:n})},toggleMute:function(){return u("TOGGLE_MUTE")},keepSession:function(){return u("KEEP_SESSION")}}}(n,o)}function d(e){var t=e.style,a=e.webviewProps,d=i(e.options,function(n,e){if(null==n)return{};var t={};for(var a in n)if({}.hasOwnProperty.call(n,a)){if(-1!==e.indexOf(a))continue;t[a]=n[a]}return t}(e,r));/*#__PURE__*/return n.createElement(o,s({ref:d.webViewRef},d.webViewProps,a,{style:t}))}export{d as UnithConversationView,i as useConversation};
2
2
  //# sourceMappingURL=lib.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lib.module.js","sources":["../src/index.tsx"],"sourcesContent":["import { Status as StatusType, Mode as ModeType, ConversationEvents as ConversationEventsType, } from \"@unith-ai/core-client\";\nimport React, { useCallback, useRef, useState } from \"react\";\nimport { ViewStyle } from \"react-native\";\nimport { WebView, WebViewMessageEvent } from \"react-native-webview\";\n\nexport type ConversationOptions = {\n orgId: string;\n headId: string;\n apiKey: string;\n language?: string;\n username?: string;\n};\n\n\nexport type BridgeOptions = {\n webClientUrl?: string;\n webViewBaseUrl?: string;\n};\n\nexport type UseConversationResult = {\n webViewRef: React.RefObject<any>;\n webViewProps: Record<string, any>;\n initialized: boolean;\n startSession: () => void;\n endSession: () => void;\n sendMessage: (text: string) => void;\n toggleMute: () => void;\n keepSession: () => void;\n};\n\ntype BridgeMessage = {\n type: string;\n payload?: any;\n};\n\nconst DEFAULT_WEB_CLIENT_URL =\n \"https://unpkg.com/@unith-ai/core-client@2.0.3-beta.2/dist/lib.web.js\";\n\nfunction buildHtml(webClientUrl: string) {\n return `<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === \"INIT\") {\n try {\n const { Conversation } = await import(\"${webClientUrl}\");\n\n if (!(\"VideoDecoder\" in window)) {\n send(\"ERROR\", {\n message: \"WebCodecs VideoDecoder is not supported on this device.\",\n type: \"modal\",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById(\"root\");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: 'custom',\n onStatusChange: (data) => send(\"STATUS_CHANGE\", data),\n onConnect: (data) => send(\"CONNECT\", data),\n onDisconnect: (data) => send(\"DISCONNECT\", data),\n onMessage: (data) => send(\"MESSAGE\", data),\n onSuggestions: (data) => send(\"SUGGESTIONS\", data),\n onSpeakingStart: () => send(\"SPEAKING_START\"),\n onSpeakingEnd: () => send(\"SPEAKING_END\"),\n onTimeoutWarning: () => send(\"TIMEOUT_WARNING\"),\n onTimeout: () => send(\"TIMEOUT\"),\n onKeepSession: (data) => send(\"KEEP_SESSION\", data),\n onMuteStatusChange: (data) => send(\"MUTE_STATUS\", data),\n onError: (data) => send(\"ERROR\", data), \n });\n\n ready = true;\n send(\"READY\");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to process queued message\",\n type: \"notification\",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to initialize conversation\",\n type: \"modal\",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case \"START_SESSION\":\n await conversation.startSession();\n break;\n case \"END_SESSION\":\n await conversation.endSession();\n break;\n case \"SEND_MESSAGE\":\n await conversation.sendMessage(payload?.text || \"\");\n break; \n case \"TOGGLE_MUTE\":\n await conversation.toggleMute();\n break;\n case \"KEEP_SESSION\":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Operation failed\",\n type: \"notification\",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== \"INIT\") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error(\"Failed to handle incoming message:\", error);\n }\n };\n\n window.addEventListener(\"message\", handleIncoming);\n document.addEventListener(\"message\", handleIncoming);\n </script>\n </body>\n</html>`;\n}\n\nfunction useBridge(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n const webViewRef = useRef<any>(null);\n const initializedRef = useRef(false);\n const [initialized, setInitialized] = useState(false);\n\n const html = buildHtml(DEFAULT_WEB_CLIENT_URL)\n\n const post = useCallback((type: string, payload?: any) => {\n const message: BridgeMessage = { type, payload };\n webViewRef.current?.postMessage(JSON.stringify(message));\n }, []);\n\n const handleLoadEnd = useCallback(() => {\n if (initializedRef.current) {\n return;\n }\n\n\n initializedRef.current = true;\n setInitialized(true);\n\n // Add a small delay to ensure WebView is ready to receive messages\n setTimeout(() => {\n post(\"INIT\", {\n ...options,\n });\n }, 100);\n }, [options, post]);\n\n const onMessage = useCallback(\n (event: WebViewMessageEvent) => {\n let data: BridgeMessage | null = null;\n try {\n data = JSON.parse(event.nativeEvent.data);\n } catch (_) {\n return;\n }\n if (!data) return;\n\n switch (data.type) {\n case \"STATUS_CHANGE\":\n events.onStatusChange?.(data.payload);\n break;\n case \"CONNECT\":\n events.onConnect?.(data.payload);\n break;\n case \"DISCONNECT\":\n events.onDisconnect?.(data.payload);\n break;\n case \"MESSAGE\":\n events.onMessage?.(data.payload);\n break;\n case \"SUGGESTIONS\":\n events.onSuggestions?.(data.payload);\n break;\n case \"SPEAKING_START\":\n events.onSpeakingStart?.();\n break;\n case \"SPEAKING_END\":\n events.onSpeakingEnd?.();\n break;\n case \"TIMEOUT_WARNING\":\n events.onTimeoutWarning?.();\n break;\n case \"TIMEOUT\":\n events.onTimeout?.();\n break;\n case \"KEEP_SESSION\":\n events.onKeepSession?.(data.payload);\n break;\n case \"MUTE_STATUS\":\n events.onMuteStatusChange?.(data.payload);\n break;\n case \"ERROR\":\n events.onError?.(data.payload);\n break;\n default:\n break;\n }\n },\n [events]\n );\n\n return {\n webViewRef,\n webViewProps: {\n source: { html, baseUrl: \"https://unpkg.com\" },\n onMessage,\n onLoadEnd: handleLoadEnd,\n javaScriptEnabled: true,\n allowsInlineMediaPlayback: true,\n allowsFileAccess: true,\n domStorageEnabled: true,\n mediaCapturePermissionGrantType: 'grant',\n },\n initialized,\n startSession: () => post(\"START_SESSION\"),\n endSession: () => post(\"END_SESSION\"),\n sendMessage: (text: string) => post(\"SEND_MESSAGE\", { text }),\n toggleMute: () => post(\"TOGGLE_MUTE\"),\n keepSession: () => post(\"KEEP_SESSION\"),\n };\n}\n\nexport function useConversation(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n return useBridge(options, events,);\n}\n\n\nexport type UnithConversationViewProps = ConversationEventsType\n & {\n options: ConversationOptions;\n style?: ViewStyle;\n webviewProps?: Record<string, any>;\n webClientUrl?: string;\n };\n\n\nexport type Status = StatusType;\nexport type Mode = ModeType;\nexport type ConversationEvents = ConversationEventsType;\n\n\nexport function UnithConversationView({\n options,\n style,\n webviewProps,\n webClientUrl,\n ...events\n}: UnithConversationViewProps) {\n const convo = useConversation(options, events);\n\n return (\n <WebView\n ref={convo.webViewRef}\n {...convo.webViewProps}\n {...webviewProps}\n style={style}\n />\n );\n}\n"],"names":["_excluded","useConversation","options","events","webViewRef","useRef","initializedRef","_useState","useState","initialized","setInitialized","post","useCallback","type","payload","_webViewRef$current","current","postMessage","JSON","stringify","handleLoadEnd","setTimeout","_extends","onMessage","event","data","parse","nativeEvent","_","onStatusChange","onConnect","onDisconnect","onSuggestions","onSpeakingStart","onSpeakingEnd","onTimeoutWarning","onTimeout","onKeepSession","onMuteStatusChange","onError","webViewProps","source","html","baseUrl","onLoadEnd","javaScriptEnabled","allowsInlineMediaPlayback","allowsFileAccess","domStorageEnabled","mediaCapturePermissionGrantType","startSession","endSession","sendMessage","text","toggleMute","keepSession","useBridge","UnithConversationView","_ref","style","webviewProps","convo","_objectWithoutPropertiesLoose","React","WebView","ref"],"mappings":"wUACA,IAAAA,EAAA,CAAA,UAAA,QAAA,eAAA,gBAuRgB,SAAAC,EACdC,EACAC,GAEA,OA/GF,SACED,EACAC,GAEA,IAAMC,EAAaC,EAAY,MACzBC,EAAiBD,GAAO,GAC9BE,EAAsCC,GAAS,GAAxCC,EAAWF,EAAA,GAAEG,EAAcH,KAI5BI,EAAOC,EAAY,SAACC,EAAcC,GAAiBC,IAAAA,SAEvDA,EAAAX,EAAWY,UAAXD,EAAoBE,YAAYC,KAAKC,UADN,CAAEN,KAAAA,EAAMC,QAAAA,IAEzC,EAAG,IAEGM,EAAgBR,EAAY,WAC5BN,EAAeU,UAKnBV,EAAeU,SAAU,EACzBN,GAAe,GAGfW,WAAW,WACTV,EAAK,OAAMW,EACNpB,CAAAA,EAAAA,GAEP,EAAG,KACL,EAAG,CAACA,EAASS,IAEPY,EAAYX,EAChB,SAACY,GACC,IAAIC,EAA6B,KACjC,IACEA,EAAOP,KAAKQ,MAAMF,EAAMG,YAAYF,KACtC,CAAE,MAAOG,GACP,MACF,CACA,GAAKH,EAEL,OAAQA,EAAKZ,MACX,IAAK,gBACHV,MAAAA,EAAO0B,gBAAP1B,EAAO0B,eAAiBJ,EAAKX,SAC7B,MACF,IAAK,gBACHX,EAAO2B,WAAP3B,EAAO2B,UAAYL,EAAKX,SACxB,MACF,IAAK,aACHX,MAAAA,EAAO4B,cAAP5B,EAAO4B,aAAeN,EAAKX,SAC3B,MACF,IAAK,UACa,MAAhBX,EAAOoB,WAAPpB,EAAOoB,UAAYE,EAAKX,SACxB,MACF,IAAK,cACHX,MAAAA,EAAO6B,eAAP7B,EAAO6B,cAAgBP,EAAKX,SAC5B,MACF,IAAK,iBACmB,MAAtBX,EAAO8B,iBAAP9B,EAAO8B,kBACP,MACF,IAAK,eACH9B,MAAAA,EAAO+B,eAAP/B,EAAO+B,gBACP,MACF,IAAK,kBACoB,MAAvB/B,EAAOgC,kBAAPhC,EAAOgC,mBACP,MACF,IAAK,gBACHhC,EAAOiC,WAAPjC,EAAOiC,YACP,MACF,IAAK,eACiB,MAApBjC,EAAOkC,eAAPlC,EAAOkC,cAAgBZ,EAAKX,SAC5B,MACF,IAAK,oBACHX,EAAOmC,oBAAPnC,EAAOmC,mBAAqBb,EAAKX,SACjC,MACF,IAAK,QACHX,MAAAA,EAAOoC,SAAPpC,EAAOoC,QAAUd,EAAKX,SAK5B,EACA,CAACX,IAGH,MAAO,CACLC,WAAAA,EACAoC,aAAc,CACZC,OAAQ,CAAEC,KA/Nd,23IA+NoBC,QAAS,qBACzBpB,UAAAA,EACAqB,UAAWxB,EACXyB,mBAAmB,EACnBC,2BAA2B,EAC3BC,kBAAkB,EAClBC,mBAAmB,EACnBC,gCAAiC,SAEnCxC,YAAAA,EACAyC,aAAc,WAAF,OAAQvC,EAAK,gBAAgB,EACzCwC,WAAY,WAAF,OAAQxC,EAAK,cAAc,EACrCyC,YAAa,SAACC,GAAiB,OAAA1C,EAAK,eAAgB,CAAE0C,KAAAA,GAAO,EAC7DC,WAAY,WAAF,OAAQ3C,EAAK,cAAc,EACrC4C,YAAa,WAAM,OAAA5C,EAAK,eAAe,EAE3C,CAMS6C,CAAUtD,EAASC,EAC5B,CAiBgB,SAAAsD,EAAqBC,GACnC,IACAC,EAAKD,EAALC,MACAC,EAAYF,EAAZE,aAIMC,EAAQ5D,EANPyD,EAAPxD,mJAIS4D,CAAAJ,EAAA1D,iBAIT,OACE+D,gBAACC,EAAO1C,GACN2C,IAAKJ,EAAMzD,YACPyD,EAAMrB,aACNoB,EAAY,CAChBD,MAAOA,IAGb"}
1
+ {"version":3,"file":"lib.module.js","sources":["../src/index.tsx"],"sourcesContent":["import { Status as StatusType, Mode as ModeType, ConversationEvents as ConversationEventsType, } from \"@unith-ai/core-client\";\nimport React, { useCallback, useRef, useState } from \"react\";\nimport { ViewStyle } from \"react-native\";\nimport { WebView, WebViewMessageEvent } from \"react-native-webview\";\n\nexport type ConversationOptions = {\n orgId: string;\n headId: string;\n apiKey: string;\n language?: string;\n username?: string;\n};\n\n\nexport type BridgeOptions = {\n webClientUrl?: string;\n webViewBaseUrl?: string;\n};\n\nexport type UseConversationResult = {\n webViewRef: React.RefObject<any>;\n webViewProps: Record<string, any>;\n initialized: boolean;\n startSession: () => void;\n endSession: () => void;\n sendMessage: (text: string) => void;\n toggleMute: () => void;\n keepSession: () => void;\n};\n\ntype BridgeMessage = {\n type: string;\n payload?: any;\n};\n\nconst DEFAULT_WEB_CLIENT_URL =\n \"https://unpkg.com/@unith-ai/core-client@2.0.3-beta.3/dist/lib.web.js\";\n\nfunction buildHtml(webClientUrl: string) {\n return `<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === \"INIT\") {\n try {\n const { Conversation } = await import(\"${webClientUrl}\");\n\n if (!(\"VideoDecoder\" in window)) {\n send(\"ERROR\", {\n message: \"WebCodecs VideoDecoder is not supported on this device.\",\n type: \"modal\",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById(\"root\");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: 'custom',\n onStatusChange: (data) => send(\"STATUS_CHANGE\", data),\n onConnect: (data) => send(\"CONNECT\", data),\n onDisconnect: (data) => send(\"DISCONNECT\", data),\n onMessage: (data) => send(\"MESSAGE\", data),\n onSuggestions: (data) => send(\"SUGGESTIONS\", data),\n onSpeakingStart: () => send(\"SPEAKING_START\"),\n onSpeakingEnd: () => send(\"SPEAKING_END\"),\n onTimeoutWarning: () => send(\"TIMEOUT_WARNING\"),\n onTimeout: () => send(\"TIMEOUT\"),\n onKeepSession: (data) => send(\"KEEP_SESSION\", data),\n onMuteStatusChange: (data) => send(\"MUTE_STATUS\", data),\n onError: (data) => send(\"ERROR\", data), \n });\n\n ready = true;\n send(\"READY\");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to process queued message\",\n type: \"notification\",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to initialize conversation\",\n type: \"modal\",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case \"START_SESSION\":\n await conversation.startSession();\n break;\n case \"END_SESSION\":\n await conversation.endSession();\n break;\n case \"SEND_MESSAGE\":\n await conversation.sendMessage(payload?.text || \"\");\n break; \n case \"TOGGLE_MUTE\":\n await conversation.toggleMute();\n break;\n case \"KEEP_SESSION\":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Operation failed\",\n type: \"notification\",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== \"INIT\") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error(\"Failed to handle incoming message:\", error);\n }\n };\n\n window.addEventListener(\"message\", handleIncoming);\n document.addEventListener(\"message\", handleIncoming);\n </script>\n </body>\n</html>`;\n}\n\nfunction useBridge(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n const webViewRef = useRef<any>(null);\n const initializedRef = useRef(false);\n const [initialized, setInitialized] = useState(false);\n\n const html = buildHtml(DEFAULT_WEB_CLIENT_URL)\n\n const post = useCallback((type: string, payload?: any) => {\n const message: BridgeMessage = { type, payload };\n webViewRef.current?.postMessage(JSON.stringify(message));\n }, []);\n\n const handleLoadEnd = useCallback(() => {\n if (initializedRef.current) {\n return;\n }\n\n\n initializedRef.current = true;\n setInitialized(true);\n\n // Add a small delay to ensure WebView is ready to receive messages\n setTimeout(() => {\n post(\"INIT\", {\n ...options,\n });\n }, 100);\n }, [options, post]);\n\n const onMessage = useCallback(\n (event: WebViewMessageEvent) => {\n let data: BridgeMessage | null = null;\n try {\n data = JSON.parse(event.nativeEvent.data);\n } catch (_) {\n return;\n }\n if (!data) return;\n\n switch (data.type) {\n case \"STATUS_CHANGE\":\n events.onStatusChange?.(data.payload);\n break;\n case \"CONNECT\":\n events.onConnect?.(data.payload);\n break;\n case \"DISCONNECT\":\n events.onDisconnect?.(data.payload);\n break;\n case \"MESSAGE\":\n events.onMessage?.(data.payload);\n break;\n case \"SUGGESTIONS\":\n events.onSuggestions?.(data.payload);\n break;\n case \"SPEAKING_START\":\n events.onSpeakingStart?.();\n break;\n case \"SPEAKING_END\":\n events.onSpeakingEnd?.();\n break;\n case \"TIMEOUT_WARNING\":\n events.onTimeoutWarning?.();\n break;\n case \"TIMEOUT\":\n events.onTimeout?.();\n break;\n case \"KEEP_SESSION\":\n events.onKeepSession?.(data.payload);\n break;\n case \"MUTE_STATUS\":\n events.onMuteStatusChange?.(data.payload);\n break;\n case \"ERROR\":\n events.onError?.(data.payload);\n break;\n default:\n break;\n }\n },\n [events]\n );\n\n return {\n webViewRef,\n webViewProps: {\n source: { html, baseUrl: \"https://unpkg.com\" },\n onMessage,\n onLoadEnd: handleLoadEnd,\n javaScriptEnabled: true,\n },\n initialized,\n startSession: () => post(\"START_SESSION\"),\n endSession: () => post(\"END_SESSION\"),\n sendMessage: (text: string) => post(\"SEND_MESSAGE\", { text }),\n toggleMute: () => post(\"TOGGLE_MUTE\"),\n keepSession: () => post(\"KEEP_SESSION\"),\n };\n}\n\nexport function useConversation(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n return useBridge(options, events,);\n}\n\n\nexport type UnithConversationViewProps = ConversationEventsType\n & {\n options: ConversationOptions;\n style?: ViewStyle;\n webviewProps?: Record<string, any>;\n webClientUrl?: string;\n };\n\n\nexport type Status = StatusType;\nexport type Mode = ModeType;\nexport type ConversationEvents = ConversationEventsType;\n\n\nexport function UnithConversationView({\n options,\n style,\n webviewProps,\n webClientUrl,\n ...events\n}: UnithConversationViewProps) {\n const convo = useConversation(options, events);\n\n return (\n <WebView\n ref={convo.webViewRef}\n {...convo.webViewProps}\n {...webviewProps}\n style={style}\n />\n );\n}\n"],"names":["_excluded","useConversation","options","events","webViewRef","useRef","initializedRef","_useState","useState","initialized","setInitialized","post","useCallback","type","payload","_webViewRef$current","current","postMessage","JSON","stringify","handleLoadEnd","setTimeout","_extends","onMessage","event","data","parse","nativeEvent","_","onStatusChange","onConnect","onDisconnect","onSuggestions","onSpeakingStart","onSpeakingEnd","onTimeoutWarning","onTimeout","onKeepSession","onMuteStatusChange","onError","webViewProps","source","html","baseUrl","onLoadEnd","javaScriptEnabled","startSession","endSession","sendMessage","text","toggleMute","keepSession","useBridge","UnithConversationView","_ref","style","webviewProps","convo","_objectWithoutPropertiesLoose","React","WebView","ref"],"mappings":"wUACA,IAAAA,EAAA,CAAA,UAAA,QAAA,eAAA,gBAmRgB,SAAAC,EACdC,EACAC,GAEA,OA3GF,SACED,EACAC,GAEA,IAAMC,EAAaC,EAAY,MACzBC,EAAiBD,GAAO,GAC9BE,EAAsCC,GAAS,GAAxCC,EAAWF,EAAEG,GAAAA,EAAcH,EAAA,GAI5BI,EAAOC,EAAY,SAACC,EAAcC,OAAiBC,EAEvDA,OAAAA,EAAAX,EAAWY,UAAXD,EAAoBE,YAAYC,KAAKC,UADN,CAAEN,KAAAA,EAAMC,QAAAA,IAEzC,EAAG,IAEGM,EAAgBR,EAAY,WAC5BN,EAAeU,UAKnBV,EAAeU,SAAU,EACzBN,GAAe,GAGfW,WAAW,WACTV,EAAK,OAAMW,KACNpB,GAEP,EAAG,KACL,EAAG,CAACA,EAASS,IAEPY,EAAYX,EAChB,SAACY,GACC,IAAIC,EAA6B,KACjC,IACEA,EAAOP,KAAKQ,MAAMF,EAAMG,YAAYF,KACtC,CAAE,MAAOG,GACP,MACF,CACA,GAAKH,EAEL,OAAQA,EAAKZ,MACX,IAAK,gBACkB,MAArBV,EAAO0B,gBAAP1B,EAAO0B,eAAiBJ,EAAKX,SAC7B,MACF,IAAK,UACHX,MAAAA,EAAO2B,WAAP3B,EAAO2B,UAAYL,EAAKX,SACxB,MACF,IAAK,mBACHX,EAAO4B,cAAP5B,EAAO4B,aAAeN,EAAKX,SAC3B,MACF,IAAK,UACa,MAAhBX,EAAOoB,WAAPpB,EAAOoB,UAAYE,EAAKX,SACxB,MACF,IAAK,cACHX,MAAAA,EAAO6B,eAAP7B,EAAO6B,cAAgBP,EAAKX,SAC5B,MACF,IAAK,iBACmB,MAAtBX,EAAO8B,iBAAP9B,EAAO8B,kBACP,MACF,IAAK,eACH9B,MAAAA,EAAO+B,eAAP/B,EAAO+B,gBACP,MACF,IAAK,wBACH/B,EAAOgC,kBAAPhC,EAAOgC,mBACP,MACF,IAAK,UACa,MAAhBhC,EAAOiC,WAAPjC,EAAOiC,YACP,MACF,IAAK,eACHjC,MAAAA,EAAOkC,eAAPlC,EAAOkC,cAAgBZ,EAAKX,SAC5B,MACF,IAAK,cACsB,MAAzBX,EAAOmC,oBAAPnC,EAAOmC,mBAAqBb,EAAKX,SACjC,MACF,IAAK,QACHX,MAAAA,EAAOoC,SAAPpC,EAAOoC,QAAUd,EAAKX,SAK5B,EACA,CAACX,IAGH,MAAO,CACLC,WAAAA,EACAoC,aAAc,CACZC,OAAQ,CAAEC,KA/Nd,23IA+NoBC,QAAS,qBACzBpB,UAAAA,EACAqB,UAAWxB,EACXyB,mBAAmB,GAErBpC,YAAAA,EACAqC,aAAc,kBAAMnC,EAAK,gBAAgB,EACzCoC,WAAY,WAAM,OAAApC,EAAK,cAAc,EACrCqC,YAAa,SAACC,GAAY,OAAKtC,EAAK,eAAgB,CAAEsC,KAAAA,GAAO,EAC7DC,WAAY,WAAM,OAAAvC,EAAK,cAAc,EACrCwC,YAAa,WAAF,OAAQxC,EAAK,eAAe,EAE3C,CAMSyC,CAAUlD,EAASC,EAC5B,CAiBgB,SAAAkD,EAAqBC,GACnC,IACAC,EAAKD,EAALC,MACAC,EAAYF,EAAZE,aAIMC,EAAQxD,EANPqD,EAAPpD,mJAISwD,CAAAJ,EAAAtD,iBAIT,OACE2D,gBAACC,EAAOtC,GACNuC,IAAKJ,EAAMrD,YACPqD,EAAMjB,aACNgB,EAAY,CAChBD,MAAOA,IAGb"}
package/dist/lib.umd.js CHANGED
@@ -1,2 +1,2 @@
1
- !function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react"),require("react-native-webview")):"function"==typeof define&&define.amd?define(["exports","react","react-native-webview"],e):e((n||self).reactNative={},n.react,n.reactNativeWebview)}(this,function(n,e,t){function a(n){return n&&"object"==typeof n&&"default"in n?n:{default:n}}var o=/*#__PURE__*/a(e);function s(){return s=Object.assign?Object.assign.bind():function(n){for(var e=1;e<arguments.length;e++){var t=arguments[e];for(var a in t)({}).hasOwnProperty.call(t,a)&&(n[a]=t[a])}return n},s.apply(null,arguments)}var i=["options","style","webviewProps","webClientUrl"];function r(n,t){return function(n,t){var a=e.useRef(null),o=e.useRef(!1),i=e.useState(!1),r=i[0],d=i[1],l=e.useCallback(function(n,e){var t;null==(t=a.current)||t.postMessage(JSON.stringify({type:n,payload:e}))},[]),c=e.useCallback(function(){o.current||(o.current=!0,d(!0),setTimeout(function(){l("INIT",s({},n))},100))},[n,l]),u=e.useCallback(function(n){var e=null;try{e=JSON.parse(n.nativeEvent.data)}catch(n){return}if(e)switch(e.type){case"STATUS_CHANGE":null==t.onStatusChange||t.onStatusChange(e.payload);break;case"CONNECT":null==t.onConnect||t.onConnect(e.payload);break;case"DISCONNECT":null==t.onDisconnect||t.onDisconnect(e.payload);break;case"MESSAGE":null==t.onMessage||t.onMessage(e.payload);break;case"SUGGESTIONS":null==t.onSuggestions||t.onSuggestions(e.payload);break;case"SPEAKING_START":null==t.onSpeakingStart||t.onSpeakingStart();break;case"SPEAKING_END":null==t.onSpeakingEnd||t.onSpeakingEnd();break;case"TIMEOUT_WARNING":null==t.onTimeoutWarning||t.onTimeoutWarning();break;case"TIMEOUT":null==t.onTimeout||t.onTimeout();break;case"KEEP_SESSION":null==t.onKeepSession||t.onKeepSession(e.payload);break;case"MUTE_STATUS":null==t.onMuteStatusChange||t.onMuteStatusChange(e.payload);break;case"ERROR":null==t.onError||t.onError(e.payload)}},[t]);return{webViewRef:a,webViewProps:{source:{html:'<!doctype html>\n<html>\n <head>\n <meta charset="utf-8" />\n <meta name="viewport" content="width=device-width, initial-scale=1" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id="root"></div>\n <script type="module">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === "INIT") {\n try {\n const { Conversation } = await import("https://unpkg.com/@unith-ai/core-client@2.0.3-beta.2/dist/lib.web.js");\n\n if (!("VideoDecoder" in window)) {\n send("ERROR", {\n message: "WebCodecs VideoDecoder is not supported on this device.",\n type: "modal",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById("root");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: \'custom\',\n onStatusChange: (data) => send("STATUS_CHANGE", data),\n onConnect: (data) => send("CONNECT", data),\n onDisconnect: (data) => send("DISCONNECT", data),\n onMessage: (data) => send("MESSAGE", data),\n onSuggestions: (data) => send("SUGGESTIONS", data),\n onSpeakingStart: () => send("SPEAKING_START"),\n onSpeakingEnd: () => send("SPEAKING_END"),\n onTimeoutWarning: () => send("TIMEOUT_WARNING"),\n onTimeout: () => send("TIMEOUT"),\n onKeepSession: (data) => send("KEEP_SESSION", data),\n onMuteStatusChange: (data) => send("MUTE_STATUS", data),\n onError: (data) => send("ERROR", data), \n });\n\n ready = true;\n send("READY");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to process queued message",\n type: "notification",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to initialize conversation",\n type: "modal",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case "START_SESSION":\n await conversation.startSession();\n break;\n case "END_SESSION":\n await conversation.endSession();\n break;\n case "SEND_MESSAGE":\n await conversation.sendMessage(payload?.text || "");\n break; \n case "TOGGLE_MUTE":\n await conversation.toggleMute();\n break;\n case "KEEP_SESSION":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Operation failed",\n type: "notification",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== "INIT") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error("Failed to handle incoming message:", error);\n }\n };\n\n window.addEventListener("message", handleIncoming);\n document.addEventListener("message", handleIncoming);\n <\/script>\n </body>\n</html>',baseUrl:"https://unpkg.com"},onMessage:u,onLoadEnd:c,javaScriptEnabled:!0,allowsInlineMediaPlayback:!0,allowsFileAccess:!0,domStorageEnabled:!0,mediaCapturePermissionGrantType:"grant"},initialized:r,startSession:function(){return l("START_SESSION")},endSession:function(){return l("END_SESSION")},sendMessage:function(n){return l("SEND_MESSAGE",{text:n})},toggleMute:function(){return l("TOGGLE_MUTE")},keepSession:function(){return l("KEEP_SESSION")}}}(n,t)}n.UnithConversationView=function(n){var e=n.style,a=n.webviewProps,d=r(n.options,function(n,e){if(null==n)return{};var t={};for(var a in n)if({}.hasOwnProperty.call(n,a)){if(-1!==e.indexOf(a))continue;t[a]=n[a]}return t}(n,i));/*#__PURE__*/return o.default.createElement(t.WebView,s({ref:d.webViewRef},d.webViewProps,a,{style:e}))},n.useConversation=r});
1
+ !function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react"),require("react-native-webview")):"function"==typeof define&&define.amd?define(["exports","react","react-native-webview"],e):e((n||self).reactNative={},n.react,n.reactNativeWebview)}(this,function(n,e,t){function a(n){return n&&"object"==typeof n&&"default"in n?n:{default:n}}var o=/*#__PURE__*/a(e);function s(){return s=Object.assign?Object.assign.bind():function(n){for(var e=1;e<arguments.length;e++){var t=arguments[e];for(var a in t)({}).hasOwnProperty.call(t,a)&&(n[a]=t[a])}return n},s.apply(null,arguments)}var i=["options","style","webviewProps","webClientUrl"];function r(n,t){return function(n,t){var a=e.useRef(null),o=e.useRef(!1),i=e.useState(!1),r=i[0],d=i[1],c=e.useCallback(function(n,e){var t;null==(t=a.current)||t.postMessage(JSON.stringify({type:n,payload:e}))},[]),l=e.useCallback(function(){o.current||(o.current=!0,d(!0),setTimeout(function(){c("INIT",s({},n))},100))},[n,c]),u=e.useCallback(function(n){var e=null;try{e=JSON.parse(n.nativeEvent.data)}catch(n){return}if(e)switch(e.type){case"STATUS_CHANGE":null==t.onStatusChange||t.onStatusChange(e.payload);break;case"CONNECT":null==t.onConnect||t.onConnect(e.payload);break;case"DISCONNECT":null==t.onDisconnect||t.onDisconnect(e.payload);break;case"MESSAGE":null==t.onMessage||t.onMessage(e.payload);break;case"SUGGESTIONS":null==t.onSuggestions||t.onSuggestions(e.payload);break;case"SPEAKING_START":null==t.onSpeakingStart||t.onSpeakingStart();break;case"SPEAKING_END":null==t.onSpeakingEnd||t.onSpeakingEnd();break;case"TIMEOUT_WARNING":null==t.onTimeoutWarning||t.onTimeoutWarning();break;case"TIMEOUT":null==t.onTimeout||t.onTimeout();break;case"KEEP_SESSION":null==t.onKeepSession||t.onKeepSession(e.payload);break;case"MUTE_STATUS":null==t.onMuteStatusChange||t.onMuteStatusChange(e.payload);break;case"ERROR":null==t.onError||t.onError(e.payload)}},[t]);return{webViewRef:a,webViewProps:{source:{html:'<!doctype html>\n<html>\n <head>\n <meta charset="utf-8" />\n <meta name="viewport" content="width=device-width, initial-scale=1" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id="root"></div>\n <script type="module">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === "INIT") {\n try {\n const { Conversation } = await import("https://unpkg.com/@unith-ai/core-client@2.0.3-beta.3/dist/lib.web.js");\n\n if (!("VideoDecoder" in window)) {\n send("ERROR", {\n message: "WebCodecs VideoDecoder is not supported on this device.",\n type: "modal",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById("root");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: \'custom\',\n onStatusChange: (data) => send("STATUS_CHANGE", data),\n onConnect: (data) => send("CONNECT", data),\n onDisconnect: (data) => send("DISCONNECT", data),\n onMessage: (data) => send("MESSAGE", data),\n onSuggestions: (data) => send("SUGGESTIONS", data),\n onSpeakingStart: () => send("SPEAKING_START"),\n onSpeakingEnd: () => send("SPEAKING_END"),\n onTimeoutWarning: () => send("TIMEOUT_WARNING"),\n onTimeout: () => send("TIMEOUT"),\n onKeepSession: (data) => send("KEEP_SESSION", data),\n onMuteStatusChange: (data) => send("MUTE_STATUS", data),\n onError: (data) => send("ERROR", data), \n });\n\n ready = true;\n send("READY");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to process queued message",\n type: "notification",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Failed to initialize conversation",\n type: "modal",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case "START_SESSION":\n await conversation.startSession();\n break;\n case "END_SESSION":\n await conversation.endSession();\n break;\n case "SEND_MESSAGE":\n await conversation.sendMessage(payload?.text || "");\n break; \n case "TOGGLE_MUTE":\n await conversation.toggleMute();\n break;\n case "KEEP_SESSION":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send("ERROR", {\n message: error?.message || "Operation failed",\n type: "notification",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== "INIT") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error("Failed to handle incoming message:", error);\n }\n };\n\n window.addEventListener("message", handleIncoming);\n document.addEventListener("message", handleIncoming);\n <\/script>\n </body>\n</html>',baseUrl:"https://unpkg.com"},onMessage:u,onLoadEnd:l,javaScriptEnabled:!0},initialized:r,startSession:function(){return c("START_SESSION")},endSession:function(){return c("END_SESSION")},sendMessage:function(n){return c("SEND_MESSAGE",{text:n})},toggleMute:function(){return c("TOGGLE_MUTE")},keepSession:function(){return c("KEEP_SESSION")}}}(n,t)}n.UnithConversationView=function(n){var e=n.style,a=n.webviewProps,d=r(n.options,function(n,e){if(null==n)return{};var t={};for(var a in n)if({}.hasOwnProperty.call(n,a)){if(-1!==e.indexOf(a))continue;t[a]=n[a]}return t}(n,i));/*#__PURE__*/return o.default.createElement(t.WebView,s({ref:d.webViewRef},d.webViewProps,a,{style:e}))},n.useConversation=r});
2
2
  //# sourceMappingURL=lib.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lib.umd.js","sources":["../src/index.tsx"],"sourcesContent":["import { Status as StatusType, Mode as ModeType, ConversationEvents as ConversationEventsType, } from \"@unith-ai/core-client\";\nimport React, { useCallback, useRef, useState } from \"react\";\nimport { ViewStyle } from \"react-native\";\nimport { WebView, WebViewMessageEvent } from \"react-native-webview\";\n\nexport type ConversationOptions = {\n orgId: string;\n headId: string;\n apiKey: string;\n language?: string;\n username?: string;\n};\n\n\nexport type BridgeOptions = {\n webClientUrl?: string;\n webViewBaseUrl?: string;\n};\n\nexport type UseConversationResult = {\n webViewRef: React.RefObject<any>;\n webViewProps: Record<string, any>;\n initialized: boolean;\n startSession: () => void;\n endSession: () => void;\n sendMessage: (text: string) => void;\n toggleMute: () => void;\n keepSession: () => void;\n};\n\ntype BridgeMessage = {\n type: string;\n payload?: any;\n};\n\nconst DEFAULT_WEB_CLIENT_URL =\n \"https://unpkg.com/@unith-ai/core-client@2.0.3-beta.2/dist/lib.web.js\";\n\nfunction buildHtml(webClientUrl: string) {\n return `<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === \"INIT\") {\n try {\n const { Conversation } = await import(\"${webClientUrl}\");\n\n if (!(\"VideoDecoder\" in window)) {\n send(\"ERROR\", {\n message: \"WebCodecs VideoDecoder is not supported on this device.\",\n type: \"modal\",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById(\"root\");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: 'custom',\n onStatusChange: (data) => send(\"STATUS_CHANGE\", data),\n onConnect: (data) => send(\"CONNECT\", data),\n onDisconnect: (data) => send(\"DISCONNECT\", data),\n onMessage: (data) => send(\"MESSAGE\", data),\n onSuggestions: (data) => send(\"SUGGESTIONS\", data),\n onSpeakingStart: () => send(\"SPEAKING_START\"),\n onSpeakingEnd: () => send(\"SPEAKING_END\"),\n onTimeoutWarning: () => send(\"TIMEOUT_WARNING\"),\n onTimeout: () => send(\"TIMEOUT\"),\n onKeepSession: (data) => send(\"KEEP_SESSION\", data),\n onMuteStatusChange: (data) => send(\"MUTE_STATUS\", data),\n onError: (data) => send(\"ERROR\", data), \n });\n\n ready = true;\n send(\"READY\");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to process queued message\",\n type: \"notification\",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to initialize conversation\",\n type: \"modal\",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case \"START_SESSION\":\n await conversation.startSession();\n break;\n case \"END_SESSION\":\n await conversation.endSession();\n break;\n case \"SEND_MESSAGE\":\n await conversation.sendMessage(payload?.text || \"\");\n break; \n case \"TOGGLE_MUTE\":\n await conversation.toggleMute();\n break;\n case \"KEEP_SESSION\":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Operation failed\",\n type: \"notification\",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== \"INIT\") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error(\"Failed to handle incoming message:\", error);\n }\n };\n\n window.addEventListener(\"message\", handleIncoming);\n document.addEventListener(\"message\", handleIncoming);\n </script>\n </body>\n</html>`;\n}\n\nfunction useBridge(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n const webViewRef = useRef<any>(null);\n const initializedRef = useRef(false);\n const [initialized, setInitialized] = useState(false);\n\n const html = buildHtml(DEFAULT_WEB_CLIENT_URL)\n\n const post = useCallback((type: string, payload?: any) => {\n const message: BridgeMessage = { type, payload };\n webViewRef.current?.postMessage(JSON.stringify(message));\n }, []);\n\n const handleLoadEnd = useCallback(() => {\n if (initializedRef.current) {\n return;\n }\n\n\n initializedRef.current = true;\n setInitialized(true);\n\n // Add a small delay to ensure WebView is ready to receive messages\n setTimeout(() => {\n post(\"INIT\", {\n ...options,\n });\n }, 100);\n }, [options, post]);\n\n const onMessage = useCallback(\n (event: WebViewMessageEvent) => {\n let data: BridgeMessage | null = null;\n try {\n data = JSON.parse(event.nativeEvent.data);\n } catch (_) {\n return;\n }\n if (!data) return;\n\n switch (data.type) {\n case \"STATUS_CHANGE\":\n events.onStatusChange?.(data.payload);\n break;\n case \"CONNECT\":\n events.onConnect?.(data.payload);\n break;\n case \"DISCONNECT\":\n events.onDisconnect?.(data.payload);\n break;\n case \"MESSAGE\":\n events.onMessage?.(data.payload);\n break;\n case \"SUGGESTIONS\":\n events.onSuggestions?.(data.payload);\n break;\n case \"SPEAKING_START\":\n events.onSpeakingStart?.();\n break;\n case \"SPEAKING_END\":\n events.onSpeakingEnd?.();\n break;\n case \"TIMEOUT_WARNING\":\n events.onTimeoutWarning?.();\n break;\n case \"TIMEOUT\":\n events.onTimeout?.();\n break;\n case \"KEEP_SESSION\":\n events.onKeepSession?.(data.payload);\n break;\n case \"MUTE_STATUS\":\n events.onMuteStatusChange?.(data.payload);\n break;\n case \"ERROR\":\n events.onError?.(data.payload);\n break;\n default:\n break;\n }\n },\n [events]\n );\n\n return {\n webViewRef,\n webViewProps: {\n source: { html, baseUrl: \"https://unpkg.com\" },\n onMessage,\n onLoadEnd: handleLoadEnd,\n javaScriptEnabled: true,\n allowsInlineMediaPlayback: true,\n allowsFileAccess: true,\n domStorageEnabled: true,\n mediaCapturePermissionGrantType: 'grant',\n },\n initialized,\n startSession: () => post(\"START_SESSION\"),\n endSession: () => post(\"END_SESSION\"),\n sendMessage: (text: string) => post(\"SEND_MESSAGE\", { text }),\n toggleMute: () => post(\"TOGGLE_MUTE\"),\n keepSession: () => post(\"KEEP_SESSION\"),\n };\n}\n\nexport function useConversation(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n return useBridge(options, events,);\n}\n\n\nexport type UnithConversationViewProps = ConversationEventsType\n & {\n options: ConversationOptions;\n style?: ViewStyle;\n webviewProps?: Record<string, any>;\n webClientUrl?: string;\n };\n\n\nexport type Status = StatusType;\nexport type Mode = ModeType;\nexport type ConversationEvents = ConversationEventsType;\n\n\nexport function UnithConversationView({\n options,\n style,\n webviewProps,\n webClientUrl,\n ...events\n}: UnithConversationViewProps) {\n const convo = useConversation(options, events);\n\n return (\n <WebView\n ref={convo.webViewRef}\n {...convo.webViewProps}\n {...webviewProps}\n style={style}\n />\n );\n}\n"],"names":["_excluded","useConversation","options","events","webViewRef","useRef","initializedRef","_useState","useState","initialized","setInitialized","post","useCallback","type","payload","_webViewRef$current","current","postMessage","JSON","stringify","handleLoadEnd","setTimeout","_extends","onMessage","event","data","parse","nativeEvent","_","onStatusChange","onConnect","onDisconnect","onSuggestions","onSpeakingStart","onSpeakingEnd","onTimeoutWarning","onTimeout","onKeepSession","onMuteStatusChange","onError","webViewProps","source","html","baseUrl","onLoadEnd","javaScriptEnabled","allowsInlineMediaPlayback","allowsFileAccess","domStorageEnabled","mediaCapturePermissionGrantType","startSession","endSession","sendMessage","text","toggleMute","keepSession","useBridge","_ref","style","webviewProps","convo","_objectWithoutPropertiesLoose","React","WebView","ref"],"mappings":"8oBACA,IAAAA,EAAA,CAAA,UAAA,QAAA,eAAA,gBAuRgB,SAAAC,EACdC,EACAC,GAEA,OA/GF,SACED,EACAC,GAEA,IAAMC,EAAaC,EAAAA,OAAY,MACzBC,EAAiBD,EAAAA,QAAO,GAC9BE,EAAsCC,EAAAA,UAAS,GAAxCC,EAAWF,EAAA,GAAEG,EAAcH,KAI5BI,EAAOC,EAAWA,YAAC,SAACC,EAAcC,GAAiBC,IAAAA,SAEvDA,EAAAX,EAAWY,UAAXD,EAAoBE,YAAYC,KAAKC,UADN,CAAEN,KAAAA,EAAMC,QAAAA,IAEzC,EAAG,IAEGM,EAAgBR,cAAY,WAC5BN,EAAeU,UAKnBV,EAAeU,SAAU,EACzBN,GAAe,GAGfW,WAAW,WACTV,EAAK,OAAMW,EACNpB,CAAAA,EAAAA,GAEP,EAAG,KACL,EAAG,CAACA,EAASS,IAEPY,EAAYX,EAAAA,YAChB,SAACY,GACC,IAAIC,EAA6B,KACjC,IACEA,EAAOP,KAAKQ,MAAMF,EAAMG,YAAYF,KACtC,CAAE,MAAOG,GACP,MACF,CACA,GAAKH,EAEL,OAAQA,EAAKZ,MACX,IAAK,gBACHV,MAAAA,EAAO0B,gBAAP1B,EAAO0B,eAAiBJ,EAAKX,SAC7B,MACF,IAAK,gBACHX,EAAO2B,WAAP3B,EAAO2B,UAAYL,EAAKX,SACxB,MACF,IAAK,aACHX,MAAAA,EAAO4B,cAAP5B,EAAO4B,aAAeN,EAAKX,SAC3B,MACF,IAAK,UACa,MAAhBX,EAAOoB,WAAPpB,EAAOoB,UAAYE,EAAKX,SACxB,MACF,IAAK,cACHX,MAAAA,EAAO6B,eAAP7B,EAAO6B,cAAgBP,EAAKX,SAC5B,MACF,IAAK,iBACmB,MAAtBX,EAAO8B,iBAAP9B,EAAO8B,kBACP,MACF,IAAK,eACH9B,MAAAA,EAAO+B,eAAP/B,EAAO+B,gBACP,MACF,IAAK,kBACoB,MAAvB/B,EAAOgC,kBAAPhC,EAAOgC,mBACP,MACF,IAAK,gBACHhC,EAAOiC,WAAPjC,EAAOiC,YACP,MACF,IAAK,eACiB,MAApBjC,EAAOkC,eAAPlC,EAAOkC,cAAgBZ,EAAKX,SAC5B,MACF,IAAK,oBACHX,EAAOmC,oBAAPnC,EAAOmC,mBAAqBb,EAAKX,SACjC,MACF,IAAK,QACHX,MAAAA,EAAOoC,SAAPpC,EAAOoC,QAAUd,EAAKX,SAK5B,EACA,CAACX,IAGH,MAAO,CACLC,WAAAA,EACAoC,aAAc,CACZC,OAAQ,CAAEC,KA/Nd,23IA+NoBC,QAAS,qBACzBpB,UAAAA,EACAqB,UAAWxB,EACXyB,mBAAmB,EACnBC,2BAA2B,EAC3BC,kBAAkB,EAClBC,mBAAmB,EACnBC,gCAAiC,SAEnCxC,YAAAA,EACAyC,aAAc,WAAF,OAAQvC,EAAK,gBAAgB,EACzCwC,WAAY,WAAF,OAAQxC,EAAK,cAAc,EACrCyC,YAAa,SAACC,GAAiB,OAAA1C,EAAK,eAAgB,CAAE0C,KAAAA,GAAO,EAC7DC,WAAY,WAAF,OAAQ3C,EAAK,cAAc,EACrC4C,YAAa,WAAM,OAAA5C,EAAK,eAAe,EAE3C,CAMS6C,CAAUtD,EAASC,EAC5B,yBAiBgB,SAAqBsD,GACnC,IACAC,EAAKD,EAALC,MACAC,EAAYF,EAAZE,aAIMC,EAAQ3D,EANPwD,EAAPvD,mJAIS2D,CAAAJ,EAAAzD,iBAIT,OACE8D,wBAACC,EAAAA,QAAOzC,GACN0C,IAAKJ,EAAMxD,YACPwD,EAAMpB,aACNmB,EAAY,CAChBD,MAAOA,IAGb"}
1
+ {"version":3,"file":"lib.umd.js","sources":["../src/index.tsx"],"sourcesContent":["import { Status as StatusType, Mode as ModeType, ConversationEvents as ConversationEventsType, } from \"@unith-ai/core-client\";\nimport React, { useCallback, useRef, useState } from \"react\";\nimport { ViewStyle } from \"react-native\";\nimport { WebView, WebViewMessageEvent } from \"react-native-webview\";\n\nexport type ConversationOptions = {\n orgId: string;\n headId: string;\n apiKey: string;\n language?: string;\n username?: string;\n};\n\n\nexport type BridgeOptions = {\n webClientUrl?: string;\n webViewBaseUrl?: string;\n};\n\nexport type UseConversationResult = {\n webViewRef: React.RefObject<any>;\n webViewProps: Record<string, any>;\n initialized: boolean;\n startSession: () => void;\n endSession: () => void;\n sendMessage: (text: string) => void;\n toggleMute: () => void;\n keepSession: () => void;\n};\n\ntype BridgeMessage = {\n type: string;\n payload?: any;\n};\n\nconst DEFAULT_WEB_CLIENT_URL =\n \"https://unpkg.com/@unith-ai/core-client@2.0.3-beta.3/dist/lib.web.js\";\n\nfunction buildHtml(webClientUrl: string) {\n return `<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <style>\n html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: #0b1020; }\n #root { position: relative; width: 100%; height: 100%; overflow: hidden; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\">\n const send = (type, payload) => {\n if (window.ReactNativeWebView) {\n window.ReactNativeWebView.postMessage(JSON.stringify({ type, payload }));\n }\n };\n let conversation = null;\n let queue = [];\n let ready = false;\n\n const applyMessage = async (msg) => { \n const { type, payload } = msg || {};\n if (!type) return;\n\n if (type === \"INIT\") {\n try {\n const { Conversation } = await import(\"${webClientUrl}\");\n\n if (!(\"VideoDecoder\" in window)) {\n send(\"ERROR\", {\n message: \"WebCodecs VideoDecoder is not supported on this device.\",\n type: \"modal\",\n endConversation: true,\n });\n return;\n }\n\n const element = document.getElementById(\"root\");\n conversation = await Conversation.startDigitalHuman({\n ...payload,\n element, \n microphoneProvider: 'custom',\n onStatusChange: (data) => send(\"STATUS_CHANGE\", data),\n onConnect: (data) => send(\"CONNECT\", data),\n onDisconnect: (data) => send(\"DISCONNECT\", data),\n onMessage: (data) => send(\"MESSAGE\", data),\n onSuggestions: (data) => send(\"SUGGESTIONS\", data),\n onSpeakingStart: () => send(\"SPEAKING_START\"),\n onSpeakingEnd: () => send(\"SPEAKING_END\"),\n onTimeoutWarning: () => send(\"TIMEOUT_WARNING\"),\n onTimeout: () => send(\"TIMEOUT\"),\n onKeepSession: (data) => send(\"KEEP_SESSION\", data),\n onMuteStatusChange: (data) => send(\"MUTE_STATUS\", data),\n onError: (data) => send(\"ERROR\", data), \n });\n\n ready = true;\n send(\"READY\");\n\n while (queue.length > 0) {\n const next = queue.shift();\n try {\n await applyMessage(next);\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to process queued message\",\n type: \"notification\",\n endConversation: false,\n });\n }\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Failed to initialize conversation\",\n type: \"modal\",\n endConversation: true,\n });\n }\n return;\n }\n\n if (!ready || !conversation) return;\n\n try {\n switch (type) {\n case \"START_SESSION\":\n await conversation.startSession();\n break;\n case \"END_SESSION\":\n await conversation.endSession();\n break;\n case \"SEND_MESSAGE\":\n await conversation.sendMessage(payload?.text || \"\");\n break; \n case \"TOGGLE_MUTE\":\n await conversation.toggleMute();\n break;\n case \"KEEP_SESSION\":\n await conversation.keepSession();\n break;\n default:\n break;\n }\n } catch (error) {\n send(\"ERROR\", {\n message: error?.message || \"Operation failed\",\n type: \"notification\",\n endConversation: false,\n });\n }\n };\n\n const handleIncoming = (event) => { \n try {\n const msg = JSON.parse(event.data);\n if (!ready && msg.type !== \"INIT\") {\n queue.push(msg);\n return;\n }\n applyMessage(msg);\n } catch (error) {\n console.error(\"Failed to handle incoming message:\", error);\n }\n };\n\n window.addEventListener(\"message\", handleIncoming);\n document.addEventListener(\"message\", handleIncoming);\n </script>\n </body>\n</html>`;\n}\n\nfunction useBridge(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n const webViewRef = useRef<any>(null);\n const initializedRef = useRef(false);\n const [initialized, setInitialized] = useState(false);\n\n const html = buildHtml(DEFAULT_WEB_CLIENT_URL)\n\n const post = useCallback((type: string, payload?: any) => {\n const message: BridgeMessage = { type, payload };\n webViewRef.current?.postMessage(JSON.stringify(message));\n }, []);\n\n const handleLoadEnd = useCallback(() => {\n if (initializedRef.current) {\n return;\n }\n\n\n initializedRef.current = true;\n setInitialized(true);\n\n // Add a small delay to ensure WebView is ready to receive messages\n setTimeout(() => {\n post(\"INIT\", {\n ...options,\n });\n }, 100);\n }, [options, post]);\n\n const onMessage = useCallback(\n (event: WebViewMessageEvent) => {\n let data: BridgeMessage | null = null;\n try {\n data = JSON.parse(event.nativeEvent.data);\n } catch (_) {\n return;\n }\n if (!data) return;\n\n switch (data.type) {\n case \"STATUS_CHANGE\":\n events.onStatusChange?.(data.payload);\n break;\n case \"CONNECT\":\n events.onConnect?.(data.payload);\n break;\n case \"DISCONNECT\":\n events.onDisconnect?.(data.payload);\n break;\n case \"MESSAGE\":\n events.onMessage?.(data.payload);\n break;\n case \"SUGGESTIONS\":\n events.onSuggestions?.(data.payload);\n break;\n case \"SPEAKING_START\":\n events.onSpeakingStart?.();\n break;\n case \"SPEAKING_END\":\n events.onSpeakingEnd?.();\n break;\n case \"TIMEOUT_WARNING\":\n events.onTimeoutWarning?.();\n break;\n case \"TIMEOUT\":\n events.onTimeout?.();\n break;\n case \"KEEP_SESSION\":\n events.onKeepSession?.(data.payload);\n break;\n case \"MUTE_STATUS\":\n events.onMuteStatusChange?.(data.payload);\n break;\n case \"ERROR\":\n events.onError?.(data.payload);\n break;\n default:\n break;\n }\n },\n [events]\n );\n\n return {\n webViewRef,\n webViewProps: {\n source: { html, baseUrl: \"https://unpkg.com\" },\n onMessage,\n onLoadEnd: handleLoadEnd,\n javaScriptEnabled: true,\n },\n initialized,\n startSession: () => post(\"START_SESSION\"),\n endSession: () => post(\"END_SESSION\"),\n sendMessage: (text: string) => post(\"SEND_MESSAGE\", { text }),\n toggleMute: () => post(\"TOGGLE_MUTE\"),\n keepSession: () => post(\"KEEP_SESSION\"),\n };\n}\n\nexport function useConversation(\n options: ConversationOptions,\n events: ConversationEventsType\n): UseConversationResult {\n return useBridge(options, events,);\n}\n\n\nexport type UnithConversationViewProps = ConversationEventsType\n & {\n options: ConversationOptions;\n style?: ViewStyle;\n webviewProps?: Record<string, any>;\n webClientUrl?: string;\n };\n\n\nexport type Status = StatusType;\nexport type Mode = ModeType;\nexport type ConversationEvents = ConversationEventsType;\n\n\nexport function UnithConversationView({\n options,\n style,\n webviewProps,\n webClientUrl,\n ...events\n}: UnithConversationViewProps) {\n const convo = useConversation(options, events);\n\n return (\n <WebView\n ref={convo.webViewRef}\n {...convo.webViewProps}\n {...webviewProps}\n style={style}\n />\n );\n}\n"],"names":["_excluded","useConversation","options","events","webViewRef","useRef","initializedRef","_useState","useState","initialized","setInitialized","post","useCallback","type","payload","_webViewRef$current","current","postMessage","JSON","stringify","handleLoadEnd","setTimeout","_extends","onMessage","event","data","parse","nativeEvent","_","onStatusChange","onConnect","onDisconnect","onSuggestions","onSpeakingStart","onSpeakingEnd","onTimeoutWarning","onTimeout","onKeepSession","onMuteStatusChange","onError","webViewProps","source","html","baseUrl","onLoadEnd","javaScriptEnabled","startSession","endSession","sendMessage","text","toggleMute","keepSession","useBridge","_ref","style","webviewProps","convo","_objectWithoutPropertiesLoose","React","WebView","ref"],"mappings":"8oBACA,IAAAA,EAAA,CAAA,UAAA,QAAA,eAAA,gBAmRgB,SAAAC,EACdC,EACAC,GAEA,OA3GF,SACED,EACAC,GAEA,IAAMC,EAAaC,SAAY,MACzBC,EAAiBD,EAAMA,QAAC,GAC9BE,EAAsCC,EAAQA,UAAC,GAAxCC,EAAWF,EAAEG,GAAAA,EAAcH,EAAA,GAI5BI,EAAOC,cAAY,SAACC,EAAcC,OAAiBC,EAEvDA,OAAAA,EAAAX,EAAWY,UAAXD,EAAoBE,YAAYC,KAAKC,UADN,CAAEN,KAAAA,EAAMC,QAAAA,IAEzC,EAAG,IAEGM,EAAgBR,EAAWA,YAAC,WAC5BN,EAAeU,UAKnBV,EAAeU,SAAU,EACzBN,GAAe,GAGfW,WAAW,WACTV,EAAK,OAAMW,KACNpB,GAEP,EAAG,KACL,EAAG,CAACA,EAASS,IAEPY,EAAYX,EAAAA,YAChB,SAACY,GACC,IAAIC,EAA6B,KACjC,IACEA,EAAOP,KAAKQ,MAAMF,EAAMG,YAAYF,KACtC,CAAE,MAAOG,GACP,MACF,CACA,GAAKH,EAEL,OAAQA,EAAKZ,MACX,IAAK,gBACkB,MAArBV,EAAO0B,gBAAP1B,EAAO0B,eAAiBJ,EAAKX,SAC7B,MACF,IAAK,UACHX,MAAAA,EAAO2B,WAAP3B,EAAO2B,UAAYL,EAAKX,SACxB,MACF,IAAK,mBACHX,EAAO4B,cAAP5B,EAAO4B,aAAeN,EAAKX,SAC3B,MACF,IAAK,UACa,MAAhBX,EAAOoB,WAAPpB,EAAOoB,UAAYE,EAAKX,SACxB,MACF,IAAK,cACHX,MAAAA,EAAO6B,eAAP7B,EAAO6B,cAAgBP,EAAKX,SAC5B,MACF,IAAK,iBACmB,MAAtBX,EAAO8B,iBAAP9B,EAAO8B,kBACP,MACF,IAAK,eACH9B,MAAAA,EAAO+B,eAAP/B,EAAO+B,gBACP,MACF,IAAK,wBACH/B,EAAOgC,kBAAPhC,EAAOgC,mBACP,MACF,IAAK,UACa,MAAhBhC,EAAOiC,WAAPjC,EAAOiC,YACP,MACF,IAAK,eACHjC,MAAAA,EAAOkC,eAAPlC,EAAOkC,cAAgBZ,EAAKX,SAC5B,MACF,IAAK,cACsB,MAAzBX,EAAOmC,oBAAPnC,EAAOmC,mBAAqBb,EAAKX,SACjC,MACF,IAAK,QACHX,MAAAA,EAAOoC,SAAPpC,EAAOoC,QAAUd,EAAKX,SAK5B,EACA,CAACX,IAGH,MAAO,CACLC,WAAAA,EACAoC,aAAc,CACZC,OAAQ,CAAEC,KA/Nd,23IA+NoBC,QAAS,qBACzBpB,UAAAA,EACAqB,UAAWxB,EACXyB,mBAAmB,GAErBpC,YAAAA,EACAqC,aAAc,kBAAMnC,EAAK,gBAAgB,EACzCoC,WAAY,WAAM,OAAApC,EAAK,cAAc,EACrCqC,YAAa,SAACC,GAAY,OAAKtC,EAAK,eAAgB,CAAEsC,KAAAA,GAAO,EAC7DC,WAAY,WAAM,OAAAvC,EAAK,cAAc,EACrCwC,YAAa,WAAF,OAAQxC,EAAK,eAAe,EAE3C,CAMSyC,CAAUlD,EAASC,EAC5B,yBAiBgB,SAAqBkD,GACnC,IACAC,EAAKD,EAALC,MACAC,EAAYF,EAAZE,aAIMC,EAAQvD,EANPoD,EAAPnD,mJAISuD,CAAAJ,EAAArD,iBAIT,OACE0D,wBAACC,EAAOA,QAAArC,GACNsC,IAAKJ,EAAMpD,YACPoD,EAAMhB,aACNe,EAAY,CAChBD,MAAOA,IAGb"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unith-ai/react-native",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "React Native WebView wrapper for Unith AI digital humans",
5
5
  "main": "./dist/lib.js",
6
6
  "module": "./dist/lib.module.js",
@@ -20,7 +20,7 @@
20
20
  "author": "UNITH AI",
21
21
  "license": "MIT",
22
22
  "peerDependencies": {
23
- "@unith-ai/core-client": "^2.0.3-beta.2",
23
+ "@unith-ai/core-client": "^2.0.3-beta.3",
24
24
  "react": ">=16.8.0",
25
25
  "react-native": ">=0.70.0",
26
26
  "react-native-webview": ">=11.0.0"