@eka-care/medassist-widget-embed 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/iframe.js CHANGED
@@ -20,6 +20,52 @@
20
20
  }
21
21
  return undefined;
22
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
+ /** Fetch agent-config from API with timeout; aborts if pending > 10s */
44
+ async function fetchAgentConfig(baseUrl, agentId) {
45
+ const url = `${baseUrl.replace(/\/$/, "")}/med-assist/agent-config/${agentId}`;
46
+ const controller = new AbortController();
47
+ const timeoutId = setTimeout(() => controller.abort(), API_FETCH_TIMEOUT_MS);
48
+ try {
49
+ const res = await fetch(url, {
50
+ signal: controller.signal,
51
+ headers: {
52
+ "ngrok-skip-browser-warning": "69420",
53
+ },
54
+ });
55
+ if (!res.ok)
56
+ return undefined;
57
+ const json = await res.json();
58
+ if ((json === null || json === void 0 ? void 0 : json.success) && (json === null || json === void 0 ? void 0 : json.data))
59
+ return json.data;
60
+ return undefined;
61
+ }
62
+ catch {
63
+ return undefined;
64
+ }
65
+ finally {
66
+ clearTimeout(timeoutId);
67
+ }
68
+ }
23
69
  const DEFAULT_WIDGET_ASSET_BASE = "https://unpkg.com/@eka-care/medassist-widget@latest/dist/";
24
70
  const scriptEl = getCurrentScript();
25
71
  const scriptBaseUrl = (() => {
@@ -57,40 +103,68 @@
57
103
  let widgetCssTextPromise = null;
58
104
  // Auto-initialize from URL parameters (no shadow DOM needed in iframe)
59
105
  const initializeFromUrlParams = async () => {
60
- var _a;
106
+ var _a, _b, _c, _d, _e;
61
107
  const urlParams = new URLSearchParams(window.location.search);
62
108
  const agentId = urlParams.get("agentId");
63
109
  if (!agentId) {
64
110
  console.error("Agent ID is required in URL parameters");
65
111
  return;
66
112
  }
67
- const title = urlParams.get("title") || "Medi Clinic";
68
- const iconUrl = urlParams.get("iconUrl") || undefined;
113
+ let title = urlParams.get("title") || "Medi Clinic";
114
+ let iconUrl = urlParams.get("iconUrl") || undefined;
69
115
  const context = urlParams.get("context");
70
- const baseUrl = urlParams.get("baseUrl") || undefined;
116
+ const baseUrl = urlParams.get("baseUrl") || "https://matrix.eka.care/reloaded";
71
117
  const environment = (_a = getEnvironment(urlParams.get("environment"))) !== null && _a !== void 0 ? _a : "production";
118
+ const attributeTheme = urlParams.get("theme")
119
+ ? (() => {
120
+ try {
121
+ return JSON.parse(urlParams.get("theme") || "{}");
122
+ }
123
+ catch {
124
+ return undefined;
125
+ }
126
+ })()
127
+ : undefined;
72
128
  const container = document.getElementById("root") || document.body;
73
129
  try {
74
- await Promise.all([
75
- loadWidgetCss(),
76
- loadWidgetScript(),
77
- ]);
78
- if (!(window === null || window === void 0 ? void 0 : window.renderMedAssist) || typeof (window === null || window === void 0 ? void 0 : window.renderMedAssist) !== "function") {
130
+ await Promise.all([loadWidgetCss(), loadWidgetScript()]);
131
+ if (!(window === null || window === void 0 ? void 0 : window.renderMedAssist) ||
132
+ typeof (window === null || window === void 0 ? void 0 : window.renderMedAssist) !== "function") {
79
133
  throw new Error("renderMedAssist is not available on window");
80
134
  }
135
+ // Fetch agent-config when baseUrl is available; 10s timeout aborts pending request
136
+ let apiTheme;
137
+ let allowed;
138
+ console.log("base url", baseUrl);
139
+ if (baseUrl) {
140
+ try {
141
+ const agentConfig = await fetchAgentConfig(baseUrl, agentId);
142
+ title = (_b = agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.name) !== null && _b !== void 0 ? _b : title;
143
+ 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;
144
+ apiTheme = mapAgentConfigThemeToWidgetTheme((_e = agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.theme) !== null && _e !== void 0 ? _e : undefined);
145
+ allowed = agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.allowed;
146
+ }
147
+ catch {
148
+ // ignore; use URL params only
149
+ }
150
+ }
81
151
  const config = {
82
152
  title,
83
153
  iconUrl,
154
+ allowed,
84
155
  environment,
85
156
  onClose: () => {
86
- // Send message to parent window to close iframe
87
157
  if (window.parent !== window) {
88
158
  window.parent.postMessage({ type: "WIDGET_CLOSE" }, "*");
89
159
  }
90
160
  },
91
161
  context: context ? JSON.parse(context) : undefined,
92
162
  baseUrl,
93
- displayMode: "full", //for iframe default display mode is full
163
+ displayMode: "full",
164
+ theme: {
165
+ ...(apiTheme !== null && apiTheme !== void 0 ? apiTheme : {}),
166
+ ...(attributeTheme !== null && attributeTheme !== void 0 ? attributeTheme : {}),
167
+ },
94
168
  };
95
169
  window.renderMedAssist(container, agentId, config);
96
170
  }
package/dist/index.d.ts CHANGED
@@ -3,6 +3,19 @@ type WidgetEnvironment = "production" | "development" | "staging";
3
3
  declare const getEnvironment: (value: string | null) => WidgetEnvironment | undefined;
4
4
  declare const scriptEl: HTMLScriptElement | null;
5
5
  declare const DEFAULT_WIDGET_ASSET_BASE: string;
6
+ /** Theme from agent-config API (has mode; textColor derived: dark → black, light → white) */
7
+ type AgentConfig = {
8
+ name?: string;
9
+ allowed?: ("text" | "file" | "audio")[];
10
+ theme?: {
11
+ background?: string;
12
+ background_img?: string;
13
+ accent?: string;
14
+ mode?: "light" | "dark";
15
+ title_img?: string;
16
+ icon_img?: string;
17
+ };
18
+ };
6
19
  type MedAssistInitConfig = {
7
20
  auth?: string;
8
21
  agentId?: string;
@@ -10,8 +23,19 @@ type MedAssistInitConfig = {
10
23
  title?: string;
11
24
  iconUrl?: string;
12
25
  baseUrl?: string;
26
+ allowed?: ("text" | "file" | "audio")[];
27
+ theme?: {
28
+ background?: string;
29
+ backgroundImage?: string;
30
+ primary?: string;
31
+ textColor?: "black" | "white";
32
+ };
13
33
  [key: string]: unknown;
14
34
  };
35
+ /** Map agent-config API theme to widget theme (mode → textColor: dark→black, light→white) */
36
+ declare function mapAgentConfigThemeToWidgetTheme(apiTheme: AgentConfig["theme"] | undefined): MedAssistInitConfig["theme"];
37
+ /** Fetch agent-config from API and return theme from response data */
38
+ declare function fetchAgentConfig(baseUrl: string, agentId: string): Promise<AgentConfig | undefined>;
15
39
  interface EkaMedAssistWindow extends Window {
16
40
  EkaMedAssist?: {
17
41
  init: (config: MedAssistInitConfig) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,gBAAgB,QAAO,iBAAiB,GAAG,IAahD,CAAC;AAEF,KAAK,iBAAiB,GAAG,YAAY,GAAG,aAAa,GAAG,SAAS,CAAC;AAElE,QAAA,MAAM,cAAc,GAClB,OAAO,MAAM,GAAG,IAAI,KACnB,iBAAiB,GAAG,SAStB,CAAC;AAEF,QAAA,MAAM,QAAQ,0BAAqB,CAAC;AAGpC,QAAA,MAAM,yBAAyB,QAK3B,CAAC;AAEL,KAAK,mBAAmB,GAAG;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,UAAU,kBAAmB,SAAQ,MAAM;IACzC,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;QAC5C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;KACtB,CAAC;IACF,sBAAsB,CAAC,EAAE,mBAAmB,CAAC;CAC9C;AAED,QAAA,MAAM,qBAAqB,EAAE,mBAAwB,CAAC;AAEtD,QAAA,MAAM,gBAAgB,QAAO,WAAW,GAAG,IAK1C,CAAC;AA6BF,QAAA,MAAM,aAAa,QASf,CAAC;AAEL,QAAA,MAAM,kBAAkB,QAmBpB,CAAC;AAEL,QAAA,MAAM,aAAa,QAA6C,CAAC;AACjE,QAAA,MAAM,cAAc,QAA8C,CAAC;AAEnE,QAAA,IAAI,mBAAmB,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAW,CAAC;AACrD,QAAA,IAAI,oBAAoB,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAW,CAAC;AAExD,cAAM,qBAAsB,SAAQ,WAAW;IAC7C,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,WAAW,CAAoB;;IAavC,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAExC;IAED,iBAAiB,IAAI,IAAI;IAQzB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAmB5C,OAAO,CAAC,2BAA2B;IAe5B,cAAc,IAAI,IAAI;IAgB7B,YAAY,IAAI,IAAI;IAiEpB,kBAAkB,IAAI,IAAI;IA6BpB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IA0F9B,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BpC,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;CA0ClC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -28,6 +28,34 @@ const DEFAULT_WIDGET_ASSET_BASE = (() => {
28
28
  }
29
29
  return "https://unpkg.com/@eka-care/medassist-widget@latest/dist/";
30
30
  })();
31
+ /** Map agent-config API theme to widget theme (mode → textColor: dark→black, light→white) */
32
+ function mapAgentConfigThemeToWidgetTheme(apiTheme) {
33
+ if (!apiTheme)
34
+ return undefined;
35
+ const textColor = apiTheme.mode === "dark" ? "white" : apiTheme.mode === "light" ? "black" : undefined;
36
+ return {
37
+ ...(apiTheme.background && { background: apiTheme.background }),
38
+ ...(apiTheme.background_img && { backgroundImage: apiTheme.background_img }),
39
+ ...(apiTheme.accent && { primary: apiTheme.accent }),
40
+ ...(textColor && { textColor }),
41
+ ...(apiTheme.title_img && { titleImg: apiTheme.title_img }),
42
+ };
43
+ }
44
+ /** Fetch agent-config from API and return theme from response data */
45
+ async function fetchAgentConfig(baseUrl, agentId) {
46
+ const url = `${baseUrl.replace(/\/$/, "")}/med-assist/agent-config/${agentId}`;
47
+ const res = await fetch(url, {
48
+ headers: {
49
+ "ngrok-skip-browser-warning": "69420",
50
+ },
51
+ });
52
+ if (!res.ok)
53
+ return undefined;
54
+ const json = await res.json();
55
+ if ((json === null || json === void 0 ? void 0 : json.success) && (json === null || json === void 0 ? void 0 : json.data))
56
+ return json.data;
57
+ return undefined;
58
+ }
31
59
  const globalMedAssistConfig = {};
32
60
  const getWidgetElement = () => {
33
61
  if (typeof document === "undefined") {
@@ -255,7 +283,7 @@ class MedAssistWidgetLoader extends HTMLElement {
255
283
  }
256
284
  }
257
285
  async loadAndRender() {
258
- var _a, _b, _c;
286
+ var _a, _b, _c, _d;
259
287
  const shadowRoot = this.shadowRoot;
260
288
  if (!shadowRoot) {
261
289
  console.error("Shadow root is not available");
@@ -264,13 +292,19 @@ class MedAssistWidgetLoader extends HTMLElement {
264
292
  const button = shadowRoot.getElementById("medassist-open-btn");
265
293
  const rootElement = shadowRoot.getElementById("medassist-widget-root");
266
294
  const agentId = this.getAttribute("agent-id");
267
- const iconUrl = this.getAttribute("icon-url") || this.defaultIconUrl;
295
+ let iconUrl = this.getAttribute("icon-url") || this.defaultIconUrl;
268
296
  const environment = (_a = getEnvironment(this.getAttribute("environment"))) !== null && _a !== void 0 ? _a : "production";
269
- const title = this.getAttribute("title") || "Medi Clinic";
270
- const baseUrl = this.getAttribute("base-url") || undefined;
297
+ let title = this.getAttribute("title") || "Medi Clinic";
298
+ const baseUrl = this.getAttribute("base-url") || "https://matrix.eka.care/reloaded";
271
299
  const displayModeAttribute = this.getAttribute("display-mode");
272
300
  const displayMode = displayModeAttribute === "full" ? "full" : "widget";
273
301
  const attributeContext = this.getAttribute("context") ? JSON.parse(this.getAttribute("context") || "{}") : undefined;
302
+ const attributeTheme = this.getAttribute("theme") ? (() => { try {
303
+ return JSON.parse(this.getAttribute("theme") || "{}");
304
+ }
305
+ catch {
306
+ return undefined;
307
+ } })() : undefined;
274
308
  const initConfig = (typeof window !== "undefined"
275
309
  ? window.__ekaMedAssistConfig__
276
310
  : undefined) || {};
@@ -280,6 +314,7 @@ class MedAssistWidgetLoader extends HTMLElement {
280
314
  };
281
315
  const auth = initConfig.auth || undefined;
282
316
  const resolvedAgentId = initConfig.agentId || agentId;
317
+ const apiBaseUrl = initConfig.baseUrl || baseUrl;
283
318
  const customOnClose = typeof window !== "undefined" ? (_b = window.EkaMedAssist) === null || _b === void 0 ? void 0 : _b.onClose : undefined;
284
319
  if (!resolvedAgentId) {
285
320
  console.error("Agent ID is required");
@@ -293,9 +328,25 @@ class MedAssistWidgetLoader extends HTMLElement {
293
328
  button.classList.add("hidden");
294
329
  }
295
330
  rootElement.classList.remove("hidden");
331
+ // Fetch agent-config when baseUrl is available; derive theme (mode → textColor: dark→black, light→white)
332
+ let apiTheme = undefined;
333
+ let allowed;
334
+ if (apiBaseUrl) {
335
+ try {
336
+ const agentConfig = await fetchAgentConfig(apiBaseUrl, resolvedAgentId);
337
+ title = (agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.name) || title;
338
+ iconUrl = ((_c = agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.theme) === null || _c === void 0 ? void 0 : _c.icon_img) || iconUrl;
339
+ apiTheme = mapAgentConfigThemeToWidgetTheme((agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.theme) || undefined);
340
+ allowed = agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.allowed;
341
+ }
342
+ catch {
343
+ // ignore; use attribute + init theme only
344
+ }
345
+ }
296
346
  const widgetConfig = {
297
347
  title: initConfig.title || title,
298
348
  iconUrl: initConfig.iconUrl || iconUrl,
349
+ allowed: initConfig.allowed || allowed,
299
350
  environment,
300
351
  onClose: () => {
301
352
  if (customOnClose && typeof customOnClose === "function") {
@@ -306,13 +357,14 @@ class MedAssistWidgetLoader extends HTMLElement {
306
357
  }
307
358
  rootElement.classList.add("hidden");
308
359
  },
309
- baseUrl: initConfig.baseUrl || baseUrl,
360
+ baseUrl: apiBaseUrl,
310
361
  context: mergedContext,
311
362
  displayMode,
312
- auth
363
+ auth,
364
+ theme: { ...(apiTheme || {}), ...(attributeTheme || {}), ...(initConfig.theme || {}) }
313
365
  };
314
366
  if (this.widgetLoaded) {
315
- (_c = window.renderMedAssist) === null || _c === void 0 ? void 0 : _c.call(window, rootElement, resolvedAgentId, widgetConfig);
367
+ (_d = window.renderMedAssist) === null || _d === void 0 ? void 0 : _d.call(window, rootElement, resolvedAgentId, widgetConfig);
316
368
  return;
317
369
  }
318
370
  try {