@eka-care/medassist-widget-embed 0.2.55 → 0.2.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/eka-agents.html +101 -14
- package/dist/iframe.html +97 -43
- package/dist/iframe.js +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +7 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,7 +121,7 @@ This only affects the launcher button — the chat panel that opens on click is
|
|
|
121
121
|
|
|
122
122
|
1. **Initial load** – The script registers the custom element `<eka-medassist-widget>`.
|
|
123
123
|
2. **Button** – The element shows a floating button (or full view if `display-mode="full"`).
|
|
124
|
-
3. **Lazy load** – On first open, the script fetches the widget JS and CSS (from the same origin or from `https://
|
|
124
|
+
3. **Lazy load** – On first open, the script fetches the widget JS and CSS (from the same origin or from `https://cdn.jsdelivr.net/npm/@eka-care/medassist-widget@latest/dist/` by default).
|
|
125
125
|
4. **Isolation** – The widget runs inside Shadow DOM to avoid style and script conflicts.
|
|
126
126
|
|
|
127
127
|
To use your own widget assets (e.g. after building [@eka-care/medassist-widget](https://www.npmjs.com/package/@eka-care/medassist-widget)), host `medassist-widget.js` and `medassist-widget.css` and point the script via the `data-widget-assets` attribute:
|
package/dist/eka-agents.html
CHANGED
|
@@ -7,14 +7,18 @@
|
|
|
7
7
|
<title>MedAssist</title>
|
|
8
8
|
|
|
9
9
|
<!-- Warm connections early. crossorigin must match the actual request mode. -->
|
|
10
|
-
<link rel="preconnect" href="https://
|
|
10
|
+
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
|
|
11
11
|
<link rel="preconnect" href="https://matrix.eka.care" crossorigin />
|
|
12
|
+
<!-- Icon/asset host (default bot icon + config icon_img/background). -->
|
|
13
|
+
<link rel="preconnect" href="https://cdn.eka.care" crossorigin />
|
|
12
14
|
|
|
13
|
-
<!-- Start widget JS download immediately during head parse (high priority).
|
|
15
|
+
<!-- Start widget JS download immediately during head parse (high priority).
|
|
16
|
+
modulepreload (not preload as=script): the widget entry is an ES module,
|
|
17
|
+
and classic preload's no-CORS fetch mode mismatches the module loader's
|
|
18
|
+
CORS mode — the browser would download it twice. -->
|
|
14
19
|
<link
|
|
15
|
-
rel="
|
|
16
|
-
|
|
17
|
-
href="https://unpkg.com/@eka-care/medassist-widget@0.1.83/dist/medassist-widget.js"
|
|
20
|
+
rel="modulepreload"
|
|
21
|
+
href="https://cdn.jsdelivr.net/npm/@eka-care/medassist-widget@0.1.85/dist/medassist-widget.js"
|
|
18
22
|
fetchpriority="high"
|
|
19
23
|
crossorigin
|
|
20
24
|
/>
|
|
@@ -23,23 +27,54 @@
|
|
|
23
27
|
<link
|
|
24
28
|
rel="preload"
|
|
25
29
|
as="style"
|
|
26
|
-
href="https://
|
|
30
|
+
href="https://cdn.jsdelivr.net/npm/@eka-care/medassist-widget@0.1.85/dist/medassist-widget.css"
|
|
27
31
|
onload="this.rel='stylesheet'"
|
|
28
32
|
crossorigin
|
|
29
33
|
/>
|
|
30
34
|
<noscript>
|
|
31
35
|
<link
|
|
32
36
|
rel="stylesheet"
|
|
33
|
-
href="https://
|
|
37
|
+
href="https://cdn.jsdelivr.net/npm/@eka-care/medassist-widget@0.1.85/dist/medassist-widget.css"
|
|
34
38
|
/>
|
|
35
39
|
</noscript>
|
|
36
40
|
|
|
37
41
|
<style>
|
|
38
42
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
39
|
-
html,body{width:100%;height:100%;overflow:hidden;background:#1a1a1a
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
html,body{width:100%;height:100%;overflow:hidden;background:#1a1a1a;
|
|
44
|
+
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
|
|
45
|
+
|
|
46
|
+
/* Zero-JS skeleton that mirrors the real widget shell (header + empty
|
|
47
|
+
state + composer) so the user sees the chat layout instantly instead
|
|
48
|
+
of a bare spinner while the widget JS downloads. React clears #root
|
|
49
|
+
(container.textContent="") on mount, removing all of this. */
|
|
50
|
+
#root{width:100vw;height:100dvh;display:flex;flex-direction:column;color:#fff}
|
|
51
|
+
|
|
52
|
+
.sk-header{display:flex;align-items:center;gap:12px;padding:12px 24px}
|
|
53
|
+
.sk-avatar{width:48px;height:48px;border-radius:50%;flex-shrink:0;overflow:hidden;background:#2a2a2a}
|
|
54
|
+
.sk-avatar img{width:100%;height:100%;object-fit:cover}
|
|
55
|
+
.sk-htext{display:flex;flex-direction:column;gap:7px;flex:1;min-width:0}
|
|
56
|
+
.sk-title{font-size:18px;font-weight:600;color:#fff;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
57
|
+
.sk-status{display:flex;align-items:center;gap:6px;font-size:12px;color:#9a9a9a}
|
|
58
|
+
.sk-dot{width:8px;height:8px;border-radius:50%;background:#f5a623;animation:pulse 1.2s ease-in-out infinite}
|
|
59
|
+
.sk-hicons{display:flex;gap:8px;flex-shrink:0}
|
|
60
|
+
.sk-icon{width:32px;height:32px;border-radius:50%;background:#2a2a2a}
|
|
61
|
+
|
|
62
|
+
.sk-body{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;padding:24px}
|
|
63
|
+
.sk-bigicon{width:64px;height:64px;border-radius:50%;background:#2a2a2a}
|
|
64
|
+
|
|
65
|
+
.sk-line{height:14px;border-radius:7px;background:#2a2a2a}
|
|
66
|
+
|
|
67
|
+
.sk-composer{margin:0 auto 24px;width:min(640px,calc(100% - 32px));height:52px;
|
|
68
|
+
border-radius:26px;background:#242424;border:1px solid #333;display:flex;align-items:center;padding:0 18px}
|
|
69
|
+
.sk-composer-text{height:12px;width:160px;border-radius:6px;background:#333}
|
|
70
|
+
|
|
71
|
+
/* Shimmer sweep across placeholder blocks. */
|
|
72
|
+
.shimmer{position:relative;overflow:hidden}
|
|
73
|
+
.shimmer::after{content:"";position:absolute;inset:0;transform:translateX(-100%);
|
|
74
|
+
background:linear-gradient(90deg,transparent,rgba(255,255,255,.06),transparent);animation:sh 1.4s infinite}
|
|
75
|
+
|
|
76
|
+
@keyframes sh{100%{transform:translateX(100%)}}
|
|
77
|
+
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
|
|
43
78
|
</style>
|
|
44
79
|
|
|
45
80
|
<!-- Kick off agent-config fetch in parallel with widget JS download. -->
|
|
@@ -58,11 +93,63 @@
|
|
|
58
93
|
</script>
|
|
59
94
|
</head>
|
|
60
95
|
<body>
|
|
61
|
-
|
|
96
|
+
<!-- Skeleton shell rendered immediately (no JS, no widget bundle needed).
|
|
97
|
+
Populated synchronously below with the title/icon from URL params when
|
|
98
|
+
present so real content shows the instant the HTML parses. -->
|
|
99
|
+
<div id="root" aria-busy="true">
|
|
100
|
+
<div class="sk-header">
|
|
101
|
+
<div class="sk-avatar shimmer" id="sk-avatar"></div>
|
|
102
|
+
<div class="sk-htext">
|
|
103
|
+
<div class="sk-title sk-title-shimmer shimmer" id="sk-title" style="width:160px;height:18px;border-radius:7px;background:#2a2a2a"> </div>
|
|
104
|
+
<div class="sk-status"><span class="sk-dot"></span><span>Connecting…</span></div>
|
|
105
|
+
</div>
|
|
106
|
+
<div class="sk-hicons">
|
|
107
|
+
<div class="sk-icon shimmer"></div>
|
|
108
|
+
<div class="sk-icon shimmer"></div>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<div class="sk-body">
|
|
113
|
+
<div class="sk-bigicon shimmer" id="sk-bigicon"></div>
|
|
114
|
+
<div class="sk-line shimmer" style="width:220px"></div>
|
|
115
|
+
<div class="sk-line shimmer" style="width:300px;max-width:100%;height:10px"></div>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div class="sk-composer">
|
|
119
|
+
<div class="sk-composer-text shimmer"></div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<!-- Fill the skeleton's title/icon from URL params synchronously, so the
|
|
124
|
+
shell shows real content before any bundle loads. Config-derived
|
|
125
|
+
values arrive later via init() when the real widget mounts. -->
|
|
126
|
+
<script>
|
|
127
|
+
(function(){
|
|
128
|
+
var p=new URLSearchParams(location.search);
|
|
129
|
+
var title=p.get("title");
|
|
130
|
+
if(title){
|
|
131
|
+
var t=document.getElementById("sk-title");
|
|
132
|
+
t.textContent=title;
|
|
133
|
+
t.className="sk-title";
|
|
134
|
+
t.removeAttribute("style");
|
|
135
|
+
}
|
|
136
|
+
var icon=p.get("icon-url");
|
|
137
|
+
if(icon){
|
|
138
|
+
var mk=function(el){if(!el)return;el.classList.remove("shimmer");var i=new Image();i.alt="";i.src=icon;el.appendChild(i);};
|
|
139
|
+
mk(document.getElementById("sk-avatar"));
|
|
140
|
+
mk(document.getElementById("sk-bigicon"));
|
|
141
|
+
}
|
|
142
|
+
})();
|
|
143
|
+
</script>
|
|
62
144
|
|
|
63
|
-
<!-- Production: served from
|
|
145
|
+
<!-- Production: served from jsDelivr (brotli + multi-CDN). For local dev swap with: <script type="module" src="./src/medassist-widget.js" onload="init()" async></script> -->
|
|
146
|
+
<!-- type="module" is required: the widget entry is an ES module (static
|
|
147
|
+
import/export of the main chunk) — a classic script would throw
|
|
148
|
+
"Cannot use import statement outside a module" and
|
|
149
|
+
window.renderMedAssist would never be set. -->
|
|
64
150
|
<script
|
|
65
|
-
|
|
151
|
+
type="module"
|
|
152
|
+
src="https://cdn.jsdelivr.net/npm/@eka-care/medassist-widget@0.1.85/dist/medassist-widget.js"
|
|
66
153
|
onload="init()"
|
|
67
154
|
fetchpriority="high"
|
|
68
155
|
crossorigin
|
package/dist/iframe.html
CHANGED
|
@@ -5,56 +5,110 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>MedAssist Widget</title>
|
|
7
7
|
|
|
8
|
-
<!--
|
|
9
|
-
|
|
10
|
-
<link rel="
|
|
8
|
+
<!-- Resource hints for faster loading (iframe.js adds modulepreload/preload
|
|
9
|
+
for the widget JS/CSS dynamically once it resolves the asset base URL) -->
|
|
10
|
+
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin/>
|
|
11
|
+
<link rel="dns-prefetch" href="https://cdn.jsdelivr.net"/>
|
|
12
|
+
<link rel="preconnect" href="https://matrix.eka.care" crossorigin/>
|
|
11
13
|
<style>
|
|
12
|
-
*
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
14
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
15
|
+
html,body{width:100%;height:100%;overflow:hidden;position:fixed;top:0;left:0;background-color:#1a1a1a;
|
|
16
|
+
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
|
|
17
|
+
|
|
18
|
+
/* Zero-JS skeleton that mirrors the real widget shell (header + empty
|
|
19
|
+
state + composer) so the user sees the chat layout instantly instead
|
|
20
|
+
of a bare spinner while the widget JS downloads. React (createRoot)
|
|
21
|
+
clears #root on mount, removing all of this.
|
|
22
|
+
The dark background MUST live on #root (not just body): iframe.js
|
|
23
|
+
appends the widget stylesheet to the end of <head>, and the widget's
|
|
24
|
+
`body{background-color:hsl(var(--background))}` is a light color — so it
|
|
25
|
+
would override body and flash white through a transparent #root before
|
|
26
|
+
React mounts. The widget CSS has no #root selector, so this stays dark. */
|
|
27
|
+
#root{width:100vw;height:100vh;height:100dvh;display:flex;flex-direction:column;color:#fff;background-color:#1a1a1a}
|
|
28
|
+
|
|
29
|
+
.sk-header{display:flex;align-items:center;gap:12px;padding:12px 24px}
|
|
30
|
+
.sk-avatar{width:48px;height:48px;border-radius:50%;flex-shrink:0;overflow:hidden;background:#2a2a2a}
|
|
31
|
+
.sk-avatar img{width:100%;height:100%;object-fit:cover}
|
|
32
|
+
.sk-htext{display:flex;flex-direction:column;gap:7px;flex:1;min-width:0}
|
|
33
|
+
.sk-title{font-size:18px;font-weight:600;color:#fff;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
34
|
+
.sk-status{display:flex;align-items:center;gap:6px;font-size:12px;color:#9a9a9a}
|
|
35
|
+
.sk-dot{width:8px;height:8px;border-radius:50%;background:#f5a623;animation:pulse 1.2s ease-in-out infinite}
|
|
36
|
+
.sk-hicons{display:flex;gap:8px;flex-shrink:0}
|
|
37
|
+
.sk-icon{width:32px;height:32px;border-radius:50%;background:#2a2a2a}
|
|
38
|
+
|
|
39
|
+
.sk-body{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;padding:24px}
|
|
40
|
+
.sk-bigicon{width:64px;height:64px;border-radius:50%;background:#2a2a2a}
|
|
41
|
+
|
|
42
|
+
.sk-line{height:14px;border-radius:7px;background:#2a2a2a}
|
|
43
|
+
|
|
44
|
+
.sk-composer{margin:0 auto 24px;width:min(640px,calc(100% - 32px));height:52px;
|
|
45
|
+
border-radius:26px;background:#242424;border:1px solid #333;display:flex;align-items:center;padding:0 18px}
|
|
46
|
+
.sk-composer-text{height:12px;width:160px;border-radius:6px;background:#333}
|
|
47
|
+
|
|
48
|
+
/* Shimmer sweep across placeholder blocks. */
|
|
49
|
+
.shimmer{position:relative;overflow:hidden}
|
|
50
|
+
.shimmer::after{content:"";position:absolute;inset:0;transform:translateX(-100%);
|
|
51
|
+
background:linear-gradient(90deg,transparent,rgba(255,255,255,.06),transparent);animation:sh 1.4s infinite}
|
|
52
|
+
|
|
53
|
+
@keyframes sh{100%{transform:translateX(100%)}}
|
|
54
|
+
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
|
|
49
55
|
</style>
|
|
50
56
|
</head>
|
|
51
57
|
<body>
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
<!-- Skeleton shell rendered immediately (no JS, no widget bundle needed).
|
|
59
|
+
Populated synchronously below with the title/icon from URL params when
|
|
60
|
+
present so real content shows the instant the HTML parses. iframe.js
|
|
61
|
+
then mounts the real widget into #root, replacing this. -->
|
|
62
|
+
<div id="root" aria-busy="true">
|
|
63
|
+
<div class="sk-header">
|
|
64
|
+
<div class="sk-avatar shimmer" id="sk-avatar"></div>
|
|
65
|
+
<div class="sk-htext">
|
|
66
|
+
<div class="sk-title sk-title-shimmer shimmer" id="sk-title" style="width:160px;height:18px;border-radius:7px;background:#2a2a2a"> </div>
|
|
67
|
+
<div class="sk-status"><span class="sk-dot"></span><span>Connecting…</span></div>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="sk-hicons">
|
|
70
|
+
<div class="sk-icon shimmer"></div>
|
|
71
|
+
<div class="sk-icon shimmer"></div>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<div class="sk-body">
|
|
76
|
+
<div class="sk-bigicon shimmer" id="sk-bigicon"></div>
|
|
77
|
+
<div class="sk-line shimmer" style="width:220px"></div>
|
|
78
|
+
<div class="sk-line shimmer" style="width:300px;max-width:100%;height:10px"></div>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<div class="sk-composer">
|
|
82
|
+
<div class="sk-composer-text shimmer"></div>
|
|
83
|
+
</div>
|
|
54
84
|
</div>
|
|
85
|
+
|
|
86
|
+
<!-- Fill the skeleton's title/icon from URL params synchronously, so the
|
|
87
|
+
shell shows real content before any bundle loads. iframe.js reads the
|
|
88
|
+
same param names (camelCase: title, iconUrl). Config-derived values
|
|
89
|
+
(agent name/icon) arrive later when the real widget mounts. -->
|
|
90
|
+
<script>
|
|
91
|
+
(function(){
|
|
92
|
+
var p=new URLSearchParams(location.search);
|
|
93
|
+
var title=p.get("title");
|
|
94
|
+
if(title){
|
|
95
|
+
var t=document.getElementById("sk-title");
|
|
96
|
+
t.textContent=title;
|
|
97
|
+
t.className="sk-title";
|
|
98
|
+
t.removeAttribute("style");
|
|
99
|
+
}
|
|
100
|
+
var icon=p.get("iconUrl");
|
|
101
|
+
if(icon){
|
|
102
|
+
var mk=function(el){if(!el)return;el.classList.remove("shimmer");var i=new Image();i.alt="";i.src=icon;el.appendChild(i);};
|
|
103
|
+
mk(document.getElementById("sk-avatar"));
|
|
104
|
+
mk(document.getElementById("sk-bigicon"));
|
|
105
|
+
}
|
|
106
|
+
})();
|
|
107
|
+
</script>
|
|
108
|
+
|
|
55
109
|
<!-- for local development -->
|
|
56
110
|
<!-- <script src="./iframe.js" data-widget-assets="local" async></script> -->
|
|
57
|
-
|
|
111
|
+
|
|
58
112
|
<!-- for production -->
|
|
59
113
|
<script src="./iframe.js" async></script>
|
|
60
114
|
</body>
|
package/dist/iframe.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";(function(){const
|
|
1
|
+
"use strict";(function(){const F=()=>{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},R=e=>{if(e==="production"||e==="development"||e==="staging")return e};function B(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.mode&&{mode:e.mode},...e.header_tinted!==void 0&&{headerTinted:e.header_tinted},...e.title_img&&{titleImg:e.title_img},...e.tagline&&{tagline:e.tagline}}}function _(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 D(e,t){const r=`${e.replace(/\/$/,"")}/med-assist/agent-config/${t}`,n=new AbortController,i=setTimeout(()=>n.abort(),1e4);try{const s=await fetch(r,{signal:n.signal,headers:{"ngrok-skip-browser-warning":"69420"}});if(!s.ok)return;const c=await s.json();return c!=null&&c.success&&(c!=null&&c.data)?c.data:void 0}catch{return}finally{clearTimeout(i)}}const C="https://cdn.jsdelivr.net/npm/@eka-care/medassist-widget@0.1.85/dist/",a=F(),S=(()=>{if(!a)return"";try{return new URL(".",a.src||window.location.href).href}catch{return""}})(),m=(()=>{if(!a)return C;const e=a.dataset.widgetAssets;if(e==="local")return`${S}src/`;if(e&&e.length>0)try{return new URL(e,S).href}catch{return e.endsWith("/")?e:`${e}/`}return C})(),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:""),b=d.get("agentId"),h=d.get("baseUrl")||"https://matrix.eka.care/reloaded";if(typeof document!="undefined"&&document.head){try{const e=new URL(m).origin,t=new URL(h).origin,r=document.createElement("link");if(r.rel="preconnect",r.href=e,r.crossOrigin="anonymous",document.head.appendChild(r),e!==t){const s=document.createElement("link");s.rel="preconnect",s.href=t,s.crossOrigin="anonymous",document.head.appendChild(s)}const n=document.createElement("link");n.rel="modulepreload",n.href=l,document.head.appendChild(n);const i=document.createElement("link");i.rel="preload",i.as="style",i.href=g,document.head.appendChild(i)}catch{}U(),L()}const A=b&&h?D(h,b):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&&_(t.backgroundImage)}catch{}A.then(t=>{var r;const n=(r=t==null?void 0:t.theme)===null||r===void 0?void 0:r.background_img;n&&_(n)})}const I=async()=>{var e,t,r,n,i,s,c;const M=d.get("agentId");if(!M){console.error("Agent ID is required in URL parameters");return}let p=d.get("title")||"Medi Clinic",v=d.get("iconUrl")||void 0;const P=d.get("context"),z=d.get("baseUrl")||"https://matrix.eka.care/reloaded",T=d.get("auth-token")||void 0;let y=d.get("resize")==="true"?!0:void 0;const G=(e=R(d.get("environment")))!==null&&e!==void 0?e:"production",k=d.get("connectivity"),J=k==="sse"||k==="socket"?k:void 0,E=d.get("theme")?(()=>{try{return JSON.parse(d.get("theme")||"{}")}catch{return}})():void 0,N=document.getElementById("root")||document.body;try{const[,,o]=await Promise.all([U(),L(),A]);if(!(window!=null&&window.renderMedAssist)||typeof(window==null?void 0:window.renderMedAssist)!="function")throw new Error("renderMedAssist is not available on window");let u,O,x,$,W=!1;o&&(p=(t=o==null?void 0:o.name)!==null&&t!==void 0?t:p,v=(n=(r=o==null?void 0:o.theme)===null||r===void 0?void 0:r.icon_img)!==null&&n!==void 0?n:v,u=B((i=o==null?void 0:o.theme)!==null&&i!==void 0?i:void 0),O=o==null?void 0:o.allowed,x=o==null?void 0:o.connectivity,$=o==null?void 0:o.initial_message,W=(c=(s=o==null?void 0:o.theme)===null||s===void 0?void 0:s.hide_watermark)!==null&&c!==void 0?c:!1,y=y||(o==null?void 0:o.resize)||void 0);const q={title:p,iconUrl:v,environment:G,connectionType:x||J||"socket",onClose:()=>{window.parent!==window&&window.parent.postMessage({type:"WIDGET_CLOSE"},"*")},context:P?JSON.parse(P):void 0,baseUrl:z,displayMode:"full",allowed:O,showCloseButton:!1,resize:y,initialMessage:$,hideWatermark:W,...T&&{authToken:T},theme:{...u!=null?u:{},...E!=null?E:{}}};window.renderMedAssist(N,M,q)}catch(o){throw console.error("Failed to initialize MedAssist widget",o),o}};async function U(){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 L(){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",i=>t(i.error||new Error("Unknown script loading error")));return}const n=document.createElement("script");n.src=l,n.type="module",n.async=!0,n.dataset.widget="medassist",n.onload=()=>{n.dataset.loaded="true",e()},n.onerror=i=>{if(i instanceof ErrorEvent&&i.error){t(i.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",I);else try{I()}catch(e){console.error("Failed to initialize MedAssist widget",e)}})();
|
package/dist/index.d.ts
CHANGED
|
@@ -125,7 +125,10 @@ declare const scriptBaseUrl: string;
|
|
|
125
125
|
declare const widgetAssetBaseUrl: string;
|
|
126
126
|
declare const WIDGET_JS_URL: string;
|
|
127
127
|
declare const WIDGET_CSS_URL: string;
|
|
128
|
-
|
|
128
|
+
type WidgetModule = {
|
|
129
|
+
renderMedAssist: (container: HTMLElement, agentId: string, config: MedAssistInitConfig) => ReactRoot;
|
|
130
|
+
};
|
|
131
|
+
declare let widgetModulePromise: Promise<WidgetModule> | null;
|
|
129
132
|
declare let widgetCssTextPromise: Promise<string> | null;
|
|
130
133
|
/** Start fetching widget CSS (shared promise). Used for preload and by loadWidgetCss. */
|
|
131
134
|
declare function getWidgetCssTextPromise(): Promise<string>;
|
|
@@ -139,6 +142,8 @@ declare class MedAssistWidgetLoader extends HTMLElement {
|
|
|
139
142
|
constructor();
|
|
140
143
|
static get observedAttributes(): string[];
|
|
141
144
|
connectedCallback(): void;
|
|
145
|
+
/** Run work when the browser is idle, falling back to a short timeout. */
|
|
146
|
+
private scheduleIdle;
|
|
142
147
|
attributeChangedCallback(name: string): void;
|
|
143
148
|
/** When in widget mode, start loading JS and CSS on page load so first open is faster. */
|
|
144
149
|
private preloadWidgetAssets;
|
|
@@ -155,6 +160,6 @@ declare class MedAssistWidgetLoader extends HTMLElement {
|
|
|
155
160
|
initializeFullMode(): void;
|
|
156
161
|
loadAndRender(): Promise<void>;
|
|
157
162
|
loadWidgetCss(): Promise<void>;
|
|
158
|
-
|
|
163
|
+
loadWidgetModule(): Promise<WidgetModule>;
|
|
159
164
|
}
|
|
160
165
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";const getCurrentScript=()=>{if(typeof document=="undefined")return console.error("document is not defined"),null;const{currentScript:e}=document;if(e instanceof HTMLScriptElement)return e;const t=document.getElementsByTagName("script");return t.length?t[t.length-1]:null},getEnvironment=e=>{if(e==="production"||e==="development"||e==="staging")return e},scriptEl=getCurrentScript(),DEFAULT_WIDGET_ASSET_BASE=(()=>{var e;return!((e=scriptEl==null?void 0:scriptEl.src)===null||e===void 0)&&e.includes("@dev")?"https://unpkg.com/@eka-care/medassist-widget@dev/dist/":"https://unpkg.com/@eka-care/medassist-widget@latest/dist/"})();function mapAgentConfigThemeToWidgetTheme(e){if(!e)return;const t=e.mode==="dark"?"white":e.mode==="light"?"black":void 0;return{...e.background_img&&{backgroundImage:e.background_img},...e.accent&&{primary:e.accent},...t&&{textColor:t},...e.mode&&{mode:e.mode},...e.header_tinted!==void 0&&{headerTinted:e.header_tinted},...e.title_img&&{titleImg:e.title_img},...e.tagline&&{tagline:e.tagline}}}function preloadImage(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 fetchAgentConfig(e,t){const o=`${e.replace(/\/$/,"")}/med-assist/agent-config/${t}`,i=await fetch(o,{headers:{"ngrok-skip-browser-warning":"69420"}});if(!i.ok)return;const n=await i.json();if(n!=null&&n.success&&(n!=null&&n.data))return n.data}const NUDGE_STORAGE_KEY="eka-medassist-nudges";function getNudgeStore(){try{const e=localStorage.getItem(NUDGE_STORAGE_KEY);return e?JSON.parse(e):{}}catch{return{}}}function setNudgeStore(e){try{localStorage.setItem(NUDGE_STORAGE_KEY,JSON.stringify(e))}catch{}}function normalizePath(e){let t=e.replace(/\/+$/,"");return t.startsWith("/")||(t="/"+t),t||"/"}function findCachedNudge(e,t){const i=getNudgeStore()[e];if(!i)return null;let n;try{n=new URL(t)}catch{return null}const s=n.host,r=i[s];if(!r)return null;const d=n.pathname.split("/").filter(Boolean),u=[];for(let c=d.length;c>=0;c--)u.push(c===0?"/":"/"+d.slice(0,c).join("/"));for(const c of u){if(r[c]!==void 0)return{domain:s,path:c,data:r[c]};const l=c==="/"?"/*":c+"/*";if(r[l]!==void 0)return{domain:s,path:l,data:r[l]}}return null}function clearNudgeForPath(e,t,o){const i=getNudgeStore(),n=i[e];!n||!n[t]||(delete n[t][o],setNudgeStore(i))}function storeNudgeResponse(e,t){var o,i,n,s;const r=(o=t==null?void 0:t.url_pattern)===null||o===void 0?void 0:o.domain,d=(i=t==null?void 0:t.url_pattern)===null||i===void 0?void 0:i.path;if(!(!((n=t.nudges)===null||n===void 0)&&n.length)||!t.expiry||!r||!d)return;const u=getNudgeStore();u[e]||(u[e]={}),u[e][r]||(u[e][r]={}),u[e][r][d]={nudges:t.nudges,expiry:t.expiry,delay:(s=t.delay)!==null&&s!==void 0?s:5},setNudgeStore(u)}const NUDGE_COOKIE_PREFIX="eka-nudge";function setNudgeCookie(e,t){const o=new Date(Date.now()+864e5).toUTCString();document.cookie=`${NUDGE_COOKIE_PREFIX}-${e}=${t}; expires=${o}; path=/; SameSite=Lax`}function getNudgeCookie(e){const t=document.cookie.split(";").map(i=>i.trim()).find(i=>i.startsWith(`${NUDGE_COOKIE_PREFIX}-${e}=`));if(!t)return null;const o=t.split("=")[1];return o==="open"||o==="closed"?o:null}async function fetchNudgeData(e,t){const o=`${t}/med-assist/user-nudge`,i=[];typeof document!="undefined"&&document.querySelectorAll("meta").forEach(n=>{var s,r,d;const u=(s=n.getAttribute("name"))!==null&&s!==void 0?s:void 0,c=(r=n.getAttribute("property"))!==null&&r!==void 0?r:void 0,l=(d=n.getAttribute("content"))!==null&&d!==void 0?d:void 0;(u||c)&&i.push({name:u,property:c,content:l})});try{const n=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json","x-agent-id":e,referer:typeof window!="undefined"?window.location.href:""},body:JSON.stringify({meta_tags:i,url:typeof window!="undefined"?window.location.href:""})});return n.ok?await n.json():void 0}catch{return}}const globalMedAssistConfig={},getWidgetElement=()=>typeof document=="undefined"?null:document.querySelector("eka-medassist-widget");if(typeof window!="undefined"){const e=window;e.__ekaMedAssistConfig__=globalMedAssistConfig,e.EkaMedAssist={init(t){var o,i,n;Object.assign(globalMedAssistConfig,t);const s=getWidgetElement();if(s){if(t.agentId&&s.setAttribute("agent-id",t.agentId),t.authToken&&s.setAttribute("auth-token",t.authToken),t.title&&s.setAttribute("title",t.title),t.iconUrl&&s.setAttribute("icon-url",t.iconUrl),t.baseUrl&&s.setAttribute("base-url",t.baseUrl),t.resize!==void 0&&s.setAttribute("resize",String(t.resize)),(t.displayMode==="full"||t.displayMode==="widget")&&s.setAttribute("display-mode",t.displayMode),t.context)try{s.setAttribute("context",JSON.stringify(t.context))}catch{console.warn("Failed to stringify context passed to init")}typeof t.customLauncherStyles=="string"&&s.setAttribute("custom-launcher-styles",t.customLauncherStyles),t.redirectUrl&&s.setAttribute("redirect-url",t.redirectUrl),!((o=t.theme)===null||o===void 0)&&o.backgroundImage&&preloadImage(t.theme.backgroundImage),(n=(i=s).openFromBridge)===null||n===void 0||n.call(i)}}}}const scriptBaseUrl=(()=>{if(!scriptEl)return"";try{return new URL(".",scriptEl.src||window.location.href).href}catch{return""}})(),widgetAssetBaseUrl=(()=>{if(!scriptEl)return DEFAULT_WIDGET_ASSET_BASE;const e=scriptEl.dataset.widgetAssets;if(e==="local")return`${scriptBaseUrl}src/`;if(e&&e.length>0)try{return new URL(e,scriptBaseUrl).href}catch{return e.endsWith("/")?e:`${e}/`}return DEFAULT_WIDGET_ASSET_BASE})(),WIDGET_JS_URL=`${widgetAssetBaseUrl}medassist-widget.js`,WIDGET_CSS_URL=`${widgetAssetBaseUrl}medassist-widget.css`;let widgetScriptPromise=null,widgetCssTextPromise=null;function getWidgetCssTextPromise(){return widgetCssTextPromise||(widgetCssTextPromise=fetch(WIDGET_CSS_URL).then(e=>{if(!e.ok)throw new Error(`Unable to fetch widget styles from ${WIDGET_CSS_URL}`);return e.text()})),widgetCssTextPromise}class MedAssistWidgetLoader extends HTMLElement{getAgentConfig(){if(!this.agentConfigPromise){const t=(typeof window!="undefined"?window.__ekaMedAssistConfig__:void 0)||{},o=t.baseUrl||this.getAttribute("base-url")||"https://matrix.eka.care/reloaded",i=t.agentId||this.getAttribute("agent-id")||"";if(!i)return Promise.resolve(void 0);this.agentConfigPromise=fetchAgentConfig(o,i).catch(()=>{})}return this.agentConfigPromise}constructor(){super(),this.reactRoot=null,this.agentConfigPromise=null,this.attachShadow({mode:"open"}),this.defaultIconUrl="https://cdn.eka.care/bot-icon.svg",this.widgetLoaded=!1,this.displayMode=this.getAttribute("display-mode")==="full"?"full":"widget",this.setupAuthExpirationListener()}static get observedAttributes(){return["icon-url","display-mode","custom-launcher-styles","redirect-url"]}connectedCallback(){this.displayMode==="full"?(this.initializeFullMode(),this.loadWidgetCss().then(()=>this.loadWidgetScript()).then(()=>this.loadAndRender()).catch(t=>{console.error("Failed to load MedAssist widget in full mode",t)})):(this.renderButton(),this.preloadWidgetAssets(),this.initNudge())}attributeChangedCallback(t){if(t==="icon-url"&&this.displayMode==="widget"&&this.renderButton(),t==="display-mode"){const o=this.getAttribute("display-mode")==="full"?"full":"widget";o!==this.displayMode&&(this.displayMode=o,o==="full"?this.initializeFullMode():this.renderButton())}t==="custom-launcher-styles"&&this.applyCustomLauncherStyles()}preloadWidgetAssets(){getWidgetCssTextPromise(),this.loadWidgetScript(),this.preloadBackgroundImage()}preloadBackgroundImage(){var t;const o=typeof window!="undefined"?window.__ekaMedAssistConfig__:void 0,i=this.getAttribute("theme")?(()=>{try{return JSON.parse(this.getAttribute("theme")||"{}")}catch{return}})():void 0,n=(t=o==null?void 0:o.theme)===null||t===void 0?void 0:t.backgroundImage,s=i==null?void 0:i.backgroundImage;n&&preloadImage(n),s&&s!==n&&preloadImage(s),this.getAgentConfig().then(r=>{var d;const u=(d=r==null?void 0:r.theme)===null||d===void 0?void 0:d.background_img;u&&preloadImage(u)}).catch(()=>{})}setupAuthExpirationListener(){if(typeof window=="undefined")return;const t=o=>{var i;((i=o.data)===null||i===void 0?void 0:i.type)==="AUTH_EXPIRED"&&window.parent!==window&&window.parent.postMessage({type:"AUTH_EXPIRED",message:"Authentication expired"},"*")};window.addEventListener("message",t)}openFromBridge(){this.displayMode=this.getAttribute("display-mode")==="full"?"full":"widget",this.displayMode==="full"?this.initializeFullMode():this.renderButton(),this.loadWidgetCss().then(()=>this.loadWidgetScript()).then(()=>this.loadAndRender()).catch(t=>{console.error("Failed to open MedAssist widget from bridge",t)})}async initNudge(){var t,o,i,n;const s=typeof window!="undefined"?window.__ekaMedAssistConfig__:void 0,r=(s==null?void 0:s.agentId)||this.getAttribute("agent-id")||"";if(!r)return;const d=await this.getAgentConfig();if(!(d!=null&&d.nudge))return;const u=(o=(t=d==null?void 0:d.theme)===null||t===void 0?void 0:t.nudge_color)!==null&&o!==void 0?o:"#ffffff",c=typeof window!="undefined"?window.location.href:"";let l=findCachedNudge(r,c);if(l){const f=Math.floor(Date.now()/1e3);l.data.expiry<=f&&(clearNudgeForPath(r,l.domain,l.path),l=null)}if(!l){const f=typeof window!="undefined"?window.__ekaMedAssistConfig__:void 0,m=(f==null?void 0:f.baseUrl)||this.getAttribute("base-url")||"https://matrix.eka.care/reloaded",w=await fetchNudgeData(r,m).catch(()=>{});if(!(!((i=w==null?void 0:w.nudges)===null||i===void 0)&&i.length)||(storeNudgeResponse(r,w),l=findCachedNudge(r,c),!l))return}const h=l.data.nudges[Math.floor(Math.random()*l.data.nudges.length)],p=(n=l.data.delay)!==null&&n!==void 0?n:5;setTimeout(()=>{this.showNudgePopup(h,u)},p*1e3)}showNudgePopup(t,o){var i,n;const s=this.shadowRoot;if(!s||!(!((i=s.getElementById("medassist-widget-root"))===null||i===void 0)&&i.classList.contains("hidden")))return;const d=((typeof window!="undefined"?window.__ekaMedAssistConfig__:void 0)||{}).agentId||this.getAttribute("agent-id")||"";if(d&&getNudgeCookie(d)!==null||s.getElementById("medassist-nudge-popup"))return;const c=s.getElementById("medassist-open-btn"),l=c==null?void 0:c.getBoundingClientRect(),h=272,p=12,f=8,m=16,w=16;let y=window.innerWidth-h-p,v=76,x=h-m-f*2;if(l&&l.width>0){const g=l.left+l.width/2,A=g-h/2,_=window.innerWidth-h-p;y=Math.max(p,Math.min(A,_)),v=window.innerHeight-l.top+w,x=Math.max(m,Math.min(g-y-f,h-m-f*2))}const b=document.createElement("div");b.id="medassist-nudge-popup",b.innerHTML=`
|
|
1
|
+
"use strict";const getCurrentScript=()=>{if(typeof document=="undefined")return console.error("document is not defined"),null;const{currentScript:e}=document;if(e instanceof HTMLScriptElement)return e;const t=document.getElementsByTagName("script");return t.length?t[t.length-1]:null},getEnvironment=e=>{if(e==="production"||e==="development"||e==="staging")return e},scriptEl=getCurrentScript(),DEFAULT_WIDGET_ASSET_BASE=(()=>{var e;return!((e=scriptEl==null?void 0:scriptEl.src)===null||e===void 0)&&e.includes("@dev"),"https://cdn.jsdelivr.net/npm/@eka-care/medassist-widget@0.1.85/dist/"})();function mapAgentConfigThemeToWidgetTheme(e){if(!e)return;const t=e.mode==="dark"?"white":e.mode==="light"?"black":void 0;return{...e.background_img&&{backgroundImage:e.background_img},...e.accent&&{primary:e.accent},...t&&{textColor:t},...e.mode&&{mode:e.mode},...e.header_tinted!==void 0&&{headerTinted:e.header_tinted},...e.title_img&&{titleImg:e.title_img},...e.tagline&&{tagline:e.tagline}}}function preloadImage(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 fetchAgentConfig(e,t){const n=`${e.replace(/\/$/,"")}/med-assist/agent-config/${t}`,i=await fetch(n,{headers:{"ngrok-skip-browser-warning":"69420"}});if(!i.ok)return;const o=await i.json();if(o!=null&&o.success&&(o!=null&&o.data))return o.data}const NUDGE_STORAGE_KEY="eka-medassist-nudges";function getNudgeStore(){try{const e=localStorage.getItem(NUDGE_STORAGE_KEY);return e?JSON.parse(e):{}}catch{return{}}}function setNudgeStore(e){try{localStorage.setItem(NUDGE_STORAGE_KEY,JSON.stringify(e))}catch{}}function normalizePath(e){let t=e.replace(/\/+$/,"");return t.startsWith("/")||(t="/"+t),t||"/"}function findCachedNudge(e,t){const i=getNudgeStore()[e];if(!i)return null;let o;try{o=new URL(t)}catch{return null}const s=o.host,a=i[s];if(!a)return null;const d=o.pathname.split("/").filter(Boolean),u=[];for(let c=d.length;c>=0;c--)u.push(c===0?"/":"/"+d.slice(0,c).join("/"));for(const c of u){if(a[c]!==void 0)return{domain:s,path:c,data:a[c]};const l=c==="/"?"/*":c+"/*";if(a[l]!==void 0)return{domain:s,path:l,data:a[l]}}return null}function clearNudgeForPath(e,t,n){const i=getNudgeStore(),o=i[e];!o||!o[t]||(delete o[t][n],setNudgeStore(i))}function storeNudgeResponse(e,t){var n,i,o,s;const a=(n=t==null?void 0:t.url_pattern)===null||n===void 0?void 0:n.domain,d=(i=t==null?void 0:t.url_pattern)===null||i===void 0?void 0:i.path;if(!(!((o=t.nudges)===null||o===void 0)&&o.length)||!t.expiry||!a||!d)return;const u=getNudgeStore();u[e]||(u[e]={}),u[e][a]||(u[e][a]={}),u[e][a][d]={nudges:t.nudges,expiry:t.expiry,delay:(s=t.delay)!==null&&s!==void 0?s:5},setNudgeStore(u)}const NUDGE_COOKIE_PREFIX="eka-nudge";function setNudgeCookie(e,t){const n=new Date(Date.now()+864e5).toUTCString();document.cookie=`${NUDGE_COOKIE_PREFIX}-${e}=${t}; expires=${n}; path=/; SameSite=Lax`}function getNudgeCookie(e){const t=document.cookie.split(";").map(i=>i.trim()).find(i=>i.startsWith(`${NUDGE_COOKIE_PREFIX}-${e}=`));if(!t)return null;const n=t.split("=")[1];return n==="open"||n==="closed"?n:null}async function fetchNudgeData(e,t){const n=`${t}/med-assist/user-nudge`,i=[];typeof document!="undefined"&&document.querySelectorAll("meta").forEach(o=>{var s,a,d;const u=(s=o.getAttribute("name"))!==null&&s!==void 0?s:void 0,c=(a=o.getAttribute("property"))!==null&&a!==void 0?a:void 0,l=(d=o.getAttribute("content"))!==null&&d!==void 0?d:void 0;(u||c)&&i.push({name:u,property:c,content:l})});try{const o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json","x-agent-id":e,referer:typeof window!="undefined"?window.location.href:""},body:JSON.stringify({meta_tags:i,url:typeof window!="undefined"?window.location.href:""})});return o.ok?await o.json():void 0}catch{return}}const globalMedAssistConfig={},getWidgetElement=()=>typeof document=="undefined"?null:document.querySelector("eka-medassist-widget");if(typeof window!="undefined"){const e=window;e.__ekaMedAssistConfig__=globalMedAssistConfig,e.EkaMedAssist={init(t){var n,i,o;Object.assign(globalMedAssistConfig,t);const s=getWidgetElement();if(s){if(t.agentId&&s.setAttribute("agent-id",t.agentId),t.authToken&&s.setAttribute("auth-token",t.authToken),t.title&&s.setAttribute("title",t.title),t.iconUrl&&s.setAttribute("icon-url",t.iconUrl),t.baseUrl&&s.setAttribute("base-url",t.baseUrl),t.resize!==void 0&&s.setAttribute("resize",String(t.resize)),(t.displayMode==="full"||t.displayMode==="widget")&&s.setAttribute("display-mode",t.displayMode),t.context)try{s.setAttribute("context",JSON.stringify(t.context))}catch{console.warn("Failed to stringify context passed to init")}typeof t.customLauncherStyles=="string"&&s.setAttribute("custom-launcher-styles",t.customLauncherStyles),t.redirectUrl&&s.setAttribute("redirect-url",t.redirectUrl),!((n=t.theme)===null||n===void 0)&&n.backgroundImage&&preloadImage(t.theme.backgroundImage),(o=(i=s).openFromBridge)===null||o===void 0||o.call(i)}}}}const scriptBaseUrl=(()=>{if(!scriptEl)return"";try{return new URL(".",scriptEl.src||window.location.href).href}catch{return""}})(),widgetAssetBaseUrl=(()=>{if(!scriptEl)return DEFAULT_WIDGET_ASSET_BASE;const e=scriptEl.dataset.widgetAssets;if(e==="local")return`${scriptBaseUrl}src/`;if(e&&e.length>0)try{return new URL(e,scriptBaseUrl).href}catch{return e.endsWith("/")?e:`${e}/`}return DEFAULT_WIDGET_ASSET_BASE})(),WIDGET_JS_URL=`${widgetAssetBaseUrl}medassist-widget.js`,WIDGET_CSS_URL=`${widgetAssetBaseUrl}medassist-widget.css`;let widgetModulePromise=null,widgetCssTextPromise=null;function getWidgetCssTextPromise(){return widgetCssTextPromise||(widgetCssTextPromise=fetch(WIDGET_CSS_URL).then(e=>{if(!e.ok)throw new Error(`Unable to fetch widget styles from ${WIDGET_CSS_URL}`);return e.text()})),widgetCssTextPromise}class MedAssistWidgetLoader extends HTMLElement{getAgentConfig(){if(!this.agentConfigPromise){const t=(typeof window!="undefined"?window.__ekaMedAssistConfig__:void 0)||{},n=t.baseUrl||this.getAttribute("base-url")||"https://matrix.eka.care/reloaded",i=t.agentId||this.getAttribute("agent-id")||"";if(!i)return Promise.resolve(void 0);this.agentConfigPromise=fetchAgentConfig(n,i).catch(()=>{})}return this.agentConfigPromise}constructor(){super(),this.reactRoot=null,this.agentConfigPromise=null,this.attachShadow({mode:"open"}),this.defaultIconUrl="https://cdn.eka.care/bot-icon.svg",this.widgetLoaded=!1,this.displayMode=this.getAttribute("display-mode")==="full"?"full":"widget",this.setupAuthExpirationListener()}static get observedAttributes(){return["icon-url","display-mode","custom-launcher-styles","redirect-url"]}connectedCallback(){this.displayMode==="full"?(this.initializeFullMode(),this.loadAndRender().catch(t=>{console.error("Failed to load MedAssist widget in full mode",t)})):(this.renderButton(),this.scheduleIdle(()=>{this.preloadWidgetAssets(),this.initNudge()}))}scheduleIdle(t){if(typeof window=="undefined"){t();return}const n=window.requestIdleCallback;typeof n=="function"?n(t,{timeout:3e3}):setTimeout(t,200)}attributeChangedCallback(t){if(t==="icon-url"&&this.displayMode==="widget"&&this.renderButton(),t==="display-mode"){const n=this.getAttribute("display-mode")==="full"?"full":"widget";n!==this.displayMode&&(this.displayMode=n,n==="full"?this.initializeFullMode():this.renderButton())}t==="custom-launcher-styles"&&this.applyCustomLauncherStyles()}preloadWidgetAssets(){getWidgetCssTextPromise(),this.loadWidgetModule(),this.preloadBackgroundImage()}preloadBackgroundImage(){var t;const n=typeof window!="undefined"?window.__ekaMedAssistConfig__:void 0,i=this.getAttribute("theme")?(()=>{try{return JSON.parse(this.getAttribute("theme")||"{}")}catch{return}})():void 0,o=(t=n==null?void 0:n.theme)===null||t===void 0?void 0:t.backgroundImage,s=i==null?void 0:i.backgroundImage;o&&preloadImage(o),s&&s!==o&&preloadImage(s),this.getAgentConfig().then(a=>{var d;const u=(d=a==null?void 0:a.theme)===null||d===void 0?void 0:d.background_img;u&&preloadImage(u)}).catch(()=>{})}setupAuthExpirationListener(){if(typeof window=="undefined")return;const t=n=>{var i;((i=n.data)===null||i===void 0?void 0:i.type)==="AUTH_EXPIRED"&&window.parent!==window&&window.parent.postMessage({type:"AUTH_EXPIRED",message:"Authentication expired"},"*")};window.addEventListener("message",t)}openFromBridge(){this.displayMode=this.getAttribute("display-mode")==="full"?"full":"widget",this.displayMode==="full"?this.initializeFullMode():this.renderButton(),this.loadAndRender().catch(t=>{console.error("Failed to open MedAssist widget from bridge",t)})}async initNudge(){var t,n,i,o;const s=typeof window!="undefined"?window.__ekaMedAssistConfig__:void 0,a=(s==null?void 0:s.agentId)||this.getAttribute("agent-id")||"";if(!a)return;const d=await this.getAgentConfig();if(!(d!=null&&d.nudge))return;const u=(n=(t=d==null?void 0:d.theme)===null||t===void 0?void 0:t.nudge_color)!==null&&n!==void 0?n:"#ffffff",c=typeof window!="undefined"?window.location.href:"";let l=findCachedNudge(a,c);if(l){const f=Math.floor(Date.now()/1e3);l.data.expiry<=f&&(clearNudgeForPath(a,l.domain,l.path),l=null)}if(!l){const f=typeof window!="undefined"?window.__ekaMedAssistConfig__:void 0,m=(f==null?void 0:f.baseUrl)||this.getAttribute("base-url")||"https://matrix.eka.care/reloaded",w=await fetchNudgeData(a,m).catch(()=>{});if(!(!((i=w==null?void 0:w.nudges)===null||i===void 0)&&i.length)||(storeNudgeResponse(a,w),l=findCachedNudge(a,c),!l))return}const h=l.data.nudges[Math.floor(Math.random()*l.data.nudges.length)],p=(o=l.data.delay)!==null&&o!==void 0?o:5;setTimeout(()=>{this.showNudgePopup(h,u)},p*1e3)}showNudgePopup(t,n){var i,o;const s=this.shadowRoot;if(!s||!(!((i=s.getElementById("medassist-widget-root"))===null||i===void 0)&&i.classList.contains("hidden")))return;const d=((typeof window!="undefined"?window.__ekaMedAssistConfig__:void 0)||{}).agentId||this.getAttribute("agent-id")||"";if(d&&getNudgeCookie(d)!==null||s.getElementById("medassist-nudge-popup"))return;const c=s.getElementById("medassist-open-btn"),l=c==null?void 0:c.getBoundingClientRect(),h=272,p=12,f=8,m=16,w=16;let y=window.innerWidth-h-p,v=76,x=h-m-f*2;if(l&&l.width>0){const g=l.left+l.width/2,A=g-h/2,_=window.innerWidth-h-p;y=Math.max(p,Math.min(A,_)),v=window.innerHeight-l.top+w,x=Math.max(m,Math.min(g-y-f,h-m-f*2))}const b=document.createElement("div");b.id="medassist-nudge-popup",b.innerHTML=`
|
|
2
2
|
<style>
|
|
3
3
|
@keyframes nudge-slide-up {
|
|
4
4
|
from { opacity: 0; transform: translateY(12px) scale(0.97); }
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
bottom: ${v}px;
|
|
10
10
|
left: ${y}px;
|
|
11
11
|
width: ${h}px;
|
|
12
|
-
background: ${
|
|
12
|
+
background: ${n};
|
|
13
13
|
border-radius: 16px;
|
|
14
14
|
box-shadow: 0 8px 32px rgba(0,0,0,0.14), 0 2px 8px rgba(0,0,0,0.08);
|
|
15
15
|
padding: 16px 16px 14px 16px;
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
left: ${x}px;
|
|
30
30
|
width: 16px;
|
|
31
31
|
height: 10px;
|
|
32
|
-
background: ${
|
|
32
|
+
background: ${n};
|
|
33
33
|
clip-path: polygon(0 0, 100% 0, 50% 100%);
|
|
34
34
|
}
|
|
35
35
|
#medassist-nudge-popup {
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
<p class="nudge-text">${t.replace(/</g,"<").replace(/>/g,">")}</p>
|
|
80
80
|
<button class="nudge-close" aria-label="Dismiss">✕</button>
|
|
81
81
|
</div>
|
|
82
|
-
`,(
|
|
82
|
+
`,(o=b.querySelector(".nudge-close"))===null||o===void 0||o.addEventListener("click",g=>{g.stopPropagation(),d&&setNudgeCookie(d,"closed"),this.dismissNudgePopup()}),b.addEventListener("click",()=>{d&&setNudgeCookie(d,"closed"),this.dismissNudgePopup(),this.loadAndRender()}),s.appendChild(b)}dismissNudgePopup(){var t;const n=(t=this.shadowRoot)===null||t===void 0?void 0:t.getElementById("medassist-nudge-popup");n==null||n.remove()}applyCustomLauncherStyles(){var t;const n=this.shadowRoot;if(!n||this.displayMode!=="widget")return;const i=n.querySelector('style[data-medassist-custom-launcher="true"]'),o=(t=this.getAttribute("custom-launcher-styles"))!==null&&t!==void 0?t:"";if(!o){i==null||i.remove();return}if(i){i.textContent=o;return}const s=document.createElement("style");s.setAttribute("data-medassist-custom-launcher","true"),s.textContent=o,n.appendChild(s)}renderButton(){var t;const n=this.getAttribute("icon-url")||this.defaultIconUrl,i=this.shadowRoot;if(!i){console.error("Shadow root was not created");return}if(!i.querySelector("button"))i.innerHTML=`
|
|
83
83
|
<style>
|
|
84
84
|
#medassist-open-btn {
|
|
85
85
|
width: 60px;
|
|
@@ -118,10 +118,10 @@
|
|
|
118
118
|
</style>
|
|
119
119
|
|
|
120
120
|
<button id="medassist-open-btn">
|
|
121
|
-
<img src="${
|
|
121
|
+
<img src="${n}" alt="MedAssist Icon">
|
|
122
122
|
</button>
|
|
123
123
|
<div id="medassist-widget-root" class="hidden"></div>
|
|
124
|
-
`,(t=i.getElementById("medassist-open-btn"))===null||t===void 0||t.addEventListener("click",()=>{const s=((typeof window!="undefined"?window.__ekaMedAssistConfig__:void 0)||{}).agentId||this.getAttribute("agent-id")||"";s&&setNudgeCookie(s,"closed"),this.dismissNudgePopup(),this.loadAndRender()});else{const
|
|
124
|
+
`,(t=i.getElementById("medassist-open-btn"))===null||t===void 0||t.addEventListener("click",()=>{const s=((typeof window!="undefined"?window.__ekaMedAssistConfig__:void 0)||{}).agentId||this.getAttribute("agent-id")||"";s&&setNudgeCookie(s,"closed"),this.dismissNudgePopup(),this.loadAndRender()});else{const o=i.querySelector("#medassist-open-btn img");o&&(o.src=n)}this.applyCustomLauncherStyles()}initializeFullMode(){const t=this.shadowRoot;if(!t){console.error("Shadow root is not available");return}t.getElementById("medassist-widget-root")||(t.innerHTML=`
|
|
125
125
|
<style>
|
|
126
126
|
:host {
|
|
127
127
|
display: block;
|
|
@@ -138,4 +138,4 @@
|
|
|
138
138
|
}
|
|
139
139
|
</style>
|
|
140
140
|
<div id="medassist-widget-root"></div>
|
|
141
|
-
`)}async loadAndRender(){var t,
|
|
141
|
+
`)}async loadAndRender(){var t,n,i,o,s;const a=this.shadowRoot;if(!a){console.error("Shadow root is not available");return}this.style.display="";const d=a.getElementById("medassist-open-btn"),u=a.getElementById("medassist-widget-root"),c=this.getAttribute("agent-id");let l=this.getAttribute("icon-url")||this.defaultIconUrl;const h=(t=getEnvironment(this.getAttribute("environment")))!==null&&t!==void 0?t:"production",p=this.getAttribute("connectivity"),f=p==="sse"||p==="socket"?p:void 0;let m=this.getAttribute("title")||"Medi Clinic";const w=this.getAttribute("base-url")||"https://matrix.eka.care/reloaded",v=this.getAttribute("display-mode")==="full"?"full":"widget",x=this.getAttribute("context")?JSON.parse(this.getAttribute("context")||"{}"):void 0,b=this.getAttribute("theme")?(()=>{try{return JSON.parse(this.getAttribute("theme")||"{}")}catch{return}})():void 0,g=(typeof window!="undefined"?window.__ekaMedAssistConfig__:void 0)||{},A={...x||{},...g.context||{}},_=g.auth||void 0,B=g.authToken||this.getAttribute("auth-token")||void 0,k=g.agentId||c,P=g.baseUrl||w,C=typeof window!="undefined"?(n=window.EkaMedAssist)===null||n===void 0?void 0:n.onClose:void 0,T=this.getAttribute("redirect-url")||void 0,M=g.redirectUrl||T,$=!!M||g.showCloseButton===!0;if(!k){console.error("Agent ID is required");return}if(!u){console.error("Widget root element is missing");return}d&&d.classList.add("hidden"),u.classList.remove("hidden");let E,S,I,U=!1,L,R=!1;try{const r=await this.getAgentConfig();m=(r==null?void 0:r.name)||m,l=((i=r==null?void 0:r.theme)===null||i===void 0?void 0:i.icon_img)||l,E=mapAgentConfigThemeToWidgetTheme((r==null?void 0:r.theme)||void 0),S=r==null?void 0:r.allowed,I=r==null?void 0:r.connectivity,U=(r==null?void 0:r.resize)||(g==null?void 0:g.resize)||!1,L=r==null?void 0:r.initial_message,R=(s=(o=r==null?void 0:r.theme)===null||o===void 0?void 0:o.hide_watermark)!==null&&s!==void 0?s:!1}catch{}const W=I||f||"socket",N={title:g.title||m,iconUrl:l||g.iconUrl,showCloseButton:$,allowed:S,environment:h,connectionType:W,onClose:()=>{var r;if((r=this.reactRoot)===null||r===void 0||r.unmount(),this.reactRoot=null,C&&typeof C=="function"&&C(),M){window.location.href=M;return}v==="full"?this.style.display="none":(d&&d.classList.remove("hidden"),u.classList.add("hidden"))},baseUrl:P,context:A,displayMode:v,resize:U||this.getAttribute("resize")==="true",auth:_,authToken:B,initialMessage:L,hideWatermark:R,theme:{...E||{},...b||{},...g.theme||{}}},z=window;if(this.widgetLoaded){this.reactRoot=z.renderMedAssist(u,k,N);return}try{const[,r]=await Promise.all([this.loadWidgetCss(),this.loadWidgetModule()]);this.reactRoot=r.renderMedAssist(u,k,N),this.widgetLoaded=!0}catch(r){console.error("Failed to load MedAssist widget",r),d&&d.classList.remove("hidden"),u.classList.add("hidden")}}async loadWidgetCss(){const t=this.shadowRoot;if(!t)throw new Error("Shadow root is not available");if(t.querySelector("[data-medassist-style='true']"))return;const n=await getWidgetCssTextPromise(),i=document.createElement("style");i.setAttribute("data-medassist-style","true"),i.textContent=n,t.appendChild(i)}loadWidgetModule(){return widgetModulePromise||(widgetModulePromise=import(WIDGET_JS_URL)),widgetModulePromise}}customElements.define("eka-medassist-widget",MedAssistWidgetLoader);
|