@eka-care/medassist-widget-embed 0.2.13 → 0.2.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,55 +1,4 @@
1
- // Helper function to create and open MedAssist widget in fullscreen iframe
2
- // This eliminates the need for Sebenza app to add custom styles
3
- const DEFAULT_IFRAME_BASE = "https://unpkg.com/@eka-care/medassist-widget-embed@latest/dist/";
4
- // Get current script to determine base URL
5
- const getCurrentScript = () => {
6
- if (typeof document === "undefined") {
7
- return null;
8
- }
9
- const { currentScript } = document;
10
- if (currentScript instanceof HTMLScriptElement) {
11
- return currentScript;
12
- }
13
- const scripts = document.getElementsByTagName("script");
14
- return scripts.length ? scripts[scripts.length - 1] : null;
15
- };
16
- const getIframeBaseUrl = (customUrl) => {
17
- return customUrl || DEFAULT_IFRAME_BASE;
18
- };
19
- export const openMedAssistIframe = (options) => {
20
- const { agentId, title, iconUrl, environment, iframeBaseUrl, context } = options;
21
- if (!agentId) {
22
- console.error("Agent ID is required");
23
- return;
24
- }
25
- // Remove existing iframe if any
26
- const existingIframe = document.getElementById("medassist-iframe");
27
- if (existingIframe) {
28
- existingIframe.remove();
29
- }
30
- // Build iframe URL
31
- const baseUrl = getIframeBaseUrl(iframeBaseUrl);
32
- const iframeUrl = new URL(`${baseUrl}iframe.html`);
33
- iframeUrl.searchParams.set("agentId", agentId);
34
- if (title) {
35
- iframeUrl.searchParams.set("title", title);
36
- }
37
- if (iconUrl) {
38
- iframeUrl.searchParams.set("iconUrl", iconUrl);
39
- }
40
- if (environment) {
41
- iframeUrl.searchParams.set("environment", environment);
42
- }
43
- if (context) {
44
- iframeUrl.searchParams.set("context", JSON.stringify(context));
45
- }
46
- // Create iframe element
47
- const iframe = document.createElement("iframe");
48
- iframe.id = "medassist-iframe";
49
- iframe.src = iframeUrl.toString();
50
- iframe.setAttribute("allow", "microphone; camera");
51
- // Apply fullscreen styles automatically
52
- iframe.style.cssText = `
1
+ const h="https://unpkg.com/@eka-care/medassist-widget-embed@latest/dist/",w=()=>{if(typeof document=="undefined")return null;const{currentScript:e}=document;if(e instanceof HTMLScriptElement)return e;const t=document.getElementsByTagName("script");return t.length?t[t.length-1]:null},p=e=>e||h;export const openMedAssistIframe=e=>{const{agentId:t,title:i,iconUrl:a,environment:o,iframeBaseUrl:f,context:m}=e;if(!t){console.error("Agent ID is required");return}const c=document.getElementById("medassist-iframe");c&&c.remove();const u=p(f),n=new URL(`${u}iframe.html`);n.searchParams.set("agentId",t),i&&n.searchParams.set("title",i),a&&n.searchParams.set("iconUrl",a),o&&n.searchParams.set("environment",o),m&&n.searchParams.set("context",JSON.stringify(m));const s=document.createElement("iframe");s.id="medassist-iframe",s.src=n.toString(),s.setAttribute("allow","microphone; camera"),s.style.cssText=`
53
2
  width: 100vw;
54
3
  height: 100vh;
55
4
  height: 100dvh;
@@ -60,26 +9,4 @@ export const openMedAssistIframe = (options) => {
60
9
  left: 0;
61
10
  z-index: 9999;
62
11
  background: white;
63
- `;
64
- // Append to body
65
- document.body.appendChild(iframe);
66
- // Listen for close message from iframe
67
- const messageHandler = (event) => {
68
- // Optional: verify origin for security
69
- // if (event.origin !== "https://your-cdn.com") return;
70
- var _a;
71
- if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === "WIDGET_CLOSE") {
72
- const iframeElement = document.getElementById("medassist-iframe");
73
- if (iframeElement) {
74
- iframeElement.remove();
75
- }
76
- // Remove event listener after closing
77
- window.removeEventListener("message", messageHandler);
78
- }
79
- };
80
- window.addEventListener("message", messageHandler);
81
- };
82
- // Make it available on window for easy access
83
- if (typeof window !== "undefined") {
84
- window.openMedAssistIframe = openMedAssistIframe;
85
- }
12
+ `,document.body.appendChild(s);const d=g=>{var r;if(((r=g.data)===null||r===void 0?void 0:r.type)==="WIDGET_CLOSE"){const l=document.getElementById("medassist-iframe");l&&l.remove(),window.removeEventListener("message",d)}};window.addEventListener("message",d)};typeof window!="undefined"&&(window.openMedAssistIframe=openMedAssistIframe);
package/dist/iframe.js CHANGED
@@ -1,318 +1 @@
1
- "use strict";
2
- // Wrap in IIFE to avoid conflicts with index.ts
3
- (function () {
4
- const getCurrentScript = () => {
5
- if (typeof document === "undefined") {
6
- return null;
7
- }
8
- const { currentScript } = document;
9
- if (currentScript instanceof HTMLScriptElement) {
10
- return currentScript;
11
- }
12
- const scripts = document.getElementsByTagName("script");
13
- return scripts.length ? scripts[scripts.length - 1] : null;
14
- };
15
- const getEnvironment = (value) => {
16
- if (value === "production" ||
17
- value === "development" ||
18
- value === "staging") {
19
- return value;
20
- }
21
- return undefined;
22
- };
23
- const API_FETCH_TIMEOUT_MS = 10000;
24
- /** Map agent-config API theme to widget theme (mode → textColor: dark→black, light→white) */
25
- function mapAgentConfigThemeToWidgetTheme(apiTheme) {
26
- if (!apiTheme)
27
- return undefined;
28
- const textColor = apiTheme.mode === "dark"
29
- ? "white"
30
- : apiTheme.mode === "light"
31
- ? "black"
32
- : undefined;
33
- return {
34
- ...(apiTheme.background && { background: apiTheme.background }),
35
- ...(apiTheme.background_img && {
36
- backgroundImage: apiTheme.background_img,
37
- }),
38
- ...(apiTheme.accent && { primary: apiTheme.accent }),
39
- ...(textColor && { textColor }),
40
- ...(apiTheme.title_img && { titleImg: apiTheme.title_img }),
41
- };
42
- }
43
- /** Preload an image by URL so it is cached and loads faster when the widget uses it. */
44
- function preloadImage(url) {
45
- if (!url || typeof document === "undefined")
46
- return;
47
- try {
48
- const link = document.createElement("link");
49
- link.rel = "preload";
50
- link.as = "image";
51
- link.href = url;
52
- document.head.appendChild(link);
53
- }
54
- catch {
55
- const img = new Image();
56
- img.src = url;
57
- }
58
- }
59
- /** Fetch agent-config from API with timeout; aborts if pending > 10s */
60
- async function fetchAgentConfig(baseUrl, agentId) {
61
- const url = `${baseUrl.replace(/\/$/, "")}/med-assist/agent-config/${agentId}`;
62
- const controller = new AbortController();
63
- const timeoutId = setTimeout(() => controller.abort(), API_FETCH_TIMEOUT_MS);
64
- try {
65
- const res = await fetch(url, {
66
- signal: controller.signal,
67
- headers: {
68
- "ngrok-skip-browser-warning": "69420",
69
- },
70
- });
71
- if (!res.ok)
72
- return undefined;
73
- const json = await res.json();
74
- if ((json === null || json === void 0 ? void 0 : json.success) && (json === null || json === void 0 ? void 0 : json.data))
75
- return json.data;
76
- return undefined;
77
- }
78
- catch {
79
- return undefined;
80
- }
81
- finally {
82
- clearTimeout(timeoutId);
83
- }
84
- }
85
- const DEFAULT_WIDGET_ASSET_BASE = "https://unpkg.com/@eka-care/medassist-widget@latest/dist/";
86
- const scriptEl = getCurrentScript();
87
- const scriptBaseUrl = (() => {
88
- if (!scriptEl) {
89
- return "";
90
- }
91
- try {
92
- return new URL(".", scriptEl.src || window.location.href).href;
93
- }
94
- catch {
95
- return "";
96
- }
97
- })();
98
- const widgetAssetBaseUrl = (() => {
99
- if (!scriptEl) {
100
- return DEFAULT_WIDGET_ASSET_BASE;
101
- }
102
- const dataValue = scriptEl.dataset.widgetAssets;
103
- if (dataValue === "local") {
104
- return `${scriptBaseUrl}src/`;
105
- }
106
- if (dataValue && dataValue.length > 0) {
107
- try {
108
- return new URL(dataValue, scriptBaseUrl).href;
109
- }
110
- catch {
111
- return dataValue.endsWith("/") ? dataValue : `${dataValue}/`;
112
- }
113
- }
114
- return DEFAULT_WIDGET_ASSET_BASE;
115
- })();
116
- const WIDGET_JS_URL = `${widgetAssetBaseUrl}medassist-widget.js`;
117
- const WIDGET_CSS_URL = `${widgetAssetBaseUrl}medassist-widget.css`;
118
- let widgetScriptPromise = null;
119
- let widgetCssTextPromise = null;
120
- // --- Start loading as early as possible (don't wait for DOMContentLoaded) ---
121
- const urlParams = new URLSearchParams(typeof window !== "undefined" ? window.location.search : "");
122
- const earlyAgentId = urlParams.get("agentId");
123
- const earlyBaseUrl = urlParams.get("baseUrl") || "https://matrix.eka.care/reloaded";
124
- if (typeof document !== "undefined" && document.head) {
125
- try {
126
- const assetOrigin = new URL(widgetAssetBaseUrl).origin;
127
- const apiOrigin = new URL(earlyBaseUrl).origin;
128
- const preconnectAsset = document.createElement("link");
129
- preconnectAsset.rel = "preconnect";
130
- preconnectAsset.href = assetOrigin;
131
- preconnectAsset.crossOrigin = "anonymous";
132
- document.head.appendChild(preconnectAsset);
133
- if (assetOrigin !== apiOrigin) {
134
- const preconnectApi = document.createElement("link");
135
- preconnectApi.rel = "preconnect";
136
- preconnectApi.href = apiOrigin;
137
- preconnectApi.crossOrigin = "anonymous";
138
- document.head.appendChild(preconnectApi);
139
- }
140
- const preloadScript = document.createElement("link");
141
- preloadScript.rel = "preload";
142
- preloadScript.as = "script";
143
- preloadScript.href = WIDGET_JS_URL;
144
- document.head.appendChild(preloadScript);
145
- const preloadCss = document.createElement("link");
146
- preloadCss.rel = "preload";
147
- preloadCss.as = "style";
148
- preloadCss.href = WIDGET_CSS_URL;
149
- document.head.appendChild(preloadCss);
150
- }
151
- catch {
152
- // ignore URL/preload errors
153
- }
154
- loadWidgetCss();
155
- loadWidgetScript();
156
- }
157
- const agentConfigPromise = earlyAgentId && earlyBaseUrl
158
- ? fetchAgentConfig(earlyBaseUrl, earlyAgentId)
159
- : Promise.resolve(undefined);
160
- // Preload background image when available (theme URL param or agent-config)
161
- if (typeof document !== "undefined" && document.head) {
162
- const themeParam = urlParams.get("theme");
163
- if (themeParam) {
164
- try {
165
- const theme = JSON.parse(themeParam);
166
- if (theme.backgroundImage)
167
- preloadImage(theme.backgroundImage);
168
- }
169
- catch {
170
- // ignore
171
- }
172
- }
173
- agentConfigPromise.then((agentConfig) => {
174
- var _a;
175
- const url = (_a = agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.theme) === null || _a === void 0 ? void 0 : _a.background_img;
176
- if (url)
177
- preloadImage(url);
178
- });
179
- }
180
- // Auto-initialize from URL parameters (no shadow DOM needed in iframe)
181
- const initializeFromUrlParams = async () => {
182
- var _a, _b, _c, _d, _e;
183
- const agentId = urlParams.get("agentId");
184
- if (!agentId) {
185
- console.error("Agent ID is required in URL parameters");
186
- return;
187
- }
188
- let title = urlParams.get("title") || "Medi Clinic";
189
- let iconUrl = urlParams.get("iconUrl") || undefined;
190
- const context = urlParams.get("context");
191
- const baseUrl = urlParams.get("baseUrl") || "https://matrix.eka.care/reloaded";
192
- const environment = (_a = getEnvironment(urlParams.get("environment"))) !== null && _a !== void 0 ? _a : "production";
193
- const attributeTheme = urlParams.get("theme")
194
- ? (() => {
195
- try {
196
- return JSON.parse(urlParams.get("theme") || "{}");
197
- }
198
- catch {
199
- return undefined;
200
- }
201
- })()
202
- : undefined;
203
- const container = document.getElementById("root") || document.body;
204
- try {
205
- const [, , agentConfig] = await Promise.all([
206
- loadWidgetCss(),
207
- loadWidgetScript(),
208
- agentConfigPromise,
209
- ]);
210
- if (!(window === null || window === void 0 ? void 0 : window.renderMedAssist) ||
211
- typeof (window === null || window === void 0 ? void 0 : window.renderMedAssist) !== "function") {
212
- throw new Error("renderMedAssist is not available on window");
213
- }
214
- let apiTheme;
215
- let allowed;
216
- if (agentConfig) {
217
- title = (_b = agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.name) !== null && _b !== void 0 ? _b : title;
218
- iconUrl = (_d = (_c = agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.theme) === null || _c === void 0 ? void 0 : _c.icon_img) !== null && _d !== void 0 ? _d : iconUrl;
219
- apiTheme = mapAgentConfigThemeToWidgetTheme((_e = agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.theme) !== null && _e !== void 0 ? _e : undefined);
220
- allowed = agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.allowed;
221
- }
222
- const config = {
223
- title,
224
- iconUrl,
225
- environment,
226
- onClose: () => {
227
- if (window.parent !== window) {
228
- window.parent.postMessage({ type: "WIDGET_CLOSE" }, "*");
229
- }
230
- },
231
- context: context ? JSON.parse(context) : undefined,
232
- baseUrl,
233
- displayMode: "full",
234
- allowed,
235
- showCloseButton: false,
236
- theme: {
237
- ...(apiTheme !== null && apiTheme !== void 0 ? apiTheme : {}),
238
- ...(attributeTheme !== null && attributeTheme !== void 0 ? attributeTheme : {}),
239
- },
240
- };
241
- window.renderMedAssist(container, agentId, config);
242
- }
243
- catch (error) {
244
- console.error("Failed to initialize MedAssist widget", error);
245
- throw error;
246
- }
247
- };
248
- async function loadWidgetCss() {
249
- // Check if already loaded
250
- const existingLink = document.querySelector(`link[data-medassist-style='true']`);
251
- if (existingLink) {
252
- return;
253
- }
254
- if (!widgetCssTextPromise) {
255
- widgetCssTextPromise = new Promise((resolve, reject) => {
256
- const link = document.createElement("link");
257
- link.rel = "stylesheet";
258
- link.href = WIDGET_CSS_URL;
259
- link.setAttribute("data-medassist-style", "true");
260
- link.onload = () => {
261
- resolve("");
262
- };
263
- link.onerror = () => {
264
- reject(new Error(`Failed to load ${WIDGET_CSS_URL}`));
265
- };
266
- document.head.appendChild(link);
267
- });
268
- }
269
- await widgetCssTextPromise;
270
- }
271
- function loadWidgetScript() {
272
- if (!widgetScriptPromise) {
273
- widgetScriptPromise = new Promise((resolve, reject) => {
274
- const existingScript = document.querySelector(`script[src="${WIDGET_JS_URL}"]`);
275
- if (existingScript) {
276
- if (existingScript.dataset.loaded === "true") {
277
- resolve();
278
- return;
279
- }
280
- existingScript.addEventListener("load", () => resolve());
281
- existingScript.addEventListener("error", (event) => reject(event.error || new Error("Unknown script loading error")));
282
- return;
283
- }
284
- const script = document.createElement("script");
285
- script.src = WIDGET_JS_URL;
286
- script.async = true;
287
- script.dataset.widget = "medassist";
288
- script.onload = () => {
289
- script.dataset.loaded = "true";
290
- resolve();
291
- };
292
- script.onerror = (event) => {
293
- if (event instanceof ErrorEvent && event.error) {
294
- reject(event.error);
295
- return;
296
- }
297
- reject(new Error(`Failed to load ${WIDGET_JS_URL}`));
298
- };
299
- document.head.appendChild(script);
300
- });
301
- }
302
- return widgetScriptPromise;
303
- }
304
- // Auto-initialize when script loads
305
- if (typeof document !== "undefined") {
306
- if (document.readyState === "loading") {
307
- document.addEventListener("DOMContentLoaded", initializeFromUrlParams);
308
- }
309
- else {
310
- try {
311
- initializeFromUrlParams();
312
- }
313
- catch (error) {
314
- console.error("Failed to initialize MedAssist widget", error);
315
- }
316
- }
317
- }
318
- })();
1
+ "use strict";(function(){const L=()=>{if(typeof document=="undefined")return null;const{currentScript:e}=document;if(e instanceof HTMLScriptElement)return e;const t=document.getElementsByTagName("script");return t.length?t[t.length-1]:null},M=e=>{if(e==="production"||e==="development"||e==="staging")return e};function P(e){if(!e)return;const t=e.mode==="dark"?"white":e.mode==="light"?"black":void 0;return{...e.background&&{background:e.background},...e.background_img&&{backgroundImage:e.background_img},...e.accent&&{primary:e.accent},...t&&{textColor:t},...e.title_img&&{titleImg:e.title_img}}}function v(e){if(!(!e||typeof document=="undefined"))try{const t=document.createElement("link");t.rel="preload",t.as="image",t.href=e,document.head.appendChild(t)}catch{const t=new Image;t.src=e}}async function T(e,t){const r=`${e.replace(/\/$/,"")}/med-assist/agent-config/${t}`,n=new AbortController,o=setTimeout(()=>n.abort(),1e4);try{const c=await fetch(r,{signal:n.signal,headers:{"ngrok-skip-browser-warning":"69420"}});if(!c.ok)return;const s=await c.json();return s!=null&&s.success&&(s!=null&&s.data)?s.data:void 0}catch{return}finally{clearTimeout(o)}}const E="https://unpkg.com/@eka-care/medassist-widget@latest/dist/",a=L(),k=(()=>{if(!a)return"";try{return new URL(".",a.src||window.location.href).href}catch{return""}})(),m=(()=>{if(!a)return E;const e=a.dataset.widgetAssets;if(e==="local")return`${k}src/`;if(e&&e.length>0)try{return new URL(e,k).href}catch{return e.endsWith("/")?e:`${e}/`}return E})(),l=`${m}medassist-widget.js`,g=`${m}medassist-widget.css`;let f=null,w=null;const d=new URLSearchParams(typeof window!="undefined"?window.location.search:""),_=d.get("agentId"),p=d.get("baseUrl")||"https://matrix.eka.care/reloaded";if(typeof document!="undefined"&&document.head){try{const e=new URL(m).origin,t=new URL(p).origin,r=document.createElement("link");if(r.rel="preconnect",r.href=e,r.crossOrigin="anonymous",document.head.appendChild(r),e!==t){const c=document.createElement("link");c.rel="preconnect",c.href=t,c.crossOrigin="anonymous",document.head.appendChild(c)}const n=document.createElement("link");n.rel="preload",n.as="script",n.href=l,document.head.appendChild(n);const o=document.createElement("link");o.rel="preload",o.as="style",o.href=g,document.head.appendChild(o)}catch{}b(),A()}const C=_&&p?T(p,_):Promise.resolve(void 0);if(typeof document!="undefined"&&document.head){const e=d.get("theme");if(e)try{const t=JSON.parse(e);t.backgroundImage&&v(t.backgroundImage)}catch{}C.then(t=>{var r;const n=(r=t==null?void 0:t.theme)===null||r===void 0?void 0:r.background_img;n&&v(n)})}const S=async()=>{var e,t,r,n,o;const c=d.get("agentId");if(!c){console.error("Agent ID is required in URL parameters");return}let s=d.get("title")||"Medi Clinic",h=d.get("iconUrl")||void 0;const I=d.get("context"),O=d.get("baseUrl")||"https://matrix.eka.care/reloaded",x=(e=M(d.get("environment")))!==null&&e!==void 0?e:"production",y=d.get("theme")?(()=>{try{return JSON.parse(d.get("theme")||"{}")}catch{return}})():void 0,$=document.getElementById("root")||document.body;try{const[,,i]=await Promise.all([b(),A(),C]);if(!(window!=null&&window.renderMedAssist)||typeof(window==null?void 0:window.renderMedAssist)!="function")throw new Error("renderMedAssist is not available on window");let u,U;i&&(s=(t=i==null?void 0:i.name)!==null&&t!==void 0?t:s,h=(n=(r=i==null?void 0:i.theme)===null||r===void 0?void 0:r.icon_img)!==null&&n!==void 0?n:h,u=P((o=i==null?void 0:i.theme)!==null&&o!==void 0?o:void 0),U=i==null?void 0:i.allowed);const F={title:s,iconUrl:h,environment:x,onClose:()=>{window.parent!==window&&window.parent.postMessage({type:"WIDGET_CLOSE"},"*")},context:I?JSON.parse(I):void 0,baseUrl:O,displayMode:"full",allowed:U,showCloseButton:!1,theme:{...u!=null?u:{},...y!=null?y:{}}};window.renderMedAssist($,c,F)}catch(i){throw console.error("Failed to initialize MedAssist widget",i),i}};async function b(){document.querySelector("link[data-medassist-style='true']")||(w||(w=new Promise((t,r)=>{const n=document.createElement("link");n.rel="stylesheet",n.href=g,n.setAttribute("data-medassist-style","true"),n.onload=()=>{t("")},n.onerror=()=>{r(new Error(`Failed to load ${g}`))},document.head.appendChild(n)})),await w)}function A(){return f||(f=new Promise((e,t)=>{const r=document.querySelector(`script[src="${l}"]`);if(r){if(r.dataset.loaded==="true"){e();return}r.addEventListener("load",()=>e()),r.addEventListener("error",o=>t(o.error||new Error("Unknown script loading error")));return}const n=document.createElement("script");n.src=l,n.async=!0,n.dataset.widget="medassist",n.onload=()=>{n.dataset.loaded="true",e()},n.onerror=o=>{if(o instanceof ErrorEvent&&o.error){t(o.error);return}t(new Error(`Failed to load ${l}`))},document.head.appendChild(n)})),f}if(typeof document!="undefined")if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",S);else try{S()}catch(e){console.error("Failed to initialize MedAssist widget",e)}})();