cap-copilot-widget 0.1.0
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/btp-copilot.esm.js +665 -0
- package/dist/btp-copilot.esm.js.map +1 -0
- package/dist/btp-copilot.js +153 -0
- package/dist/btp-copilot.js.map +1 -0
- package/package.json +29 -0
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
const f = class f {
|
|
2
|
+
static resolve(t) {
|
|
3
|
+
if (t) return t.replace(/^Bearer\s+/i, "");
|
|
4
|
+
const e = window.__BTP_COPILOT_TOKEN__;
|
|
5
|
+
if (e) return e.replace(/^Bearer\s+/i, "");
|
|
6
|
+
const n = f._fromCookie();
|
|
7
|
+
if (n) return n;
|
|
8
|
+
try {
|
|
9
|
+
const i = localStorage.getItem("access_token");
|
|
10
|
+
if (i) return i;
|
|
11
|
+
} catch {
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
static getAuthHeader(t) {
|
|
16
|
+
return t ? { Authorization: `Bearer ${t}` } : {};
|
|
17
|
+
}
|
|
18
|
+
static _fromCookie() {
|
|
19
|
+
try {
|
|
20
|
+
const t = document.cookie.split(";");
|
|
21
|
+
for (const e of t) {
|
|
22
|
+
const [n, ...i] = e.trim().split("=");
|
|
23
|
+
if (f.XSUAA_COOKIE_NAMES.includes(n.trim()))
|
|
24
|
+
return decodeURIComponent(i.join("=").trim());
|
|
25
|
+
}
|
|
26
|
+
} catch {
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
f.XSUAA_COOKIE_NAMES = [
|
|
32
|
+
"x-uaa-token",
|
|
33
|
+
"xsuaa_token",
|
|
34
|
+
"access_token",
|
|
35
|
+
"X-Authorization"
|
|
36
|
+
];
|
|
37
|
+
let d = f;
|
|
38
|
+
class m {
|
|
39
|
+
static getHash() {
|
|
40
|
+
var t, e, n, i;
|
|
41
|
+
try {
|
|
42
|
+
const r = (n = (e = (t = sap == null ? void 0 : sap.ushell) == null ? void 0 : t.Container) == null ? void 0 : e.getService) == null ? void 0 : n.call(
|
|
43
|
+
e,
|
|
44
|
+
"CrossApplicationNavigation"
|
|
45
|
+
);
|
|
46
|
+
if (r) {
|
|
47
|
+
const s = (i = r.hrefForExternal) == null ? void 0 : i.call(r);
|
|
48
|
+
if (s) return s;
|
|
49
|
+
}
|
|
50
|
+
} catch (r) {
|
|
51
|
+
console.log(r);
|
|
52
|
+
}
|
|
53
|
+
return window.location.hash || "";
|
|
54
|
+
}
|
|
55
|
+
static getCurrentAppId() {
|
|
56
|
+
try {
|
|
57
|
+
const e = m.getHash().match(/^#([^&?/]+)/);
|
|
58
|
+
return e ? e[1] : null;
|
|
59
|
+
} catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
static getUserLocale() {
|
|
64
|
+
var t, e, n, i, r, s;
|
|
65
|
+
try {
|
|
66
|
+
return ((s = (r = (i = (n = (e = (t = sap == null ? void 0 : sap.ui) == null ? void 0 : t.getCore) == null ? void 0 : e.call(t)) == null ? void 0 : n.getConfiguration) == null ? void 0 : i.call(n)) == null ? void 0 : r.getLanguageTag) == null ? void 0 : s.call(r)) ?? navigator.language ?? "en";
|
|
67
|
+
} catch {
|
|
68
|
+
return navigator.language ?? "en";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
class u {
|
|
73
|
+
static getCurrentEntity() {
|
|
74
|
+
var t, e, n, i;
|
|
75
|
+
try {
|
|
76
|
+
const r = (e = (t = sap == null ? void 0 : sap.ui) == null ? void 0 : t.getCore) == null ? void 0 : e.call(t);
|
|
77
|
+
if (!r) return null;
|
|
78
|
+
let s = document.activeElement;
|
|
79
|
+
for (; s; ) {
|
|
80
|
+
const a = s.getAttribute("id") || s.getAttribute("data-sap-ui");
|
|
81
|
+
if (a) {
|
|
82
|
+
const o = r.byId(a), l = (n = o == null ? void 0 : o.getBindingContext) == null ? void 0 : n.call(o);
|
|
83
|
+
if (l) {
|
|
84
|
+
const p = (i = l.getObject) == null ? void 0 : i.call(l);
|
|
85
|
+
if (p && typeof p == "object")
|
|
86
|
+
return u._sanitize(p);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
s = s.parentElement;
|
|
90
|
+
}
|
|
91
|
+
return u._scanAllControls(r);
|
|
92
|
+
} catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
static _scanAllControls(t) {
|
|
97
|
+
var e, n;
|
|
98
|
+
try {
|
|
99
|
+
const i = t.mElements ?? {};
|
|
100
|
+
for (const r of Object.keys(i)) {
|
|
101
|
+
const s = i[r], a = (e = s == null ? void 0 : s.getBindingContext) == null ? void 0 : e.call(s);
|
|
102
|
+
if (a) {
|
|
103
|
+
const o = (n = a.getObject) == null ? void 0 : n.call(a);
|
|
104
|
+
if (o && typeof o == "object" && Object.keys(o).length > 0)
|
|
105
|
+
return u._sanitize(o);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
static getServiceUrl() {
|
|
113
|
+
var t, e;
|
|
114
|
+
try {
|
|
115
|
+
const n = (e = (t = sap == null ? void 0 : sap.ui) == null ? void 0 : t.getCore) == null ? void 0 : e.call(t);
|
|
116
|
+
if (!n) return null;
|
|
117
|
+
const i = n.mElements ?? {};
|
|
118
|
+
for (const r of Object.keys(i)) {
|
|
119
|
+
const s = i[r];
|
|
120
|
+
if (!(s != null && s.getModel)) continue;
|
|
121
|
+
const a = s.getModel();
|
|
122
|
+
if (!a) continue;
|
|
123
|
+
const o = a.sServiceUrl ?? a._sServiceUrl;
|
|
124
|
+
if (typeof o == "string" && o.length > 4)
|
|
125
|
+
return o.replace(/\/$/, "");
|
|
126
|
+
}
|
|
127
|
+
} catch {
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
static _sanitize(t) {
|
|
132
|
+
const e = {};
|
|
133
|
+
for (const [n, i] of Object.entries(t))
|
|
134
|
+
n.startsWith("__") || (i === null || typeof i != "object" ? e[n] = i : i.__deferred || (e[n] = i));
|
|
135
|
+
return e;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const c = class c {
|
|
139
|
+
static async fetchSchemaDocuments(t, e) {
|
|
140
|
+
const n = `btp-copilot-meta-${t}`;
|
|
141
|
+
if (c._cache.has(n))
|
|
142
|
+
return c._cache.get(n);
|
|
143
|
+
const i = sessionStorage.getItem(n);
|
|
144
|
+
if (i)
|
|
145
|
+
try {
|
|
146
|
+
const r = JSON.parse(i);
|
|
147
|
+
return c._cache.set(n, r), r;
|
|
148
|
+
} catch {
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const r = `${t}/$metadata`, s = { Accept: "application/xml" };
|
|
152
|
+
e && (s.Authorization = `Bearer ${e}`);
|
|
153
|
+
const a = await fetch(r, { headers: s });
|
|
154
|
+
if (!a.ok) return [];
|
|
155
|
+
const o = await a.text(), l = c._parseEDMX(o), p = c._schemasToDocuments(l, t);
|
|
156
|
+
return c._cache.set(n, p), sessionStorage.setItem(n, JSON.stringify(p)), p;
|
|
157
|
+
} catch {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
static _parseEDMX(t) {
|
|
162
|
+
try {
|
|
163
|
+
const i = new DOMParser().parseFromString(t, "text/xml").querySelectorAll("EntityType");
|
|
164
|
+
return Array.from(i).map((r) => {
|
|
165
|
+
const s = r.getAttribute("Name") ?? "", a = r.querySelectorAll("Key > PropertyRef"), o = new Set(
|
|
166
|
+
Array.from(a).map((h) => h.getAttribute("Name") ?? "")
|
|
167
|
+
), l = Array.from(
|
|
168
|
+
r.querySelectorAll("Property")
|
|
169
|
+
).map((h) => ({
|
|
170
|
+
name: h.getAttribute("Name") ?? "",
|
|
171
|
+
type: c._shortType(h.getAttribute("Type") ?? ""),
|
|
172
|
+
isKey: o.has(h.getAttribute("Name") ?? ""),
|
|
173
|
+
nullable: h.getAttribute("Nullable") !== "false"
|
|
174
|
+
})), p = Array.from(
|
|
175
|
+
r.querySelectorAll("NavigationProperty")
|
|
176
|
+
).map((h) => ({
|
|
177
|
+
name: h.getAttribute("Name") ?? "",
|
|
178
|
+
type: c._shortType(
|
|
179
|
+
h.getAttribute("Type") ?? h.getAttribute("ToRole") ?? ""
|
|
180
|
+
)
|
|
181
|
+
}));
|
|
182
|
+
return { name: s, properties: l, navProperties: p };
|
|
183
|
+
});
|
|
184
|
+
} catch {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
static _shortType(t) {
|
|
189
|
+
return t.startsWith("Collection(") ? `${t.slice(11, -1).split(".").pop()}[]` : t.split(".").pop() ?? t;
|
|
190
|
+
}
|
|
191
|
+
static _schemasToDocuments(t, e) {
|
|
192
|
+
const n = [];
|
|
193
|
+
for (const i of t) {
|
|
194
|
+
if (!i.name) continue;
|
|
195
|
+
const r = i.properties.filter((o) => o.isKey), s = i.properties.filter((o) => !o.isKey), a = [
|
|
196
|
+
`Entity: ${i.name}`,
|
|
197
|
+
`OData service: ${e}`,
|
|
198
|
+
`Entity set path: ${e}/${i.name}`,
|
|
199
|
+
`Count path: ${e}/${i.name}/$count`
|
|
200
|
+
];
|
|
201
|
+
r.length && a.push(
|
|
202
|
+
`Key fields: ${r.map((o) => `${o.name} (${o.type})`).join(", ")}`
|
|
203
|
+
), s.length && a.push(
|
|
204
|
+
`Fields: ${s.map(
|
|
205
|
+
(o) => `${o.name} (${o.type}${o.nullable ? "" : ", required"})`
|
|
206
|
+
).join(", ")}`
|
|
207
|
+
), i.navProperties.length && a.push(
|
|
208
|
+
`Navigation: ${i.navProperties.map((o) => `${o.name} → ${o.type}`).join(", ")}`
|
|
209
|
+
), n.push({
|
|
210
|
+
title: `${i.name} entity schema`,
|
|
211
|
+
content: a.join(`
|
|
212
|
+
`)
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return t.length > 0 && n.push({
|
|
216
|
+
title: "Available OData entity sets",
|
|
217
|
+
content: [
|
|
218
|
+
`OData service: ${e}`,
|
|
219
|
+
`Entities: ${t.map((i) => i.name).join(", ")}`,
|
|
220
|
+
"GET {entity}/$count | ?$filter=field eq 'value' | ?$top=10&$skip=0 | ?$orderby=field desc"
|
|
221
|
+
].join(`
|
|
222
|
+
`)
|
|
223
|
+
}), n;
|
|
224
|
+
}
|
|
225
|
+
static invalidate(t) {
|
|
226
|
+
const e = `btp-copilot-meta-${t}`;
|
|
227
|
+
c._cache.delete(e), sessionStorage.removeItem(e);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
c._cache = /* @__PURE__ */ new Map();
|
|
231
|
+
let b = c;
|
|
232
|
+
class g {
|
|
233
|
+
static capture(t) {
|
|
234
|
+
const e = { ...t };
|
|
235
|
+
try {
|
|
236
|
+
const n = m.getHash();
|
|
237
|
+
n && (e.current_view = n);
|
|
238
|
+
} catch {
|
|
239
|
+
}
|
|
240
|
+
try {
|
|
241
|
+
const n = u.getCurrentEntity();
|
|
242
|
+
n && Object.keys(n).length > 0 && (e.entity_data = n);
|
|
243
|
+
} catch {
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
e.user_locale || (e.user_locale = m.getUserLocale());
|
|
247
|
+
} catch {
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
const n = window.__APP_CONTEXT__;
|
|
251
|
+
n && (n.entity_data && (e.entity_data = { ...n.entity_data, ...e.entity_data }), n.current_view && !e.current_view && (e.current_view = n.current_view), n.extra && (e.extra = { ...n.extra, ...e.extra ?? {} }), n.service_url && !e.service_url && (e.service_url = n.service_url));
|
|
252
|
+
} catch {
|
|
253
|
+
}
|
|
254
|
+
return e;
|
|
255
|
+
}
|
|
256
|
+
static async captureAsync(t) {
|
|
257
|
+
var n;
|
|
258
|
+
const e = g.capture(t);
|
|
259
|
+
if (e.service_url || (e.service_url = g._discoverServiceUrl() ?? void 0), e.service_url)
|
|
260
|
+
try {
|
|
261
|
+
const i = ((n = e.extra) == null ? void 0 : n.auth_token) ?? null, r = await b.fetchSchemaDocuments(
|
|
262
|
+
e.service_url,
|
|
263
|
+
i
|
|
264
|
+
);
|
|
265
|
+
if (r.length > 0) {
|
|
266
|
+
const s = r.map((a) => `## ${a.title}
|
|
267
|
+
${a.content}`).join(`
|
|
268
|
+
|
|
269
|
+
`);
|
|
270
|
+
e.extra = { ...e.extra ?? {}, schema_hint: s };
|
|
271
|
+
}
|
|
272
|
+
} catch {
|
|
273
|
+
}
|
|
274
|
+
return e;
|
|
275
|
+
}
|
|
276
|
+
static _discoverServiceUrl() {
|
|
277
|
+
try {
|
|
278
|
+
const t = u.getServiceUrl();
|
|
279
|
+
if (t) return t;
|
|
280
|
+
} catch {
|
|
281
|
+
}
|
|
282
|
+
try {
|
|
283
|
+
const t = performance.getEntriesByType(
|
|
284
|
+
"resource"
|
|
285
|
+
);
|
|
286
|
+
for (const e of t) {
|
|
287
|
+
const n = e.name.match(/^(https?:\/\/[^?#]+)\/\$metadata/);
|
|
288
|
+
if (n) return n[1];
|
|
289
|
+
}
|
|
290
|
+
} catch {
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
const t = window.location.href.match(
|
|
294
|
+
/(https?:\/\/[^/]+(?:\/odata\/v[24]\/[^/?#]+|\/sap\/opu\/odata\/[^/?#]+))/
|
|
295
|
+
);
|
|
296
|
+
if (t) return t[1];
|
|
297
|
+
} catch {
|
|
298
|
+
}
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
static async discoverFromManifest() {
|
|
302
|
+
var t;
|
|
303
|
+
try {
|
|
304
|
+
const e = await fetch("/manifest.json");
|
|
305
|
+
if (!e.ok) return null;
|
|
306
|
+
const n = await e.json(), i = ((t = n == null ? void 0 : n["sap.app"]) == null ? void 0 : t.dataSources) ?? {};
|
|
307
|
+
for (const r of Object.keys(i)) {
|
|
308
|
+
const s = i[r];
|
|
309
|
+
if ((s == null ? void 0 : s.type) === "ODataAnnotation") continue;
|
|
310
|
+
const a = s == null ? void 0 : s.uri;
|
|
311
|
+
if (typeof a == "string" && a.length > 0)
|
|
312
|
+
return new URL(a, window.location.href).toString().replace(/\/$/, "");
|
|
313
|
+
}
|
|
314
|
+
} catch {
|
|
315
|
+
}
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
static listenForUpdates(t, e, n, i) {
|
|
319
|
+
const r = (s) => {
|
|
320
|
+
if (!s.data || typeof s.data != "object") return;
|
|
321
|
+
const { type: a, payload: o, text: l } = s.data;
|
|
322
|
+
switch (a) {
|
|
323
|
+
case "btp-copilot:set-context":
|
|
324
|
+
o && t(o);
|
|
325
|
+
break;
|
|
326
|
+
case "btp-copilot:send-message":
|
|
327
|
+
l && e(l);
|
|
328
|
+
break;
|
|
329
|
+
case "btp-copilot:open":
|
|
330
|
+
n();
|
|
331
|
+
break;
|
|
332
|
+
case "btp-copilot:close":
|
|
333
|
+
i();
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
return window.addEventListener("message", r), () => window.removeEventListener("message", r);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const v = `/* ── Host element ─────────────────────────────────────────────────────────── */
|
|
341
|
+
:host {
|
|
342
|
+
position: fixed;
|
|
343
|
+
z-index: 2147483647;
|
|
344
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
348
|
+
|
|
349
|
+
/* ── Toggle (FAB) button ─────────────────────────────────────────────────── */
|
|
350
|
+
.toggle-btn {
|
|
351
|
+
position: fixed;
|
|
352
|
+
bottom: 1.25rem;
|
|
353
|
+
width: 3.25rem;
|
|
354
|
+
height: 3.25rem;
|
|
355
|
+
border-radius: 50%;
|
|
356
|
+
border: none;
|
|
357
|
+
cursor: pointer;
|
|
358
|
+
display: flex;
|
|
359
|
+
align-items: center;
|
|
360
|
+
justify-content: center;
|
|
361
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
362
|
+
color: #fff;
|
|
363
|
+
box-shadow: 0 4px 14px rgba(102, 126, 234, 0.45);
|
|
364
|
+
z-index: 2147483647;
|
|
365
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
366
|
+
outline: none;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.toggle-btn.bottom-right { right: 1.25rem; }
|
|
370
|
+
.toggle-btn.bottom-left { left: 1.25rem; }
|
|
371
|
+
|
|
372
|
+
.toggle-btn:hover {
|
|
373
|
+
transform: scale(1.08);
|
|
374
|
+
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.55);
|
|
375
|
+
}
|
|
376
|
+
.toggle-btn:active { transform: scale(0.95); }
|
|
377
|
+
.toggle-btn:focus-visible { outline: 3px solid #60a5fa; outline-offset: 2px; }
|
|
378
|
+
|
|
379
|
+
.toggle-btn[aria-expanded="false"] .icon-close { display: none; }
|
|
380
|
+
.toggle-btn[aria-expanded="true"] .icon-chat { display: none; }
|
|
381
|
+
.toggle-btn svg { width: 1.375rem; height: 1.375rem; pointer-events: none; }
|
|
382
|
+
|
|
383
|
+
/* Unread-message badge */
|
|
384
|
+
.badge {
|
|
385
|
+
position: absolute;
|
|
386
|
+
top: 0.125rem;
|
|
387
|
+
right: 0.125rem;
|
|
388
|
+
width: 0.625rem;
|
|
389
|
+
height: 0.625rem;
|
|
390
|
+
border-radius: 50%;
|
|
391
|
+
background: #ef4444;
|
|
392
|
+
border: 2px solid #fff;
|
|
393
|
+
opacity: 0;
|
|
394
|
+
transform: scale(0);
|
|
395
|
+
transition: opacity 0.2s ease, transform 0.2s ease;
|
|
396
|
+
}
|
|
397
|
+
.badge.visible { opacity: 1; transform: scale(1); }
|
|
398
|
+
|
|
399
|
+
/* ── Chat panel ──────────────────────────────────────────────────────────── */
|
|
400
|
+
.panel {
|
|
401
|
+
position: fixed;
|
|
402
|
+
bottom: 5.5rem;
|
|
403
|
+
width: 26rem;
|
|
404
|
+
height: 70vh;
|
|
405
|
+
min-height: 25rem;
|
|
406
|
+
max-height: 47.5rem;
|
|
407
|
+
background: transparent;
|
|
408
|
+
border-radius: 1rem;
|
|
409
|
+
box-shadow: 0 8px 40px rgba(0, 0, 0, 0.22), 0 0 0 1px rgba(0, 0, 0, 0.06);
|
|
410
|
+
z-index: 2147483646;
|
|
411
|
+
overflow: hidden;
|
|
412
|
+
display: flex;
|
|
413
|
+
flex-direction: column;
|
|
414
|
+
transform-origin: bottom center;
|
|
415
|
+
transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.34, 1.3, 0.64, 1),
|
|
416
|
+
width 0.3s cubic-bezier(0.4, 0, 0.2, 1), height 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
|
417
|
+
bottom 0.3s cubic-bezier(0.4, 0, 0.2, 1), border-radius 0.3s ease;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.panel.bottom-right { right: 1.25rem; }
|
|
421
|
+
.panel.bottom-left { left: 1.25rem; }
|
|
422
|
+
|
|
423
|
+
.panel.closed {
|
|
424
|
+
opacity: 0;
|
|
425
|
+
pointer-events: none;
|
|
426
|
+
transform: translateY(0.5rem) scale(0.97);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/* Fullscreen mode */
|
|
430
|
+
.panel.fullscreen {
|
|
431
|
+
width: 100vw !important;
|
|
432
|
+
height: 100vh !important;
|
|
433
|
+
height: 100dvh !important;
|
|
434
|
+
bottom: 0 !important;
|
|
435
|
+
right: 0 !important;
|
|
436
|
+
left: 0 !important;
|
|
437
|
+
border-radius: 0 !important;
|
|
438
|
+
max-height: none !important;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.panel.fullscreen .chat-iframe {
|
|
442
|
+
border-radius: 0 !important;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/* Iframe fills the entire panel */
|
|
446
|
+
.chat-iframe {
|
|
447
|
+
width: 100%;
|
|
448
|
+
height: 100%;
|
|
449
|
+
border: none;
|
|
450
|
+
border-radius: 1rem;
|
|
451
|
+
display: block;
|
|
452
|
+
background: #fff;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/* ── Mobile: full-screen ─────────────────────────────────────────────────── */
|
|
456
|
+
@media (max-width: 30rem) {
|
|
457
|
+
.panel {
|
|
458
|
+
width: 100vw;
|
|
459
|
+
height: 85dvh;
|
|
460
|
+
bottom: 0;
|
|
461
|
+
right: 0 !important;
|
|
462
|
+
left: 0 !important;
|
|
463
|
+
border-radius: 1rem 1rem 0 0;
|
|
464
|
+
}
|
|
465
|
+
.chat-iframe { border-radius: 1rem 1rem 0 0; }
|
|
466
|
+
}
|
|
467
|
+
`, x = [
|
|
468
|
+
"iframe-url",
|
|
469
|
+
"app-id",
|
|
470
|
+
"app-name",
|
|
471
|
+
"service-url",
|
|
472
|
+
"auto-context",
|
|
473
|
+
"position",
|
|
474
|
+
"theme",
|
|
475
|
+
"token",
|
|
476
|
+
"context-interval"
|
|
477
|
+
], _ = class _ extends HTMLElement {
|
|
478
|
+
constructor() {
|
|
479
|
+
super(...arguments), this._open = !1, this._isFullscreen = !1, this._iframeEl = null, this._contextTimer = null;
|
|
480
|
+
}
|
|
481
|
+
connectedCallback() {
|
|
482
|
+
this._config = this._readConfig(), this._buildShadow(), this._startContextPolling();
|
|
483
|
+
const t = (e) => {
|
|
484
|
+
if (!e.data || typeof e.data != "object") return;
|
|
485
|
+
const { type: n } = e.data;
|
|
486
|
+
n === "btp-copilot:close" && this.close(), n === "btp-copilot:open" && this.open(), n === "btp-copilot:fullscreen" && this._toggleFullscreen(), n === "btp-copilot:minimize" && this.close();
|
|
487
|
+
};
|
|
488
|
+
window.addEventListener("message", t), this._removeMessageListener = () => window.removeEventListener("message", t);
|
|
489
|
+
}
|
|
490
|
+
disconnectedCallback() {
|
|
491
|
+
var t;
|
|
492
|
+
(t = this._removeMessageListener) == null || t.call(this), this._stopContextPolling();
|
|
493
|
+
}
|
|
494
|
+
attributeChangedCallback(t, e, n) {
|
|
495
|
+
e === n || !this.isConnected || (this._config = this._readConfig(), this._updateAfterAttributeChange());
|
|
496
|
+
}
|
|
497
|
+
// ── Public API ─────────────────────────────────────────────────────────────
|
|
498
|
+
open() {
|
|
499
|
+
this._open = !0, this.shadowRoot.querySelector(".panel").classList.remove("closed"), this.shadowRoot.querySelector(".toggle-btn").setAttribute("aria-expanded", "true"), this._clearBadge(), this._pushContextToIframe();
|
|
500
|
+
}
|
|
501
|
+
close() {
|
|
502
|
+
this._open = !1;
|
|
503
|
+
const t = this.shadowRoot.querySelector(".panel");
|
|
504
|
+
t.classList.add("closed"), t.classList.remove("fullscreen"), this._isFullscreen = !1, this.shadowRoot.querySelector(".toggle-btn").setAttribute("aria-expanded", "false");
|
|
505
|
+
}
|
|
506
|
+
_toggleFullscreen() {
|
|
507
|
+
this._isFullscreen = !this._isFullscreen;
|
|
508
|
+
const t = this.shadowRoot.querySelector(".panel"), e = this.shadowRoot.querySelector(".toggle-btn");
|
|
509
|
+
this._isFullscreen ? (t.classList.add("fullscreen"), e.style.display = "none") : (t.classList.remove("fullscreen"), e.style.display = "");
|
|
510
|
+
}
|
|
511
|
+
sendMessage(t) {
|
|
512
|
+
this._open || this.open(), setTimeout(() => {
|
|
513
|
+
var e, n;
|
|
514
|
+
(n = (e = this._iframeEl) == null ? void 0 : e.contentWindow) == null || n.postMessage(
|
|
515
|
+
{ type: "btp-copilot:send-message", text: t },
|
|
516
|
+
"*"
|
|
517
|
+
);
|
|
518
|
+
}, 100);
|
|
519
|
+
}
|
|
520
|
+
// ── Shadow DOM ─────────────────────────────────────────────────────────────
|
|
521
|
+
_buildShadow() {
|
|
522
|
+
var i;
|
|
523
|
+
const t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
|
|
524
|
+
e.textContent = v, t.appendChild(e);
|
|
525
|
+
const n = document.createElement("div");
|
|
526
|
+
for (n.innerHTML = this._template(); n.firstChild; ) t.appendChild(n.firstChild);
|
|
527
|
+
t.querySelector(".toggle-btn").addEventListener("click", () => {
|
|
528
|
+
this._open ? this.close() : this.open();
|
|
529
|
+
}), this._iframeEl = t.querySelector(".chat-iframe"), (i = this._iframeEl) == null || i.addEventListener("load", () => {
|
|
530
|
+
this._pushAuthToIframe(), this._pushContextToIframe();
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
_template() {
|
|
534
|
+
var n;
|
|
535
|
+
const t = ((n = this._config) == null ? void 0 : n.position) ?? "bottom-right", e = this._esc(this._buildIframeUrl());
|
|
536
|
+
return `
|
|
537
|
+
<button class="toggle-btn ${t}" aria-label="Open AI assistant" aria-expanded="false" aria-haspopup="dialog">
|
|
538
|
+
<svg class="icon-chat" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
539
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
|
|
540
|
+
</svg>
|
|
541
|
+
<svg class="icon-close" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
|
|
542
|
+
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
|
|
543
|
+
</svg>
|
|
544
|
+
<span class="badge" aria-hidden="true"></span>
|
|
545
|
+
</button>
|
|
546
|
+
|
|
547
|
+
<div class="panel closed ${t}" role="dialog" aria-label="AI Assistant" aria-modal="true">
|
|
548
|
+
<iframe
|
|
549
|
+
class="chat-iframe"
|
|
550
|
+
src="${e}"
|
|
551
|
+
title="AI Assistant"
|
|
552
|
+
allow="clipboard-read; clipboard-write"
|
|
553
|
+
loading="lazy">
|
|
554
|
+
</iframe>
|
|
555
|
+
</div>`;
|
|
556
|
+
}
|
|
557
|
+
// ── Context + Auth ─────────────────────────────────────────────────────────
|
|
558
|
+
_buildBaseContext() {
|
|
559
|
+
const t = d.resolve(this._config.token);
|
|
560
|
+
return {
|
|
561
|
+
app_id: this._config.appId,
|
|
562
|
+
app_name: this._config.appName,
|
|
563
|
+
service_url: this._config.serviceUrl,
|
|
564
|
+
// Include the resolved auth token in extra so the backend can
|
|
565
|
+
// proxy OData calls on behalf of the user to fetch real data
|
|
566
|
+
...t ? { extra: { auth_token: t } } : {}
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
_buildIframeUrl() {
|
|
570
|
+
var e;
|
|
571
|
+
const t = ((e = this._config) == null ? void 0 : e.iframeUrl) ?? "";
|
|
572
|
+
if (!t) return "";
|
|
573
|
+
try {
|
|
574
|
+
const n = new URL(t), { appId: i, appName: r, serviceUrl: s } = this._config;
|
|
575
|
+
i && n.searchParams.set("appId", i), r && n.searchParams.set("appName", r), s && n.searchParams.set("serviceUrl", s);
|
|
576
|
+
const a = d.resolve(this._config.token);
|
|
577
|
+
return a && n.searchParams.set("token", a), n.toString();
|
|
578
|
+
} catch {
|
|
579
|
+
return t;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
/** Derive the allowed postMessage target origin from the configured iframe URL.
|
|
583
|
+
* Falls back to "*" only when the URL cannot be parsed (e.g. empty string). */
|
|
584
|
+
_iframeOrigin() {
|
|
585
|
+
try {
|
|
586
|
+
return new URL(this._config.iframeUrl).origin;
|
|
587
|
+
} catch {
|
|
588
|
+
return "*";
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
_pushContextToIframe() {
|
|
592
|
+
var e;
|
|
593
|
+
if (!((e = this._iframeEl) != null && e.contentWindow)) return;
|
|
594
|
+
const t = this._iframeOrigin();
|
|
595
|
+
this._config.autoContext ? g.captureAsync(this._buildBaseContext()).then((n) => {
|
|
596
|
+
var i, r;
|
|
597
|
+
(r = (i = this._iframeEl) == null ? void 0 : i.contentWindow) == null || r.postMessage(
|
|
598
|
+
{ type: "btp-copilot:set-context", payload: n },
|
|
599
|
+
t
|
|
600
|
+
), n.service_url && !this._config.serviceUrl && (this._config = { ...this._config, serviceUrl: n.service_url });
|
|
601
|
+
}).catch(() => {
|
|
602
|
+
var n, i;
|
|
603
|
+
(i = (n = this._iframeEl) == null ? void 0 : n.contentWindow) == null || i.postMessage(
|
|
604
|
+
{ type: "btp-copilot:set-context", payload: this._buildBaseContext() },
|
|
605
|
+
t
|
|
606
|
+
);
|
|
607
|
+
}) : this._iframeEl.contentWindow.postMessage(
|
|
608
|
+
{ type: "btp-copilot:set-context", payload: this._buildBaseContext() },
|
|
609
|
+
t
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
_pushAuthToIframe() {
|
|
613
|
+
var e;
|
|
614
|
+
const t = d.resolve(this._config.token);
|
|
615
|
+
!t || !((e = this._iframeEl) != null && e.contentWindow) || this._iframeEl.contentWindow.postMessage(
|
|
616
|
+
{ type: "btp-copilot:auth", token: t },
|
|
617
|
+
this._iframeOrigin()
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
_startContextPolling() {
|
|
621
|
+
this._config.autoContext && (this._contextTimer = setInterval(() => {
|
|
622
|
+
this._open && this._pushContextToIframe();
|
|
623
|
+
}, this._config.contextInterval));
|
|
624
|
+
}
|
|
625
|
+
_stopContextPolling() {
|
|
626
|
+
this._contextTimer !== null && (clearInterval(this._contextTimer), this._contextTimer = null);
|
|
627
|
+
}
|
|
628
|
+
// ── Config ─────────────────────────────────────────────────────────────────
|
|
629
|
+
_readConfig() {
|
|
630
|
+
const t = (e) => this.getAttribute(e);
|
|
631
|
+
return {
|
|
632
|
+
iframeUrl: t("iframe-url") ?? "",
|
|
633
|
+
appId: t("app-id") ?? "default",
|
|
634
|
+
appName: t("app-name") ?? void 0,
|
|
635
|
+
serviceUrl: t("service-url") ?? void 0,
|
|
636
|
+
autoContext: t("auto-context") !== "false",
|
|
637
|
+
position: t("position") ?? "bottom-right",
|
|
638
|
+
theme: t("theme") ?? "auto",
|
|
639
|
+
token: t("token") ?? void 0,
|
|
640
|
+
contextInterval: Math.max(500, Number(t("context-interval")) || 3e3)
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
_updateAfterAttributeChange() {
|
|
644
|
+
var n;
|
|
645
|
+
const t = (n = this.shadowRoot) == null ? void 0 : n.querySelector("style");
|
|
646
|
+
t && (t.textContent = v);
|
|
647
|
+
const e = this._buildIframeUrl();
|
|
648
|
+
this._iframeEl && this._iframeEl.src !== e && e && (this._iframeEl.src = e), this._stopContextPolling(), this._startContextPolling();
|
|
649
|
+
}
|
|
650
|
+
_clearBadge() {
|
|
651
|
+
var t, e;
|
|
652
|
+
(e = (t = this.shadowRoot) == null ? void 0 : t.querySelector(".badge")) == null || e.classList.remove("visible");
|
|
653
|
+
}
|
|
654
|
+
_esc(t) {
|
|
655
|
+
return t.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
_.observedAttributes = [...x];
|
|
659
|
+
let y = _;
|
|
660
|
+
customElements.get("btp-copilot") || customElements.define("btp-copilot", y);
|
|
661
|
+
export {
|
|
662
|
+
y as BtpCopilotElement,
|
|
663
|
+
g as ContextBridge
|
|
664
|
+
};
|
|
665
|
+
//# sourceMappingURL=btp-copilot.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"btp-copilot.esm.js","sources":["../src/api/TokenManager.ts","../src/context/ShellProbe.ts","../src/context/UI5Probe.ts","../src/context/ODataProbe.ts","../src/context/ContextBridge.ts","../src/styles/widget.css?raw","../src/BtpCopilotElement.ts","../src/index.ts"],"sourcesContent":["export class TokenManager {\n private static readonly XSUAA_COOKIE_NAMES = [\n \"x-uaa-token\",\n \"xsuaa_token\",\n \"access_token\",\n \"X-Authorization\",\n ];\n\n static resolve(explicitToken?: string | null): string | null {\n if (explicitToken) return explicitToken.replace(/^Bearer\\s+/i, \"\");\n\n const windowToken = (window as any).__BTP_COPILOT_TOKEN__ as\n | string\n | undefined;\n if (windowToken) return windowToken.replace(/^Bearer\\s+/i, \"\");\n\n const cookieToken = TokenManager._fromCookie();\n if (cookieToken) return cookieToken;\n\n try {\n const lsToken = localStorage.getItem(\"access_token\");\n if (lsToken) return lsToken;\n } catch {}\n\n return null;\n }\n\n static getAuthHeader(token: string | null): Record<string, string> {\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n\n private static _fromCookie(): string | null {\n try {\n const cookies = document.cookie.split(\";\");\n for (const cookie of cookies) {\n const [name, ...rest] = cookie.trim().split(\"=\");\n if (TokenManager.XSUAA_COOKIE_NAMES.includes(name.trim())) {\n return decodeURIComponent(rest.join(\"=\").trim());\n }\n }\n } catch {}\n return null;\n }\n}\n","declare const sap: any;\n\nexport class ShellProbe {\n static getHash(): string {\n try {\n const nav = sap?.ushell?.Container?.getService?.(\n \"CrossApplicationNavigation\",\n );\n if (nav) {\n const href = nav.hrefForExternal?.() as string | undefined;\n if (href) return href;\n }\n } catch (err) {\n console.log(err);\n }\n return window.location.hash || \"\";\n }\n\n static getCurrentAppId(): string | null {\n try {\n const hash = ShellProbe.getHash();\n const match = hash.match(/^#([^&?/]+)/);\n return match ? match[1] : null;\n } catch {\n return null;\n }\n }\n\n static getUserLocale(): string {\n try {\n return (\n sap?.ui?.getCore?.()?.getConfiguration?.()?.getLanguageTag?.() ??\n navigator.language ??\n \"en\"\n );\n } catch {\n return navigator.language ?? \"en\";\n }\n }\n}\n","declare const sap: any;\n\nexport class UI5Probe {\n static getCurrentEntity(): Record<string, unknown> | null {\n try {\n const core = sap?.ui?.getCore?.();\n if (!core) return null;\n\n let el: Element | null = document.activeElement;\n while (el) {\n const id = el.getAttribute(\"id\") || el.getAttribute(\"data-sap-ui\");\n if (id) {\n const control = core.byId(id);\n const ctx = control?.getBindingContext?.();\n if (ctx) {\n const obj = ctx.getObject?.();\n if (obj && typeof obj === \"object\") {\n return UI5Probe._sanitize(obj as Record<string, unknown>);\n }\n }\n }\n el = el.parentElement;\n }\n return UI5Probe._scanAllControls(core);\n } catch {\n return null;\n }\n }\n\n private static _scanAllControls(core: any): Record<string, unknown> | null {\n try {\n const elements = core.mElements ?? {};\n for (const id of Object.keys(elements)) {\n const control = elements[id];\n const ctx = control?.getBindingContext?.();\n if (ctx) {\n const obj = ctx.getObject?.();\n if (obj && typeof obj === \"object\" && Object.keys(obj).length > 0) {\n return UI5Probe._sanitize(obj as Record<string, unknown>);\n }\n }\n }\n } catch {}\n return null;\n }\n\n static getServiceUrl(): string | null {\n try {\n const core = sap?.ui?.getCore?.();\n if (!core) return null;\n const elements = core.mElements ?? {};\n for (const id of Object.keys(elements)) {\n const control = elements[id];\n if (!control?.getModel) continue;\n const model = control.getModel();\n if (!model) continue;\n const url: unknown = model.sServiceUrl ?? (model as any)._sServiceUrl;\n if (typeof url === \"string\" && url.length > 4) {\n return url.replace(/\\/$/, \"\");\n }\n }\n } catch {}\n return null;\n }\n\n private static _sanitize(\n obj: Record<string, unknown>,\n ): Record<string, unknown> {\n const clean: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(obj)) {\n if (k.startsWith(\"__\")) continue;\n if (v === null || typeof v !== \"object\") {\n clean[k] = v;\n } else if ((v as any).__deferred) {\n // navigation property stub — skip\n } else {\n clean[k] = v;\n }\n }\n return clean;\n }\n}\n","import type {\n EntitySchema,\n EntityProperty,\n NavProperty,\n AppDocument,\n} from \"../types\";\n\nexport class ODataProbe {\n private static _cache = new Map<string, AppDocument[]>();\n\n static async fetchSchemaDocuments(\n serviceUrl: string,\n token?: string | null,\n ): Promise<AppDocument[]> {\n const cacheKey = `btp-copilot-meta-${serviceUrl}`;\n\n if (ODataProbe._cache.has(cacheKey)) {\n return ODataProbe._cache.get(cacheKey)!;\n }\n\n const stored = sessionStorage.getItem(cacheKey);\n if (stored) {\n try {\n const docs = JSON.parse(stored) as AppDocument[];\n ODataProbe._cache.set(cacheKey, docs);\n return docs;\n } catch {}\n }\n\n try {\n const metaUrl = `${serviceUrl}/$metadata`;\n const headers: Record<string, string> = { Accept: \"application/xml\" };\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n\n const resp = await fetch(metaUrl, { headers });\n if (!resp.ok) return [];\n\n const xml = await resp.text();\n const schemas = ODataProbe._parseEDMX(xml);\n const docs = ODataProbe._schemasToDocuments(schemas, serviceUrl);\n\n ODataProbe._cache.set(cacheKey, docs);\n sessionStorage.setItem(cacheKey, JSON.stringify(docs));\n return docs;\n } catch {\n return [];\n }\n }\n\n private static _parseEDMX(xml: string): EntitySchema[] {\n try {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml, \"text/xml\");\n const entityTypes = doc.querySelectorAll(\"EntityType\");\n return Array.from(entityTypes).map((et) => {\n const name = et.getAttribute(\"Name\") ?? \"\";\n const keyRefs = et.querySelectorAll(\"Key > PropertyRef\");\n const keyNames = new Set(\n Array.from(keyRefs).map((k) => k.getAttribute(\"Name\") ?? \"\"),\n );\n const properties: EntityProperty[] = Array.from(\n et.querySelectorAll(\"Property\"),\n ).map((p) => ({\n name: p.getAttribute(\"Name\") ?? \"\",\n type: ODataProbe._shortType(p.getAttribute(\"Type\") ?? \"\"),\n isKey: keyNames.has(p.getAttribute(\"Name\") ?? \"\"),\n nullable: p.getAttribute(\"Nullable\") !== \"false\",\n }));\n const navProperties: NavProperty[] = Array.from(\n et.querySelectorAll(\"NavigationProperty\"),\n ).map((n) => ({\n name: n.getAttribute(\"Name\") ?? \"\",\n type: ODataProbe._shortType(\n n.getAttribute(\"Type\") ?? n.getAttribute(\"ToRole\") ?? \"\",\n ),\n }));\n return { name, properties, navProperties };\n });\n } catch {\n return [];\n }\n }\n\n private static _shortType(full: string): string {\n if (full.startsWith(\"Collection(\")) {\n const inner = full.slice(11, -1);\n return `${inner.split(\".\").pop()}[]`;\n }\n return full.split(\".\").pop() ?? full;\n }\n\n private static _schemasToDocuments(\n schemas: EntitySchema[],\n serviceUrl: string,\n ): AppDocument[] {\n const docs: AppDocument[] = [];\n\n for (const schema of schemas) {\n if (!schema.name) continue;\n const keyProps = schema.properties.filter((p) => p.isKey);\n const otherProps = schema.properties.filter((p) => !p.isKey);\n const lines = [\n `Entity: ${schema.name}`,\n `OData service: ${serviceUrl}`,\n `Entity set path: ${serviceUrl}/${schema.name}`,\n `Count path: ${serviceUrl}/${schema.name}/$count`,\n ];\n if (keyProps.length) {\n lines.push(\n `Key fields: ${keyProps.map((p) => `${p.name} (${p.type})`).join(\", \")}`,\n );\n }\n if (otherProps.length) {\n lines.push(\n `Fields: ${otherProps\n .map(\n (p) => `${p.name} (${p.type}${p.nullable ? \"\" : \", required\"})`,\n )\n .join(\", \")}`,\n );\n }\n if (schema.navProperties.length) {\n lines.push(\n `Navigation: ${schema.navProperties.map((n) => `${n.name} → ${n.type}`).join(\", \")}`,\n );\n }\n docs.push({\n title: `${schema.name} entity schema`,\n content: lines.join(\"\\n\"),\n });\n }\n\n if (schemas.length > 0) {\n docs.push({\n title: \"Available OData entity sets\",\n content: [\n `OData service: ${serviceUrl}`,\n `Entities: ${schemas.map((s) => s.name).join(\", \")}`,\n \"GET {entity}/$count | ?$filter=field eq 'value' | ?$top=10&$skip=0 | ?$orderby=field desc\",\n ].join(\"\\n\"),\n });\n }\n\n return docs;\n }\n\n static invalidate(serviceUrl: string) {\n const key = `btp-copilot-meta-${serviceUrl}`;\n ODataProbe._cache.delete(key);\n sessionStorage.removeItem(key);\n }\n}\n","import type { HostAppContext } from \"../types\";\nimport { ShellProbe } from \"./ShellProbe\";\nimport { UI5Probe } from \"./UI5Probe\";\nimport { ODataProbe } from \"./ODataProbe\";\n\nexport class ContextBridge {\n static capture(baseContext: HostAppContext): HostAppContext {\n const ctx: HostAppContext = { ...baseContext };\n\n try {\n const hash = ShellProbe.getHash();\n if (hash) ctx.current_view = hash;\n } catch {}\n\n try {\n const entity = UI5Probe.getCurrentEntity();\n if (entity && Object.keys(entity).length > 0) ctx.entity_data = entity;\n } catch {}\n\n try {\n if (!ctx.user_locale) ctx.user_locale = ShellProbe.getUserLocale();\n } catch {}\n\n // Merge any context injected by the host app\n try {\n const injected = (window as any).__APP_CONTEXT__ as\n | Partial<HostAppContext>\n | undefined;\n if (injected) {\n if (injected.entity_data)\n ctx.entity_data = { ...injected.entity_data, ...ctx.entity_data };\n if (injected.current_view && !ctx.current_view)\n ctx.current_view = injected.current_view;\n if (injected.extra)\n ctx.extra = { ...injected.extra, ...(ctx.extra ?? {}) };\n if (injected.service_url && !ctx.service_url)\n ctx.service_url = injected.service_url;\n }\n } catch {}\n\n return ctx;\n }\n\n static async captureAsync(\n baseContext: HostAppContext,\n ): Promise<HostAppContext> {\n const ctx = ContextBridge.capture(baseContext);\n\n if (!ctx.service_url) {\n ctx.service_url = ContextBridge._discoverServiceUrl() ?? undefined;\n }\n\n if (ctx.service_url) {\n try {\n const token = (ctx.extra as any)?.auth_token ?? null;\n const docs = await ODataProbe.fetchSchemaDocuments(\n ctx.service_url,\n token,\n );\n if (docs.length > 0) {\n const schemaHint = docs\n .map((d) => `## ${d.title}\\n${d.content}`)\n .join(\"\\n\\n\");\n ctx.extra = { ...(ctx.extra ?? {}), schema_hint: schemaHint };\n }\n } catch {}\n }\n\n return ctx;\n }\n\n private static _discoverServiceUrl(): string | null {\n try {\n const url = UI5Probe.getServiceUrl();\n if (url) return url;\n } catch {}\n\n try {\n const entries = performance.getEntriesByType(\n \"resource\",\n ) as PerformanceResourceTiming[];\n for (const e of entries) {\n const m = e.name.match(/^(https?:\\/\\/[^?#]+)\\/\\$metadata/);\n if (m) return m[1];\n }\n } catch {}\n\n try {\n const m = window.location.href.match(\n /(https?:\\/\\/[^/]+(?:\\/odata\\/v[24]\\/[^/?#]+|\\/sap\\/opu\\/odata\\/[^/?#]+))/,\n );\n if (m) return m[1];\n } catch {}\n\n return null;\n }\n\n static async discoverFromManifest(): Promise<string | null> {\n try {\n const resp = await fetch(\"/manifest.json\");\n if (!resp.ok) return null;\n const manifest = await resp.json();\n const sources: Record<string, any> =\n manifest?.[\"sap.app\"]?.dataSources ?? {};\n for (const key of Object.keys(sources)) {\n const src = sources[key];\n if (src?.type === \"ODataAnnotation\") continue;\n const uri: unknown = src?.uri;\n if (typeof uri === \"string\" && uri.length > 0) {\n return new URL(uri, window.location.href)\n .toString()\n .replace(/\\/$/, \"\");\n }\n }\n } catch {}\n return null;\n }\n\n static listenForUpdates(\n onContextUpdate: (ctx: Partial<HostAppContext>) => void,\n onMessage: (text: string) => void,\n onOpen: () => void,\n onClose: () => void,\n ): () => void {\n const handler = (event: MessageEvent) => {\n if (!event.data || typeof event.data !== \"object\") return;\n const { type, payload, text } = event.data as {\n type?: string;\n payload?: Partial<HostAppContext>;\n text?: string;\n };\n switch (type) {\n case \"btp-copilot:set-context\":\n if (payload) onContextUpdate(payload);\n break;\n case \"btp-copilot:send-message\":\n if (text) onMessage(text);\n break;\n case \"btp-copilot:open\":\n onOpen();\n break;\n case \"btp-copilot:close\":\n onClose();\n break;\n }\n };\n window.addEventListener(\"message\", handler);\n return () => window.removeEventListener(\"message\", handler);\n }\n}\n","export default \"/* ── Host element ─────────────────────────────────────────────────────────── */\\n:host {\\n position: fixed;\\n z-index: 2147483647;\\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\\n}\\n\\n*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\\n\\n/* ── Toggle (FAB) button ─────────────────────────────────────────────────── */\\n.toggle-btn {\\n position: fixed;\\n bottom: 1.25rem;\\n width: 3.25rem;\\n height: 3.25rem;\\n border-radius: 50%;\\n border: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\\n color: #fff;\\n box-shadow: 0 4px 14px rgba(102, 126, 234, 0.45);\\n z-index: 2147483647;\\n transition: transform 0.2s ease, box-shadow 0.2s ease;\\n outline: none;\\n}\\n\\n.toggle-btn.bottom-right { right: 1.25rem; }\\n.toggle-btn.bottom-left { left: 1.25rem; }\\n\\n.toggle-btn:hover {\\n transform: scale(1.08);\\n box-shadow: 0 6px 20px rgba(102, 126, 234, 0.55);\\n}\\n.toggle-btn:active { transform: scale(0.95); }\\n.toggle-btn:focus-visible { outline: 3px solid #60a5fa; outline-offset: 2px; }\\n\\n.toggle-btn[aria-expanded=\\\"false\\\"] .icon-close { display: none; }\\n.toggle-btn[aria-expanded=\\\"true\\\"] .icon-chat { display: none; }\\n.toggle-btn svg { width: 1.375rem; height: 1.375rem; pointer-events: none; }\\n\\n/* Unread-message badge */\\n.badge {\\n position: absolute;\\n top: 0.125rem;\\n right: 0.125rem;\\n width: 0.625rem;\\n height: 0.625rem;\\n border-radius: 50%;\\n background: #ef4444;\\n border: 2px solid #fff;\\n opacity: 0;\\n transform: scale(0);\\n transition: opacity 0.2s ease, transform 0.2s ease;\\n}\\n.badge.visible { opacity: 1; transform: scale(1); }\\n\\n/* ── Chat panel ──────────────────────────────────────────────────────────── */\\n.panel {\\n position: fixed;\\n bottom: 5.5rem;\\n width: 26rem;\\n height: 70vh;\\n min-height: 25rem;\\n max-height: 47.5rem;\\n background: transparent;\\n border-radius: 1rem;\\n box-shadow: 0 8px 40px rgba(0, 0, 0, 0.22), 0 0 0 1px rgba(0, 0, 0, 0.06);\\n z-index: 2147483646;\\n overflow: hidden;\\n display: flex;\\n flex-direction: column;\\n transform-origin: bottom center;\\n transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.34, 1.3, 0.64, 1),\\n width 0.3s cubic-bezier(0.4, 0, 0.2, 1), height 0.3s cubic-bezier(0.4, 0, 0.2, 1),\\n bottom 0.3s cubic-bezier(0.4, 0, 0.2, 1), border-radius 0.3s ease;\\n}\\n\\n.panel.bottom-right { right: 1.25rem; }\\n.panel.bottom-left { left: 1.25rem; }\\n\\n.panel.closed {\\n opacity: 0;\\n pointer-events: none;\\n transform: translateY(0.5rem) scale(0.97);\\n}\\n\\n/* Fullscreen mode */\\n.panel.fullscreen {\\n width: 100vw !important;\\n height: 100vh !important;\\n height: 100dvh !important;\\n bottom: 0 !important;\\n right: 0 !important;\\n left: 0 !important;\\n border-radius: 0 !important;\\n max-height: none !important;\\n}\\n\\n.panel.fullscreen .chat-iframe {\\n border-radius: 0 !important;\\n}\\n\\n/* Iframe fills the entire panel */\\n.chat-iframe {\\n width: 100%;\\n height: 100%;\\n border: none;\\n border-radius: 1rem;\\n display: block;\\n background: #fff;\\n}\\n\\n/* ── Mobile: full-screen ─────────────────────────────────────────────────── */\\n@media (max-width: 30rem) {\\n .panel {\\n width: 100vw;\\n height: 85dvh;\\n bottom: 0;\\n right: 0 !important;\\n left: 0 !important;\\n border-radius: 1rem 1rem 0 0;\\n }\\n .chat-iframe { border-radius: 1rem 1rem 0 0; }\\n}\\n\"","/**\n * BtpCopilotElement — <btp-copilot> Custom Element.\n *\n * Renders a fixed floating FAB button. When opened, shows your deployed\n * BTP Copilot React chatbot in an iframe. Context from the host UI5/Fiori\n * app is auto-captured and forwarded into the iframe via postMessage so the\n * chatbot is always aware of what the user is looking at.\n *\n * Attributes:\n * iframe-url Full URL of the deployed React chatbot frontend (required)\n * app-id Stable identifier of the host application (required)\n * app-name Human-readable app name\n * service-url OData service URL for context auto-capture\n * auto-context \"true\"|\"false\" — auto-capture UI5/OData context (default: true)\n * position \"bottom-right\"|\"bottom-left\" (default: bottom-right)\n * theme \"auto\"|\"light\"|\"dark\" (default: auto)\n * token Bearer token forwarded to the chatbot iframe\n * context-interval Context re-capture interval in ms (default: 3000)\n *\n * postMessage protocol (outgoing → iframe):\n * { type: 'btp-copilot:set-context', payload: HostAppContext }\n * { type: 'btp-copilot:auth', token: string }\n *\n * postMessage protocol (incoming ← iframe or host page):\n * { type: 'btp-copilot:close' }\n * { type: 'btp-copilot:open' }\n */\n\nimport type { HostAppContext, WidgetConfig } from \"./types\";\nimport { TokenManager } from \"./api/TokenManager\";\nimport { ContextBridge } from \"./context/ContextBridge\";\nimport widgetCss from \"./styles/widget.css?raw\";\n\nconst OBSERVED = [\n \"iframe-url\",\n \"app-id\",\n \"app-name\",\n \"service-url\",\n \"auto-context\",\n \"position\",\n \"theme\",\n \"token\",\n \"context-interval\",\n] as const;\n\nexport class BtpCopilotElement extends HTMLElement {\n static observedAttributes = [...OBSERVED];\n\n private _config!: WidgetConfig;\n private _open = false;\n private _isFullscreen = false;\n private _iframeEl: HTMLIFrameElement | null = null;\n private _contextTimer: ReturnType<typeof setInterval> | null = null;\n private _removeMessageListener?: () => void;\n\n connectedCallback() {\n this._config = this._readConfig();\n this._buildShadow();\n this._startContextPolling();\n\n const msgHandler = (event: MessageEvent) => {\n if (!event.data || typeof event.data !== \"object\") return;\n const { type } = event.data as { type?: string };\n if (type === \"btp-copilot:close\") this.close();\n if (type === \"btp-copilot:open\") this.open();\n if (type === \"btp-copilot:fullscreen\") this._toggleFullscreen();\n if (type === \"btp-copilot:minimize\") this.close();\n };\n window.addEventListener(\"message\", msgHandler);\n this._removeMessageListener = () =>\n window.removeEventListener(\"message\", msgHandler);\n }\n\n disconnectedCallback() {\n this._removeMessageListener?.();\n this._stopContextPolling();\n }\n\n attributeChangedCallback(\n _name: string,\n old: string | null,\n next: string | null\n ) {\n if (old === next || !this.isConnected) return;\n this._config = this._readConfig();\n this._updateAfterAttributeChange();\n }\n\n // ── Public API ─────────────────────────────────────────────────────────────\n open() {\n this._open = true;\n this.shadowRoot!.querySelector(\".panel\")!.classList.remove(\"closed\");\n this.shadowRoot!\n .querySelector(\".toggle-btn\")!\n .setAttribute(\"aria-expanded\", \"true\");\n this._clearBadge();\n this._pushContextToIframe();\n }\n\n close() {\n this._open = false;\n const panel = this.shadowRoot!.querySelector(\".panel\")!;\n panel.classList.add(\"closed\");\n panel.classList.remove(\"fullscreen\");\n this._isFullscreen = false;\n this.shadowRoot!\n .querySelector(\".toggle-btn\")!\n .setAttribute(\"aria-expanded\", \"false\");\n }\n\n private _toggleFullscreen() {\n this._isFullscreen = !this._isFullscreen;\n const panel = this.shadowRoot!.querySelector(\".panel\")!;\n const fab = this.shadowRoot!.querySelector(\".toggle-btn\") as HTMLElement;\n if (this._isFullscreen) {\n panel.classList.add(\"fullscreen\");\n fab.style.display = \"none\";\n } else {\n panel.classList.remove(\"fullscreen\");\n fab.style.display = \"\";\n }\n }\n\n sendMessage(text: string) {\n if (!this._open) this.open();\n setTimeout(() => {\n this._iframeEl?.contentWindow?.postMessage(\n { type: \"btp-copilot:send-message\", text },\n \"*\"\n );\n }, 100);\n }\n\n // ── Shadow DOM ─────────────────────────────────────────────────────────────\n private _buildShadow() {\n const shadow = this.attachShadow({ mode: \"open\" });\n\n const styleEl = document.createElement(\"style\");\n styleEl.textContent = widgetCss;\n shadow.appendChild(styleEl);\n\n const wrapper = document.createElement(\"div\");\n wrapper.innerHTML = this._template();\n while (wrapper.firstChild) shadow.appendChild(wrapper.firstChild);\n\n shadow.querySelector(\".toggle-btn\")!.addEventListener(\"click\", () => {\n this._open ? this.close() : this.open();\n });\n\n this._iframeEl = shadow.querySelector(\".chat-iframe\");\n\n this._iframeEl?.addEventListener(\"load\", () => {\n this._pushAuthToIframe();\n this._pushContextToIframe();\n });\n }\n\n private _template(): string {\n const pos = this._config?.position ?? \"bottom-right\";\n const src = this._esc(this._buildIframeUrl());\n return `\n<button class=\"toggle-btn ${pos}\" aria-label=\"Open AI assistant\" aria-expanded=\"false\" aria-haspopup=\"dialog\">\n <svg class=\"icon-chat\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n <svg class=\"icon-close\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n <span class=\"badge\" aria-hidden=\"true\"></span>\n</button>\n\n<div class=\"panel closed ${pos}\" role=\"dialog\" aria-label=\"AI Assistant\" aria-modal=\"true\">\n <iframe\n class=\"chat-iframe\"\n src=\"${src}\"\n title=\"AI Assistant\"\n allow=\"clipboard-read; clipboard-write\"\n loading=\"lazy\">\n </iframe>\n</div>`;\n }\n\n // ── Context + Auth ─────────────────────────────────────────────────────────\n private _buildBaseContext(): HostAppContext {\n const token = TokenManager.resolve(this._config.token);\n return {\n app_id: this._config.appId,\n app_name: this._config.appName,\n service_url: this._config.serviceUrl,\n // Include the resolved auth token in extra so the backend can\n // proxy OData calls on behalf of the user to fetch real data\n ...(token ? { extra: { auth_token: token } } : {}),\n };\n }\n\n private _buildIframeUrl(): string {\n const base = this._config?.iframeUrl ?? \"\";\n if (!base) return \"\";\n try {\n const url = new URL(base);\n const { appId, appName, serviceUrl } = this._config;\n if (appId) url.searchParams.set(\"appId\", appId);\n if (appName) url.searchParams.set(\"appName\", appName);\n if (serviceUrl) url.searchParams.set(\"serviceUrl\", serviceUrl);\n // Pass token as URL param so the chatbot can auto-authenticate in iframe mode\n const token = TokenManager.resolve(this._config.token);\n if (token) url.searchParams.set(\"token\", token);\n return url.toString();\n } catch {\n return base;\n }\n }\n\n /** Derive the allowed postMessage target origin from the configured iframe URL.\n * Falls back to \"*\" only when the URL cannot be parsed (e.g. empty string). */\n private _iframeOrigin(): string {\n try {\n return new URL(this._config.iframeUrl).origin;\n } catch {\n return \"*\";\n }\n }\n\n private _pushContextToIframe() {\n if (!this._iframeEl?.contentWindow) return;\n const origin = this._iframeOrigin();\n\n if (this._config.autoContext) {\n ContextBridge.captureAsync(this._buildBaseContext())\n .then((ctx) => {\n this._iframeEl?.contentWindow?.postMessage(\n { type: \"btp-copilot:set-context\", payload: ctx },\n origin\n );\n if (ctx.service_url && !this._config.serviceUrl) {\n this._config = { ...this._config, serviceUrl: ctx.service_url };\n }\n })\n .catch(() => {\n this._iframeEl?.contentWindow?.postMessage(\n { type: \"btp-copilot:set-context\", payload: this._buildBaseContext() },\n origin\n );\n });\n } else {\n this._iframeEl.contentWindow.postMessage(\n { type: \"btp-copilot:set-context\", payload: this._buildBaseContext() },\n origin\n );\n }\n }\n\n private _pushAuthToIframe() {\n const token = TokenManager.resolve(this._config.token);\n if (!token || !this._iframeEl?.contentWindow) return;\n this._iframeEl.contentWindow.postMessage(\n { type: \"btp-copilot:auth\", token },\n this._iframeOrigin()\n );\n }\n\n private _startContextPolling() {\n if (!this._config.autoContext) return;\n this._contextTimer = setInterval(() => {\n if (this._open) this._pushContextToIframe();\n }, this._config.contextInterval);\n }\n\n private _stopContextPolling() {\n if (this._contextTimer !== null) {\n clearInterval(this._contextTimer);\n this._contextTimer = null;\n }\n }\n\n // ── Config ─────────────────────────────────────────────────────────────────\n private _readConfig(): WidgetConfig {\n const get = (attr: string) => this.getAttribute(attr);\n return {\n iframeUrl: get(\"iframe-url\") ?? \"\",\n appId: get(\"app-id\") ?? \"default\",\n appName: get(\"app-name\") ?? undefined,\n serviceUrl: get(\"service-url\") ?? undefined,\n autoContext: get(\"auto-context\") !== \"false\",\n position: (get(\"position\") ?? \"bottom-right\") as WidgetConfig[\"position\"],\n theme: (get(\"theme\") ?? \"auto\") as WidgetConfig[\"theme\"],\n token: get(\"token\") ?? undefined,\n contextInterval: Math.max(500, Number(get(\"context-interval\")) || 3000),\n };\n }\n\n private _updateAfterAttributeChange() {\n const style = this.shadowRoot?.querySelector(\"style\");\n if (style) style.textContent = widgetCss;\n\n const newSrc = this._buildIframeUrl();\n if (this._iframeEl && this._iframeEl.src !== newSrc && newSrc) {\n this._iframeEl.src = newSrc;\n }\n\n this._stopContextPolling();\n this._startContextPolling();\n }\n\n private _clearBadge() {\n this.shadowRoot?.querySelector(\".badge\")?.classList.remove(\"visible\");\n }\n\n private _esc(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n }\n}\n","import { BtpCopilotElement } from \"./BtpCopilotElement\";\n\nif (!customElements.get(\"btp-copilot\")) {\n customElements.define(\"btp-copilot\", BtpCopilotElement);\n}\n\nexport { BtpCopilotElement };\nexport type { HostAppContext, WidgetConfig, AppDocument } from \"./types\";\nexport { ContextBridge } from \"./context/ContextBridge\";\n"],"names":["_TokenManager","explicitToken","windowToken","cookieToken","lsToken","token","cookies","cookie","name","rest","TokenManager","ShellProbe","_a","_b","_c","_d","nav","href","err","match","_e","_f","UI5Probe","core","el","id","control","ctx","obj","elements","model","url","clean","k","v","_ODataProbe","serviceUrl","cacheKey","stored","docs","metaUrl","headers","resp","xml","schemas","entityTypes","et","keyRefs","keyNames","properties","p","navProperties","n","full","schema","keyProps","otherProps","lines","s","key","ODataProbe","ContextBridge","baseContext","hash","entity","injected","schemaHint","d","entries","m","manifest","sources","src","uri","onContextUpdate","onMessage","onOpen","onClose","handler","event","type","payload","text","widgetCss","OBSERVED","_BtpCopilotElement","msgHandler","_name","old","next","panel","fab","shadow","styleEl","wrapper","pos","base","appId","appName","origin","get","attr","style","newSrc","BtpCopilotElement"],"mappings":"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"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
var BtpCopilot=function(g){"use strict";const m=class m{static resolve(t){if(t)return t.replace(/^Bearer\s+/i,"");const e=window.__BTP_COPILOT_TOKEN__;if(e)return e.replace(/^Bearer\s+/i,"");const n=m._fromCookie();if(n)return n;try{const i=localStorage.getItem("access_token");if(i)return i}catch{}return null}static getAuthHeader(t){return t?{Authorization:`Bearer ${t}`}:{}}static _fromCookie(){try{const t=document.cookie.split(";");for(const e of t){const[n,...i]=e.trim().split("=");if(m.XSUAA_COOKIE_NAMES.includes(n.trim()))return decodeURIComponent(i.join("=").trim())}}catch{}return null}};m.XSUAA_COOKIE_NAMES=["x-uaa-token","xsuaa_token","access_token","X-Authorization"];let d=m;class b{static getHash(){var t,e,n,i;try{const r=(n=(e=(t=sap==null?void 0:sap.ushell)==null?void 0:t.Container)==null?void 0:e.getService)==null?void 0:n.call(e,"CrossApplicationNavigation");if(r){const o=(i=r.hrefForExternal)==null?void 0:i.call(r);if(o)return o}}catch(r){console.log(r)}return window.location.hash||""}static getCurrentAppId(){try{const e=b.getHash().match(/^#([^&?/]+)/);return e?e[1]:null}catch{return null}}static getUserLocale(){var t,e,n,i,r,o;try{return((o=(r=(i=(n=(e=(t=sap==null?void 0:sap.ui)==null?void 0:t.getCore)==null?void 0:e.call(t))==null?void 0:n.getConfiguration)==null?void 0:i.call(n))==null?void 0:r.getLanguageTag)==null?void 0:o.call(r))??navigator.language??"en"}catch{return navigator.language??"en"}}}class u{static getCurrentEntity(){var t,e,n,i;try{const r=(e=(t=sap==null?void 0:sap.ui)==null?void 0:t.getCore)==null?void 0:e.call(t);if(!r)return null;let o=document.activeElement;for(;o;){const a=o.getAttribute("id")||o.getAttribute("data-sap-ui");if(a){const s=r.byId(a),l=(n=s==null?void 0:s.getBindingContext)==null?void 0:n.call(s);if(l){const p=(i=l.getObject)==null?void 0:i.call(l);if(p&&typeof p=="object")return u._sanitize(p)}}o=o.parentElement}return u._scanAllControls(r)}catch{return null}}static _scanAllControls(t){var e,n;try{const i=t.mElements??{};for(const r of Object.keys(i)){const o=i[r],a=(e=o==null?void 0:o.getBindingContext)==null?void 0:e.call(o);if(a){const s=(n=a.getObject)==null?void 0:n.call(a);if(s&&typeof s=="object"&&Object.keys(s).length>0)return u._sanitize(s)}}}catch{}return null}static getServiceUrl(){var t,e;try{const n=(e=(t=sap==null?void 0:sap.ui)==null?void 0:t.getCore)==null?void 0:e.call(t);if(!n)return null;const i=n.mElements??{};for(const r of Object.keys(i)){const o=i[r];if(!(o!=null&&o.getModel))continue;const a=o.getModel();if(!a)continue;const s=a.sServiceUrl??a._sServiceUrl;if(typeof s=="string"&&s.length>4)return s.replace(/\/$/,"")}}catch{}return null}static _sanitize(t){const e={};for(const[n,i]of Object.entries(t))n.startsWith("__")||(i===null||typeof i!="object"?e[n]=i:i.__deferred||(e[n]=i));return e}}const c=class c{static async fetchSchemaDocuments(t,e){const n=`btp-copilot-meta-${t}`;if(c._cache.has(n))return c._cache.get(n);const i=sessionStorage.getItem(n);if(i)try{const r=JSON.parse(i);return c._cache.set(n,r),r}catch{}try{const r=`${t}/$metadata`,o={Accept:"application/xml"};e&&(o.Authorization=`Bearer ${e}`);const a=await fetch(r,{headers:o});if(!a.ok)return[];const s=await a.text(),l=c._parseEDMX(s),p=c._schemasToDocuments(l,t);return c._cache.set(n,p),sessionStorage.setItem(n,JSON.stringify(p)),p}catch{return[]}}static _parseEDMX(t){try{const i=new DOMParser().parseFromString(t,"text/xml").querySelectorAll("EntityType");return Array.from(i).map(r=>{const o=r.getAttribute("Name")??"",a=r.querySelectorAll("Key > PropertyRef"),s=new Set(Array.from(a).map(h=>h.getAttribute("Name")??"")),l=Array.from(r.querySelectorAll("Property")).map(h=>({name:h.getAttribute("Name")??"",type:c._shortType(h.getAttribute("Type")??""),isKey:s.has(h.getAttribute("Name")??""),nullable:h.getAttribute("Nullable")!=="false"})),p=Array.from(r.querySelectorAll("NavigationProperty")).map(h=>({name:h.getAttribute("Name")??"",type:c._shortType(h.getAttribute("Type")??h.getAttribute("ToRole")??"")}));return{name:o,properties:l,navProperties:p}})}catch{return[]}}static _shortType(t){return t.startsWith("Collection(")?`${t.slice(11,-1).split(".").pop()}[]`:t.split(".").pop()??t}static _schemasToDocuments(t,e){const n=[];for(const i of t){if(!i.name)continue;const r=i.properties.filter(s=>s.isKey),o=i.properties.filter(s=>!s.isKey),a=[`Entity: ${i.name}`,`OData service: ${e}`,`Entity set path: ${e}/${i.name}`,`Count path: ${e}/${i.name}/$count`];r.length&&a.push(`Key fields: ${r.map(s=>`${s.name} (${s.type})`).join(", ")}`),o.length&&a.push(`Fields: ${o.map(s=>`${s.name} (${s.type}${s.nullable?"":", required"})`).join(", ")}`),i.navProperties.length&&a.push(`Navigation: ${i.navProperties.map(s=>`${s.name} → ${s.type}`).join(", ")}`),n.push({title:`${i.name} entity schema`,content:a.join(`
|
|
2
|
+
`)})}return t.length>0&&n.push({title:"Available OData entity sets",content:[`OData service: ${e}`,`Entities: ${t.map(i=>i.name).join(", ")}`,"GET {entity}/$count | ?$filter=field eq 'value' | ?$top=10&$skip=0 | ?$orderby=field desc"].join(`
|
|
3
|
+
`)}),n}static invalidate(t){const e=`btp-copilot-meta-${t}`;c._cache.delete(e),sessionStorage.removeItem(e)}};c._cache=new Map;let _=c;class f{static capture(t){const e={...t};try{const n=b.getHash();n&&(e.current_view=n)}catch{}try{const n=u.getCurrentEntity();n&&Object.keys(n).length>0&&(e.entity_data=n)}catch{}try{e.user_locale||(e.user_locale=b.getUserLocale())}catch{}try{const n=window.__APP_CONTEXT__;n&&(n.entity_data&&(e.entity_data={...n.entity_data,...e.entity_data}),n.current_view&&!e.current_view&&(e.current_view=n.current_view),n.extra&&(e.extra={...n.extra,...e.extra??{}}),n.service_url&&!e.service_url&&(e.service_url=n.service_url))}catch{}return e}static async captureAsync(t){var n;const e=f.capture(t);if(e.service_url||(e.service_url=f._discoverServiceUrl()??void 0),e.service_url)try{const i=((n=e.extra)==null?void 0:n.auth_token)??null,r=await _.fetchSchemaDocuments(e.service_url,i);if(r.length>0){const o=r.map(a=>`## ${a.title}
|
|
4
|
+
${a.content}`).join(`
|
|
5
|
+
|
|
6
|
+
`);e.extra={...e.extra??{},schema_hint:o}}}catch{}return e}static _discoverServiceUrl(){try{const t=u.getServiceUrl();if(t)return t}catch{}try{const t=performance.getEntriesByType("resource");for(const e of t){const n=e.name.match(/^(https?:\/\/[^?#]+)\/\$metadata/);if(n)return n[1]}}catch{}try{const t=window.location.href.match(/(https?:\/\/[^/]+(?:\/odata\/v[24]\/[^/?#]+|\/sap\/opu\/odata\/[^/?#]+))/);if(t)return t[1]}catch{}return null}static async discoverFromManifest(){var t;try{const e=await fetch("/manifest.json");if(!e.ok)return null;const n=await e.json(),i=((t=n==null?void 0:n["sap.app"])==null?void 0:t.dataSources)??{};for(const r of Object.keys(i)){const o=i[r];if((o==null?void 0:o.type)==="ODataAnnotation")continue;const a=o==null?void 0:o.uri;if(typeof a=="string"&&a.length>0)return new URL(a,window.location.href).toString().replace(/\/$/,"")}}catch{}return null}static listenForUpdates(t,e,n,i){const r=o=>{if(!o.data||typeof o.data!="object")return;const{type:a,payload:s,text:l}=o.data;switch(a){case"btp-copilot:set-context":s&&t(s);break;case"btp-copilot:send-message":l&&e(l);break;case"btp-copilot:open":n();break;case"btp-copilot:close":i();break}};return window.addEventListener("message",r),()=>window.removeEventListener("message",r)}}const x=`/* ── Host element ─────────────────────────────────────────────────────────── */
|
|
7
|
+
:host {
|
|
8
|
+
position: fixed;
|
|
9
|
+
z-index: 2147483647;
|
|
10
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
14
|
+
|
|
15
|
+
/* ── Toggle (FAB) button ─────────────────────────────────────────────────── */
|
|
16
|
+
.toggle-btn {
|
|
17
|
+
position: fixed;
|
|
18
|
+
bottom: 1.25rem;
|
|
19
|
+
width: 3.25rem;
|
|
20
|
+
height: 3.25rem;
|
|
21
|
+
border-radius: 50%;
|
|
22
|
+
border: none;
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
28
|
+
color: #fff;
|
|
29
|
+
box-shadow: 0 4px 14px rgba(102, 126, 234, 0.45);
|
|
30
|
+
z-index: 2147483647;
|
|
31
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
32
|
+
outline: none;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.toggle-btn.bottom-right { right: 1.25rem; }
|
|
36
|
+
.toggle-btn.bottom-left { left: 1.25rem; }
|
|
37
|
+
|
|
38
|
+
.toggle-btn:hover {
|
|
39
|
+
transform: scale(1.08);
|
|
40
|
+
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.55);
|
|
41
|
+
}
|
|
42
|
+
.toggle-btn:active { transform: scale(0.95); }
|
|
43
|
+
.toggle-btn:focus-visible { outline: 3px solid #60a5fa; outline-offset: 2px; }
|
|
44
|
+
|
|
45
|
+
.toggle-btn[aria-expanded="false"] .icon-close { display: none; }
|
|
46
|
+
.toggle-btn[aria-expanded="true"] .icon-chat { display: none; }
|
|
47
|
+
.toggle-btn svg { width: 1.375rem; height: 1.375rem; pointer-events: none; }
|
|
48
|
+
|
|
49
|
+
/* Unread-message badge */
|
|
50
|
+
.badge {
|
|
51
|
+
position: absolute;
|
|
52
|
+
top: 0.125rem;
|
|
53
|
+
right: 0.125rem;
|
|
54
|
+
width: 0.625rem;
|
|
55
|
+
height: 0.625rem;
|
|
56
|
+
border-radius: 50%;
|
|
57
|
+
background: #ef4444;
|
|
58
|
+
border: 2px solid #fff;
|
|
59
|
+
opacity: 0;
|
|
60
|
+
transform: scale(0);
|
|
61
|
+
transition: opacity 0.2s ease, transform 0.2s ease;
|
|
62
|
+
}
|
|
63
|
+
.badge.visible { opacity: 1; transform: scale(1); }
|
|
64
|
+
|
|
65
|
+
/* ── Chat panel ──────────────────────────────────────────────────────────── */
|
|
66
|
+
.panel {
|
|
67
|
+
position: fixed;
|
|
68
|
+
bottom: 5.5rem;
|
|
69
|
+
width: 26rem;
|
|
70
|
+
height: 70vh;
|
|
71
|
+
min-height: 25rem;
|
|
72
|
+
max-height: 47.5rem;
|
|
73
|
+
background: transparent;
|
|
74
|
+
border-radius: 1rem;
|
|
75
|
+
box-shadow: 0 8px 40px rgba(0, 0, 0, 0.22), 0 0 0 1px rgba(0, 0, 0, 0.06);
|
|
76
|
+
z-index: 2147483646;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
display: flex;
|
|
79
|
+
flex-direction: column;
|
|
80
|
+
transform-origin: bottom center;
|
|
81
|
+
transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.34, 1.3, 0.64, 1),
|
|
82
|
+
width 0.3s cubic-bezier(0.4, 0, 0.2, 1), height 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
|
83
|
+
bottom 0.3s cubic-bezier(0.4, 0, 0.2, 1), border-radius 0.3s ease;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.panel.bottom-right { right: 1.25rem; }
|
|
87
|
+
.panel.bottom-left { left: 1.25rem; }
|
|
88
|
+
|
|
89
|
+
.panel.closed {
|
|
90
|
+
opacity: 0;
|
|
91
|
+
pointer-events: none;
|
|
92
|
+
transform: translateY(0.5rem) scale(0.97);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Fullscreen mode */
|
|
96
|
+
.panel.fullscreen {
|
|
97
|
+
width: 100vw !important;
|
|
98
|
+
height: 100vh !important;
|
|
99
|
+
height: 100dvh !important;
|
|
100
|
+
bottom: 0 !important;
|
|
101
|
+
right: 0 !important;
|
|
102
|
+
left: 0 !important;
|
|
103
|
+
border-radius: 0 !important;
|
|
104
|
+
max-height: none !important;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.panel.fullscreen .chat-iframe {
|
|
108
|
+
border-radius: 0 !important;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* Iframe fills the entire panel */
|
|
112
|
+
.chat-iframe {
|
|
113
|
+
width: 100%;
|
|
114
|
+
height: 100%;
|
|
115
|
+
border: none;
|
|
116
|
+
border-radius: 1rem;
|
|
117
|
+
display: block;
|
|
118
|
+
background: #fff;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* ── Mobile: full-screen ─────────────────────────────────────────────────── */
|
|
122
|
+
@media (max-width: 30rem) {
|
|
123
|
+
.panel {
|
|
124
|
+
width: 100vw;
|
|
125
|
+
height: 85dvh;
|
|
126
|
+
bottom: 0;
|
|
127
|
+
right: 0 !important;
|
|
128
|
+
left: 0 !important;
|
|
129
|
+
border-radius: 1rem 1rem 0 0;
|
|
130
|
+
}
|
|
131
|
+
.chat-iframe { border-radius: 1rem 1rem 0 0; }
|
|
132
|
+
}
|
|
133
|
+
`,w=["iframe-url","app-id","app-name","service-url","auto-context","position","theme","token","context-interval"],v=class v extends HTMLElement{constructor(){super(...arguments),this._open=!1,this._isFullscreen=!1,this._iframeEl=null,this._contextTimer=null}connectedCallback(){this._config=this._readConfig(),this._buildShadow(),this._startContextPolling();const t=e=>{if(!e.data||typeof e.data!="object")return;const{type:n}=e.data;n==="btp-copilot:close"&&this.close(),n==="btp-copilot:open"&&this.open(),n==="btp-copilot:fullscreen"&&this._toggleFullscreen(),n==="btp-copilot:minimize"&&this.close()};window.addEventListener("message",t),this._removeMessageListener=()=>window.removeEventListener("message",t)}disconnectedCallback(){var t;(t=this._removeMessageListener)==null||t.call(this),this._stopContextPolling()}attributeChangedCallback(t,e,n){e===n||!this.isConnected||(this._config=this._readConfig(),this._updateAfterAttributeChange())}open(){this._open=!0,this.shadowRoot.querySelector(".panel").classList.remove("closed"),this.shadowRoot.querySelector(".toggle-btn").setAttribute("aria-expanded","true"),this._clearBadge(),this._pushContextToIframe()}close(){this._open=!1;const t=this.shadowRoot.querySelector(".panel");t.classList.add("closed"),t.classList.remove("fullscreen"),this._isFullscreen=!1,this.shadowRoot.querySelector(".toggle-btn").setAttribute("aria-expanded","false")}_toggleFullscreen(){this._isFullscreen=!this._isFullscreen;const t=this.shadowRoot.querySelector(".panel"),e=this.shadowRoot.querySelector(".toggle-btn");this._isFullscreen?(t.classList.add("fullscreen"),e.style.display="none"):(t.classList.remove("fullscreen"),e.style.display="")}sendMessage(t){this._open||this.open(),setTimeout(()=>{var e,n;(n=(e=this._iframeEl)==null?void 0:e.contentWindow)==null||n.postMessage({type:"btp-copilot:send-message",text:t},"*")},100)}_buildShadow(){var i;const t=this.attachShadow({mode:"open"}),e=document.createElement("style");e.textContent=x,t.appendChild(e);const n=document.createElement("div");for(n.innerHTML=this._template();n.firstChild;)t.appendChild(n.firstChild);t.querySelector(".toggle-btn").addEventListener("click",()=>{this._open?this.close():this.open()}),this._iframeEl=t.querySelector(".chat-iframe"),(i=this._iframeEl)==null||i.addEventListener("load",()=>{this._pushAuthToIframe(),this._pushContextToIframe()})}_template(){var n;const t=((n=this._config)==null?void 0:n.position)??"bottom-right",e=this._esc(this._buildIframeUrl());return`
|
|
134
|
+
<button class="toggle-btn ${t}" aria-label="Open AI assistant" aria-expanded="false" aria-haspopup="dialog">
|
|
135
|
+
<svg class="icon-chat" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
136
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
|
|
137
|
+
</svg>
|
|
138
|
+
<svg class="icon-close" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
|
|
139
|
+
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
|
|
140
|
+
</svg>
|
|
141
|
+
<span class="badge" aria-hidden="true"></span>
|
|
142
|
+
</button>
|
|
143
|
+
|
|
144
|
+
<div class="panel closed ${t}" role="dialog" aria-label="AI Assistant" aria-modal="true">
|
|
145
|
+
<iframe
|
|
146
|
+
class="chat-iframe"
|
|
147
|
+
src="${e}"
|
|
148
|
+
title="AI Assistant"
|
|
149
|
+
allow="clipboard-read; clipboard-write"
|
|
150
|
+
loading="lazy">
|
|
151
|
+
</iframe>
|
|
152
|
+
</div>`}_buildBaseContext(){const t=d.resolve(this._config.token);return{app_id:this._config.appId,app_name:this._config.appName,service_url:this._config.serviceUrl,...t?{extra:{auth_token:t}}:{}}}_buildIframeUrl(){var e;const t=((e=this._config)==null?void 0:e.iframeUrl)??"";if(!t)return"";try{const n=new URL(t),{appId:i,appName:r,serviceUrl:o}=this._config;i&&n.searchParams.set("appId",i),r&&n.searchParams.set("appName",r),o&&n.searchParams.set("serviceUrl",o);const a=d.resolve(this._config.token);return a&&n.searchParams.set("token",a),n.toString()}catch{return t}}_iframeOrigin(){try{return new URL(this._config.iframeUrl).origin}catch{return"*"}}_pushContextToIframe(){var e;if(!((e=this._iframeEl)!=null&&e.contentWindow))return;const t=this._iframeOrigin();this._config.autoContext?f.captureAsync(this._buildBaseContext()).then(n=>{var i,r;(r=(i=this._iframeEl)==null?void 0:i.contentWindow)==null||r.postMessage({type:"btp-copilot:set-context",payload:n},t),n.service_url&&!this._config.serviceUrl&&(this._config={...this._config,serviceUrl:n.service_url})}).catch(()=>{var n,i;(i=(n=this._iframeEl)==null?void 0:n.contentWindow)==null||i.postMessage({type:"btp-copilot:set-context",payload:this._buildBaseContext()},t)}):this._iframeEl.contentWindow.postMessage({type:"btp-copilot:set-context",payload:this._buildBaseContext()},t)}_pushAuthToIframe(){var e;const t=d.resolve(this._config.token);!t||!((e=this._iframeEl)!=null&&e.contentWindow)||this._iframeEl.contentWindow.postMessage({type:"btp-copilot:auth",token:t},this._iframeOrigin())}_startContextPolling(){this._config.autoContext&&(this._contextTimer=setInterval(()=>{this._open&&this._pushContextToIframe()},this._config.contextInterval))}_stopContextPolling(){this._contextTimer!==null&&(clearInterval(this._contextTimer),this._contextTimer=null)}_readConfig(){const t=e=>this.getAttribute(e);return{iframeUrl:t("iframe-url")??"",appId:t("app-id")??"default",appName:t("app-name")??void 0,serviceUrl:t("service-url")??void 0,autoContext:t("auto-context")!=="false",position:t("position")??"bottom-right",theme:t("theme")??"auto",token:t("token")??void 0,contextInterval:Math.max(500,Number(t("context-interval"))||3e3)}}_updateAfterAttributeChange(){var n;const t=(n=this.shadowRoot)==null?void 0:n.querySelector("style");t&&(t.textContent=x);const e=this._buildIframeUrl();this._iframeEl&&this._iframeEl.src!==e&&e&&(this._iframeEl.src=e),this._stopContextPolling(),this._startContextPolling()}_clearBadge(){var t,e;(e=(t=this.shadowRoot)==null?void 0:t.querySelector(".badge"))==null||e.classList.remove("visible")}_esc(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}};v.observedAttributes=[...w];let y=v;return customElements.get("btp-copilot")||customElements.define("btp-copilot",y),g.BtpCopilotElement=y,g.ContextBridge=f,Object.defineProperty(g,Symbol.toStringTag,{value:"Module"}),g}({});
|
|
153
|
+
//# sourceMappingURL=btp-copilot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"btp-copilot.js","sources":["../src/api/TokenManager.ts","../src/context/ShellProbe.ts","../src/context/UI5Probe.ts","../src/context/ODataProbe.ts","../src/context/ContextBridge.ts","../src/styles/widget.css?raw","../src/BtpCopilotElement.ts","../src/index.ts"],"sourcesContent":["export class TokenManager {\n private static readonly XSUAA_COOKIE_NAMES = [\n \"x-uaa-token\",\n \"xsuaa_token\",\n \"access_token\",\n \"X-Authorization\",\n ];\n\n static resolve(explicitToken?: string | null): string | null {\n if (explicitToken) return explicitToken.replace(/^Bearer\\s+/i, \"\");\n\n const windowToken = (window as any).__BTP_COPILOT_TOKEN__ as\n | string\n | undefined;\n if (windowToken) return windowToken.replace(/^Bearer\\s+/i, \"\");\n\n const cookieToken = TokenManager._fromCookie();\n if (cookieToken) return cookieToken;\n\n try {\n const lsToken = localStorage.getItem(\"access_token\");\n if (lsToken) return lsToken;\n } catch {}\n\n return null;\n }\n\n static getAuthHeader(token: string | null): Record<string, string> {\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n\n private static _fromCookie(): string | null {\n try {\n const cookies = document.cookie.split(\";\");\n for (const cookie of cookies) {\n const [name, ...rest] = cookie.trim().split(\"=\");\n if (TokenManager.XSUAA_COOKIE_NAMES.includes(name.trim())) {\n return decodeURIComponent(rest.join(\"=\").trim());\n }\n }\n } catch {}\n return null;\n }\n}\n","declare const sap: any;\n\nexport class ShellProbe {\n static getHash(): string {\n try {\n const nav = sap?.ushell?.Container?.getService?.(\n \"CrossApplicationNavigation\",\n );\n if (nav) {\n const href = nav.hrefForExternal?.() as string | undefined;\n if (href) return href;\n }\n } catch (err) {\n console.log(err);\n }\n return window.location.hash || \"\";\n }\n\n static getCurrentAppId(): string | null {\n try {\n const hash = ShellProbe.getHash();\n const match = hash.match(/^#([^&?/]+)/);\n return match ? match[1] : null;\n } catch {\n return null;\n }\n }\n\n static getUserLocale(): string {\n try {\n return (\n sap?.ui?.getCore?.()?.getConfiguration?.()?.getLanguageTag?.() ??\n navigator.language ??\n \"en\"\n );\n } catch {\n return navigator.language ?? \"en\";\n }\n }\n}\n","declare const sap: any;\n\nexport class UI5Probe {\n static getCurrentEntity(): Record<string, unknown> | null {\n try {\n const core = sap?.ui?.getCore?.();\n if (!core) return null;\n\n let el: Element | null = document.activeElement;\n while (el) {\n const id = el.getAttribute(\"id\") || el.getAttribute(\"data-sap-ui\");\n if (id) {\n const control = core.byId(id);\n const ctx = control?.getBindingContext?.();\n if (ctx) {\n const obj = ctx.getObject?.();\n if (obj && typeof obj === \"object\") {\n return UI5Probe._sanitize(obj as Record<string, unknown>);\n }\n }\n }\n el = el.parentElement;\n }\n return UI5Probe._scanAllControls(core);\n } catch {\n return null;\n }\n }\n\n private static _scanAllControls(core: any): Record<string, unknown> | null {\n try {\n const elements = core.mElements ?? {};\n for (const id of Object.keys(elements)) {\n const control = elements[id];\n const ctx = control?.getBindingContext?.();\n if (ctx) {\n const obj = ctx.getObject?.();\n if (obj && typeof obj === \"object\" && Object.keys(obj).length > 0) {\n return UI5Probe._sanitize(obj as Record<string, unknown>);\n }\n }\n }\n } catch {}\n return null;\n }\n\n static getServiceUrl(): string | null {\n try {\n const core = sap?.ui?.getCore?.();\n if (!core) return null;\n const elements = core.mElements ?? {};\n for (const id of Object.keys(elements)) {\n const control = elements[id];\n if (!control?.getModel) continue;\n const model = control.getModel();\n if (!model) continue;\n const url: unknown = model.sServiceUrl ?? (model as any)._sServiceUrl;\n if (typeof url === \"string\" && url.length > 4) {\n return url.replace(/\\/$/, \"\");\n }\n }\n } catch {}\n return null;\n }\n\n private static _sanitize(\n obj: Record<string, unknown>,\n ): Record<string, unknown> {\n const clean: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(obj)) {\n if (k.startsWith(\"__\")) continue;\n if (v === null || typeof v !== \"object\") {\n clean[k] = v;\n } else if ((v as any).__deferred) {\n // navigation property stub — skip\n } else {\n clean[k] = v;\n }\n }\n return clean;\n }\n}\n","import type {\n EntitySchema,\n EntityProperty,\n NavProperty,\n AppDocument,\n} from \"../types\";\n\nexport class ODataProbe {\n private static _cache = new Map<string, AppDocument[]>();\n\n static async fetchSchemaDocuments(\n serviceUrl: string,\n token?: string | null,\n ): Promise<AppDocument[]> {\n const cacheKey = `btp-copilot-meta-${serviceUrl}`;\n\n if (ODataProbe._cache.has(cacheKey)) {\n return ODataProbe._cache.get(cacheKey)!;\n }\n\n const stored = sessionStorage.getItem(cacheKey);\n if (stored) {\n try {\n const docs = JSON.parse(stored) as AppDocument[];\n ODataProbe._cache.set(cacheKey, docs);\n return docs;\n } catch {}\n }\n\n try {\n const metaUrl = `${serviceUrl}/$metadata`;\n const headers: Record<string, string> = { Accept: \"application/xml\" };\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n\n const resp = await fetch(metaUrl, { headers });\n if (!resp.ok) return [];\n\n const xml = await resp.text();\n const schemas = ODataProbe._parseEDMX(xml);\n const docs = ODataProbe._schemasToDocuments(schemas, serviceUrl);\n\n ODataProbe._cache.set(cacheKey, docs);\n sessionStorage.setItem(cacheKey, JSON.stringify(docs));\n return docs;\n } catch {\n return [];\n }\n }\n\n private static _parseEDMX(xml: string): EntitySchema[] {\n try {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml, \"text/xml\");\n const entityTypes = doc.querySelectorAll(\"EntityType\");\n return Array.from(entityTypes).map((et) => {\n const name = et.getAttribute(\"Name\") ?? \"\";\n const keyRefs = et.querySelectorAll(\"Key > PropertyRef\");\n const keyNames = new Set(\n Array.from(keyRefs).map((k) => k.getAttribute(\"Name\") ?? \"\"),\n );\n const properties: EntityProperty[] = Array.from(\n et.querySelectorAll(\"Property\"),\n ).map((p) => ({\n name: p.getAttribute(\"Name\") ?? \"\",\n type: ODataProbe._shortType(p.getAttribute(\"Type\") ?? \"\"),\n isKey: keyNames.has(p.getAttribute(\"Name\") ?? \"\"),\n nullable: p.getAttribute(\"Nullable\") !== \"false\",\n }));\n const navProperties: NavProperty[] = Array.from(\n et.querySelectorAll(\"NavigationProperty\"),\n ).map((n) => ({\n name: n.getAttribute(\"Name\") ?? \"\",\n type: ODataProbe._shortType(\n n.getAttribute(\"Type\") ?? n.getAttribute(\"ToRole\") ?? \"\",\n ),\n }));\n return { name, properties, navProperties };\n });\n } catch {\n return [];\n }\n }\n\n private static _shortType(full: string): string {\n if (full.startsWith(\"Collection(\")) {\n const inner = full.slice(11, -1);\n return `${inner.split(\".\").pop()}[]`;\n }\n return full.split(\".\").pop() ?? full;\n }\n\n private static _schemasToDocuments(\n schemas: EntitySchema[],\n serviceUrl: string,\n ): AppDocument[] {\n const docs: AppDocument[] = [];\n\n for (const schema of schemas) {\n if (!schema.name) continue;\n const keyProps = schema.properties.filter((p) => p.isKey);\n const otherProps = schema.properties.filter((p) => !p.isKey);\n const lines = [\n `Entity: ${schema.name}`,\n `OData service: ${serviceUrl}`,\n `Entity set path: ${serviceUrl}/${schema.name}`,\n `Count path: ${serviceUrl}/${schema.name}/$count`,\n ];\n if (keyProps.length) {\n lines.push(\n `Key fields: ${keyProps.map((p) => `${p.name} (${p.type})`).join(\", \")}`,\n );\n }\n if (otherProps.length) {\n lines.push(\n `Fields: ${otherProps\n .map(\n (p) => `${p.name} (${p.type}${p.nullable ? \"\" : \", required\"})`,\n )\n .join(\", \")}`,\n );\n }\n if (schema.navProperties.length) {\n lines.push(\n `Navigation: ${schema.navProperties.map((n) => `${n.name} → ${n.type}`).join(\", \")}`,\n );\n }\n docs.push({\n title: `${schema.name} entity schema`,\n content: lines.join(\"\\n\"),\n });\n }\n\n if (schemas.length > 0) {\n docs.push({\n title: \"Available OData entity sets\",\n content: [\n `OData service: ${serviceUrl}`,\n `Entities: ${schemas.map((s) => s.name).join(\", \")}`,\n \"GET {entity}/$count | ?$filter=field eq 'value' | ?$top=10&$skip=0 | ?$orderby=field desc\",\n ].join(\"\\n\"),\n });\n }\n\n return docs;\n }\n\n static invalidate(serviceUrl: string) {\n const key = `btp-copilot-meta-${serviceUrl}`;\n ODataProbe._cache.delete(key);\n sessionStorage.removeItem(key);\n }\n}\n","import type { HostAppContext } from \"../types\";\nimport { ShellProbe } from \"./ShellProbe\";\nimport { UI5Probe } from \"./UI5Probe\";\nimport { ODataProbe } from \"./ODataProbe\";\n\nexport class ContextBridge {\n static capture(baseContext: HostAppContext): HostAppContext {\n const ctx: HostAppContext = { ...baseContext };\n\n try {\n const hash = ShellProbe.getHash();\n if (hash) ctx.current_view = hash;\n } catch {}\n\n try {\n const entity = UI5Probe.getCurrentEntity();\n if (entity && Object.keys(entity).length > 0) ctx.entity_data = entity;\n } catch {}\n\n try {\n if (!ctx.user_locale) ctx.user_locale = ShellProbe.getUserLocale();\n } catch {}\n\n // Merge any context injected by the host app\n try {\n const injected = (window as any).__APP_CONTEXT__ as\n | Partial<HostAppContext>\n | undefined;\n if (injected) {\n if (injected.entity_data)\n ctx.entity_data = { ...injected.entity_data, ...ctx.entity_data };\n if (injected.current_view && !ctx.current_view)\n ctx.current_view = injected.current_view;\n if (injected.extra)\n ctx.extra = { ...injected.extra, ...(ctx.extra ?? {}) };\n if (injected.service_url && !ctx.service_url)\n ctx.service_url = injected.service_url;\n }\n } catch {}\n\n return ctx;\n }\n\n static async captureAsync(\n baseContext: HostAppContext,\n ): Promise<HostAppContext> {\n const ctx = ContextBridge.capture(baseContext);\n\n if (!ctx.service_url) {\n ctx.service_url = ContextBridge._discoverServiceUrl() ?? undefined;\n }\n\n if (ctx.service_url) {\n try {\n const token = (ctx.extra as any)?.auth_token ?? null;\n const docs = await ODataProbe.fetchSchemaDocuments(\n ctx.service_url,\n token,\n );\n if (docs.length > 0) {\n const schemaHint = docs\n .map((d) => `## ${d.title}\\n${d.content}`)\n .join(\"\\n\\n\");\n ctx.extra = { ...(ctx.extra ?? {}), schema_hint: schemaHint };\n }\n } catch {}\n }\n\n return ctx;\n }\n\n private static _discoverServiceUrl(): string | null {\n try {\n const url = UI5Probe.getServiceUrl();\n if (url) return url;\n } catch {}\n\n try {\n const entries = performance.getEntriesByType(\n \"resource\",\n ) as PerformanceResourceTiming[];\n for (const e of entries) {\n const m = e.name.match(/^(https?:\\/\\/[^?#]+)\\/\\$metadata/);\n if (m) return m[1];\n }\n } catch {}\n\n try {\n const m = window.location.href.match(\n /(https?:\\/\\/[^/]+(?:\\/odata\\/v[24]\\/[^/?#]+|\\/sap\\/opu\\/odata\\/[^/?#]+))/,\n );\n if (m) return m[1];\n } catch {}\n\n return null;\n }\n\n static async discoverFromManifest(): Promise<string | null> {\n try {\n const resp = await fetch(\"/manifest.json\");\n if (!resp.ok) return null;\n const manifest = await resp.json();\n const sources: Record<string, any> =\n manifest?.[\"sap.app\"]?.dataSources ?? {};\n for (const key of Object.keys(sources)) {\n const src = sources[key];\n if (src?.type === \"ODataAnnotation\") continue;\n const uri: unknown = src?.uri;\n if (typeof uri === \"string\" && uri.length > 0) {\n return new URL(uri, window.location.href)\n .toString()\n .replace(/\\/$/, \"\");\n }\n }\n } catch {}\n return null;\n }\n\n static listenForUpdates(\n onContextUpdate: (ctx: Partial<HostAppContext>) => void,\n onMessage: (text: string) => void,\n onOpen: () => void,\n onClose: () => void,\n ): () => void {\n const handler = (event: MessageEvent) => {\n if (!event.data || typeof event.data !== \"object\") return;\n const { type, payload, text } = event.data as {\n type?: string;\n payload?: Partial<HostAppContext>;\n text?: string;\n };\n switch (type) {\n case \"btp-copilot:set-context\":\n if (payload) onContextUpdate(payload);\n break;\n case \"btp-copilot:send-message\":\n if (text) onMessage(text);\n break;\n case \"btp-copilot:open\":\n onOpen();\n break;\n case \"btp-copilot:close\":\n onClose();\n break;\n }\n };\n window.addEventListener(\"message\", handler);\n return () => window.removeEventListener(\"message\", handler);\n }\n}\n","export default \"/* ── Host element ─────────────────────────────────────────────────────────── */\\n:host {\\n position: fixed;\\n z-index: 2147483647;\\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\\n}\\n\\n*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\\n\\n/* ── Toggle (FAB) button ─────────────────────────────────────────────────── */\\n.toggle-btn {\\n position: fixed;\\n bottom: 1.25rem;\\n width: 3.25rem;\\n height: 3.25rem;\\n border-radius: 50%;\\n border: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\\n color: #fff;\\n box-shadow: 0 4px 14px rgba(102, 126, 234, 0.45);\\n z-index: 2147483647;\\n transition: transform 0.2s ease, box-shadow 0.2s ease;\\n outline: none;\\n}\\n\\n.toggle-btn.bottom-right { right: 1.25rem; }\\n.toggle-btn.bottom-left { left: 1.25rem; }\\n\\n.toggle-btn:hover {\\n transform: scale(1.08);\\n box-shadow: 0 6px 20px rgba(102, 126, 234, 0.55);\\n}\\n.toggle-btn:active { transform: scale(0.95); }\\n.toggle-btn:focus-visible { outline: 3px solid #60a5fa; outline-offset: 2px; }\\n\\n.toggle-btn[aria-expanded=\\\"false\\\"] .icon-close { display: none; }\\n.toggle-btn[aria-expanded=\\\"true\\\"] .icon-chat { display: none; }\\n.toggle-btn svg { width: 1.375rem; height: 1.375rem; pointer-events: none; }\\n\\n/* Unread-message badge */\\n.badge {\\n position: absolute;\\n top: 0.125rem;\\n right: 0.125rem;\\n width: 0.625rem;\\n height: 0.625rem;\\n border-radius: 50%;\\n background: #ef4444;\\n border: 2px solid #fff;\\n opacity: 0;\\n transform: scale(0);\\n transition: opacity 0.2s ease, transform 0.2s ease;\\n}\\n.badge.visible { opacity: 1; transform: scale(1); }\\n\\n/* ── Chat panel ──────────────────────────────────────────────────────────── */\\n.panel {\\n position: fixed;\\n bottom: 5.5rem;\\n width: 26rem;\\n height: 70vh;\\n min-height: 25rem;\\n max-height: 47.5rem;\\n background: transparent;\\n border-radius: 1rem;\\n box-shadow: 0 8px 40px rgba(0, 0, 0, 0.22), 0 0 0 1px rgba(0, 0, 0, 0.06);\\n z-index: 2147483646;\\n overflow: hidden;\\n display: flex;\\n flex-direction: column;\\n transform-origin: bottom center;\\n transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.34, 1.3, 0.64, 1),\\n width 0.3s cubic-bezier(0.4, 0, 0.2, 1), height 0.3s cubic-bezier(0.4, 0, 0.2, 1),\\n bottom 0.3s cubic-bezier(0.4, 0, 0.2, 1), border-radius 0.3s ease;\\n}\\n\\n.panel.bottom-right { right: 1.25rem; }\\n.panel.bottom-left { left: 1.25rem; }\\n\\n.panel.closed {\\n opacity: 0;\\n pointer-events: none;\\n transform: translateY(0.5rem) scale(0.97);\\n}\\n\\n/* Fullscreen mode */\\n.panel.fullscreen {\\n width: 100vw !important;\\n height: 100vh !important;\\n height: 100dvh !important;\\n bottom: 0 !important;\\n right: 0 !important;\\n left: 0 !important;\\n border-radius: 0 !important;\\n max-height: none !important;\\n}\\n\\n.panel.fullscreen .chat-iframe {\\n border-radius: 0 !important;\\n}\\n\\n/* Iframe fills the entire panel */\\n.chat-iframe {\\n width: 100%;\\n height: 100%;\\n border: none;\\n border-radius: 1rem;\\n display: block;\\n background: #fff;\\n}\\n\\n/* ── Mobile: full-screen ─────────────────────────────────────────────────── */\\n@media (max-width: 30rem) {\\n .panel {\\n width: 100vw;\\n height: 85dvh;\\n bottom: 0;\\n right: 0 !important;\\n left: 0 !important;\\n border-radius: 1rem 1rem 0 0;\\n }\\n .chat-iframe { border-radius: 1rem 1rem 0 0; }\\n}\\n\"","/**\n * BtpCopilotElement — <btp-copilot> Custom Element.\n *\n * Renders a fixed floating FAB button. When opened, shows your deployed\n * BTP Copilot React chatbot in an iframe. Context from the host UI5/Fiori\n * app is auto-captured and forwarded into the iframe via postMessage so the\n * chatbot is always aware of what the user is looking at.\n *\n * Attributes:\n * iframe-url Full URL of the deployed React chatbot frontend (required)\n * app-id Stable identifier of the host application (required)\n * app-name Human-readable app name\n * service-url OData service URL for context auto-capture\n * auto-context \"true\"|\"false\" — auto-capture UI5/OData context (default: true)\n * position \"bottom-right\"|\"bottom-left\" (default: bottom-right)\n * theme \"auto\"|\"light\"|\"dark\" (default: auto)\n * token Bearer token forwarded to the chatbot iframe\n * context-interval Context re-capture interval in ms (default: 3000)\n *\n * postMessage protocol (outgoing → iframe):\n * { type: 'btp-copilot:set-context', payload: HostAppContext }\n * { type: 'btp-copilot:auth', token: string }\n *\n * postMessage protocol (incoming ← iframe or host page):\n * { type: 'btp-copilot:close' }\n * { type: 'btp-copilot:open' }\n */\n\nimport type { HostAppContext, WidgetConfig } from \"./types\";\nimport { TokenManager } from \"./api/TokenManager\";\nimport { ContextBridge } from \"./context/ContextBridge\";\nimport widgetCss from \"./styles/widget.css?raw\";\n\nconst OBSERVED = [\n \"iframe-url\",\n \"app-id\",\n \"app-name\",\n \"service-url\",\n \"auto-context\",\n \"position\",\n \"theme\",\n \"token\",\n \"context-interval\",\n] as const;\n\nexport class BtpCopilotElement extends HTMLElement {\n static observedAttributes = [...OBSERVED];\n\n private _config!: WidgetConfig;\n private _open = false;\n private _isFullscreen = false;\n private _iframeEl: HTMLIFrameElement | null = null;\n private _contextTimer: ReturnType<typeof setInterval> | null = null;\n private _removeMessageListener?: () => void;\n\n connectedCallback() {\n this._config = this._readConfig();\n this._buildShadow();\n this._startContextPolling();\n\n const msgHandler = (event: MessageEvent) => {\n if (!event.data || typeof event.data !== \"object\") return;\n const { type } = event.data as { type?: string };\n if (type === \"btp-copilot:close\") this.close();\n if (type === \"btp-copilot:open\") this.open();\n if (type === \"btp-copilot:fullscreen\") this._toggleFullscreen();\n if (type === \"btp-copilot:minimize\") this.close();\n };\n window.addEventListener(\"message\", msgHandler);\n this._removeMessageListener = () =>\n window.removeEventListener(\"message\", msgHandler);\n }\n\n disconnectedCallback() {\n this._removeMessageListener?.();\n this._stopContextPolling();\n }\n\n attributeChangedCallback(\n _name: string,\n old: string | null,\n next: string | null\n ) {\n if (old === next || !this.isConnected) return;\n this._config = this._readConfig();\n this._updateAfterAttributeChange();\n }\n\n // ── Public API ─────────────────────────────────────────────────────────────\n open() {\n this._open = true;\n this.shadowRoot!.querySelector(\".panel\")!.classList.remove(\"closed\");\n this.shadowRoot!\n .querySelector(\".toggle-btn\")!\n .setAttribute(\"aria-expanded\", \"true\");\n this._clearBadge();\n this._pushContextToIframe();\n }\n\n close() {\n this._open = false;\n const panel = this.shadowRoot!.querySelector(\".panel\")!;\n panel.classList.add(\"closed\");\n panel.classList.remove(\"fullscreen\");\n this._isFullscreen = false;\n this.shadowRoot!\n .querySelector(\".toggle-btn\")!\n .setAttribute(\"aria-expanded\", \"false\");\n }\n\n private _toggleFullscreen() {\n this._isFullscreen = !this._isFullscreen;\n const panel = this.shadowRoot!.querySelector(\".panel\")!;\n const fab = this.shadowRoot!.querySelector(\".toggle-btn\") as HTMLElement;\n if (this._isFullscreen) {\n panel.classList.add(\"fullscreen\");\n fab.style.display = \"none\";\n } else {\n panel.classList.remove(\"fullscreen\");\n fab.style.display = \"\";\n }\n }\n\n sendMessage(text: string) {\n if (!this._open) this.open();\n setTimeout(() => {\n this._iframeEl?.contentWindow?.postMessage(\n { type: \"btp-copilot:send-message\", text },\n \"*\"\n );\n }, 100);\n }\n\n // ── Shadow DOM ─────────────────────────────────────────────────────────────\n private _buildShadow() {\n const shadow = this.attachShadow({ mode: \"open\" });\n\n const styleEl = document.createElement(\"style\");\n styleEl.textContent = widgetCss;\n shadow.appendChild(styleEl);\n\n const wrapper = document.createElement(\"div\");\n wrapper.innerHTML = this._template();\n while (wrapper.firstChild) shadow.appendChild(wrapper.firstChild);\n\n shadow.querySelector(\".toggle-btn\")!.addEventListener(\"click\", () => {\n this._open ? this.close() : this.open();\n });\n\n this._iframeEl = shadow.querySelector(\".chat-iframe\");\n\n this._iframeEl?.addEventListener(\"load\", () => {\n this._pushAuthToIframe();\n this._pushContextToIframe();\n });\n }\n\n private _template(): string {\n const pos = this._config?.position ?? \"bottom-right\";\n const src = this._esc(this._buildIframeUrl());\n return `\n<button class=\"toggle-btn ${pos}\" aria-label=\"Open AI assistant\" aria-expanded=\"false\" aria-haspopup=\"dialog\">\n <svg class=\"icon-chat\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n <svg class=\"icon-close\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n <span class=\"badge\" aria-hidden=\"true\"></span>\n</button>\n\n<div class=\"panel closed ${pos}\" role=\"dialog\" aria-label=\"AI Assistant\" aria-modal=\"true\">\n <iframe\n class=\"chat-iframe\"\n src=\"${src}\"\n title=\"AI Assistant\"\n allow=\"clipboard-read; clipboard-write\"\n loading=\"lazy\">\n </iframe>\n</div>`;\n }\n\n // ── Context + Auth ─────────────────────────────────────────────────────────\n private _buildBaseContext(): HostAppContext {\n const token = TokenManager.resolve(this._config.token);\n return {\n app_id: this._config.appId,\n app_name: this._config.appName,\n service_url: this._config.serviceUrl,\n // Include the resolved auth token in extra so the backend can\n // proxy OData calls on behalf of the user to fetch real data\n ...(token ? { extra: { auth_token: token } } : {}),\n };\n }\n\n private _buildIframeUrl(): string {\n const base = this._config?.iframeUrl ?? \"\";\n if (!base) return \"\";\n try {\n const url = new URL(base);\n const { appId, appName, serviceUrl } = this._config;\n if (appId) url.searchParams.set(\"appId\", appId);\n if (appName) url.searchParams.set(\"appName\", appName);\n if (serviceUrl) url.searchParams.set(\"serviceUrl\", serviceUrl);\n // Pass token as URL param so the chatbot can auto-authenticate in iframe mode\n const token = TokenManager.resolve(this._config.token);\n if (token) url.searchParams.set(\"token\", token);\n return url.toString();\n } catch {\n return base;\n }\n }\n\n /** Derive the allowed postMessage target origin from the configured iframe URL.\n * Falls back to \"*\" only when the URL cannot be parsed (e.g. empty string). */\n private _iframeOrigin(): string {\n try {\n return new URL(this._config.iframeUrl).origin;\n } catch {\n return \"*\";\n }\n }\n\n private _pushContextToIframe() {\n if (!this._iframeEl?.contentWindow) return;\n const origin = this._iframeOrigin();\n\n if (this._config.autoContext) {\n ContextBridge.captureAsync(this._buildBaseContext())\n .then((ctx) => {\n this._iframeEl?.contentWindow?.postMessage(\n { type: \"btp-copilot:set-context\", payload: ctx },\n origin\n );\n if (ctx.service_url && !this._config.serviceUrl) {\n this._config = { ...this._config, serviceUrl: ctx.service_url };\n }\n })\n .catch(() => {\n this._iframeEl?.contentWindow?.postMessage(\n { type: \"btp-copilot:set-context\", payload: this._buildBaseContext() },\n origin\n );\n });\n } else {\n this._iframeEl.contentWindow.postMessage(\n { type: \"btp-copilot:set-context\", payload: this._buildBaseContext() },\n origin\n );\n }\n }\n\n private _pushAuthToIframe() {\n const token = TokenManager.resolve(this._config.token);\n if (!token || !this._iframeEl?.contentWindow) return;\n this._iframeEl.contentWindow.postMessage(\n { type: \"btp-copilot:auth\", token },\n this._iframeOrigin()\n );\n }\n\n private _startContextPolling() {\n if (!this._config.autoContext) return;\n this._contextTimer = setInterval(() => {\n if (this._open) this._pushContextToIframe();\n }, this._config.contextInterval);\n }\n\n private _stopContextPolling() {\n if (this._contextTimer !== null) {\n clearInterval(this._contextTimer);\n this._contextTimer = null;\n }\n }\n\n // ── Config ─────────────────────────────────────────────────────────────────\n private _readConfig(): WidgetConfig {\n const get = (attr: string) => this.getAttribute(attr);\n return {\n iframeUrl: get(\"iframe-url\") ?? \"\",\n appId: get(\"app-id\") ?? \"default\",\n appName: get(\"app-name\") ?? undefined,\n serviceUrl: get(\"service-url\") ?? undefined,\n autoContext: get(\"auto-context\") !== \"false\",\n position: (get(\"position\") ?? \"bottom-right\") as WidgetConfig[\"position\"],\n theme: (get(\"theme\") ?? \"auto\") as WidgetConfig[\"theme\"],\n token: get(\"token\") ?? undefined,\n contextInterval: Math.max(500, Number(get(\"context-interval\")) || 3000),\n };\n }\n\n private _updateAfterAttributeChange() {\n const style = this.shadowRoot?.querySelector(\"style\");\n if (style) style.textContent = widgetCss;\n\n const newSrc = this._buildIframeUrl();\n if (this._iframeEl && this._iframeEl.src !== newSrc && newSrc) {\n this._iframeEl.src = newSrc;\n }\n\n this._stopContextPolling();\n this._startContextPolling();\n }\n\n private _clearBadge() {\n this.shadowRoot?.querySelector(\".badge\")?.classList.remove(\"visible\");\n }\n\n private _esc(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n }\n}\n","import { BtpCopilotElement } from \"./BtpCopilotElement\";\n\nif (!customElements.get(\"btp-copilot\")) {\n customElements.define(\"btp-copilot\", BtpCopilotElement);\n}\n\nexport { BtpCopilotElement };\nexport type { HostAppContext, WidgetConfig, AppDocument } from \"./types\";\nexport { ContextBridge } from \"./context/ContextBridge\";\n"],"names":["_TokenManager","explicitToken","windowToken","cookieToken","lsToken","token","cookies","cookie","name","rest","TokenManager","ShellProbe","nav","_c","_b","_a","href","_d","err","match","_f","_e","UI5Probe","core","el","id","control","ctx","obj","elements","model","url","clean","k","v","_ODataProbe","serviceUrl","cacheKey","stored","docs","metaUrl","headers","resp","xml","schemas","entityTypes","et","keyRefs","keyNames","properties","p","navProperties","n","full","schema","keyProps","otherProps","lines","s","key","ODataProbe","ContextBridge","baseContext","hash","entity","injected","schemaHint","d","entries","m","manifest","sources","src","uri","onContextUpdate","onMessage","onOpen","onClose","handler","event","type","payload","text","widgetCss","OBSERVED","_BtpCopilotElement","msgHandler","_name","old","next","panel","fab","shadow","styleEl","wrapper","pos","base","appId","appName","origin","get","attr","style","newSrc","BtpCopilotElement"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cap-copilot-widget",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "BTP Copilot floating chat widget — Web Component (iframe launcher)",
|
|
5
|
+
"main": "dist/btp-copilot.js",
|
|
6
|
+
"module": "dist/btp-copilot.esm.js",
|
|
7
|
+
"types": "dist/btp-copilot.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/btp-copilot.esm.js",
|
|
11
|
+
"require": "./dist/btp-copilot.js",
|
|
12
|
+
"types": "./dist/btp-copilot.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist"],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"dev": "vite --port 5174 --open",
|
|
18
|
+
"build": "tsc --noEmit && vite build",
|
|
19
|
+
"prepare": "tsc --noEmit && vite build",
|
|
20
|
+
"preview": "vite preview",
|
|
21
|
+
"clean": "rm -rf dist"
|
|
22
|
+
},
|
|
23
|
+
"keywords": ["sap", "fiori", "ui5", "cap", "btp", "ai", "chatbot", "web-component"],
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"typescript": "^5.4.0",
|
|
27
|
+
"vite": "^5.2.0"
|
|
28
|
+
}
|
|
29
|
+
}
|