cap-copilot-widget 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"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 // ── SAP-specific probes (no-ops on non-SAP apps) ──────────────────────────\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 // ── Generic web context (works for any app) ───────────────────────────────\n // current_view: full path + search + hash (more useful than hash alone)\n try {\n const fullPath =\n window.location.pathname +\n window.location.search +\n window.location.hash;\n if (!ctx.current_view || ctx.current_view === \"\") {\n ctx.current_view = fullPath;\n }\n } catch {}\n\n // locale fallback\n try {\n if (!ctx.user_locale) {\n ctx.user_locale =\n navigator.language || (navigator as any).languages?.[0] || \"en\";\n }\n } catch {}\n\n // page_title and page_url give the LLM meaningful screen context\n try {\n ctx.extra = {\n ...(ctx.extra ?? {}),\n page_title:\n (ctx.extra as any)?.page_title ?? document.title ?? \"\",\n page_url:\n (ctx.extra as any)?.page_url ?? window.location.href ?? \"\",\n };\n } catch {}\n\n // ── Host-app injected context (highest priority) ──────────────────────────\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 this._isFullscreen = false;\n const panel = this.shadowRoot!.querySelector(\".panel\")!;\n panel.classList.add(\"closed\");\n panel.classList.remove(\"fullscreen\");\n const fab = this.shadowRoot!.querySelector(\".toggle-btn\") as HTMLElement;\n fab.style.display = \"\"; // always restore FAB — covers minimize-from-fullscreen\n fab.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, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\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","fullPath","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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"}
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._withEntityName(\n UI5Probe._sanitize(obj as Record<string, unknown>),\n ctx.getPath?.() ?? \"\",\n );\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._withEntityName(\n UI5Probe._sanitize(obj as Record<string, unknown>),\n ctx.getPath?.() ?? \"\",\n );\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 // Capture the deferred URI so ContextBridge can follow the navigation link.\n // Stored as `${navPropertyName}_navUri` — never sent raw to the chatbot.\n const uri: unknown = (v as any).__deferred?.uri;\n if (typeof uri === \"string\" && uri) {\n clean[`${k}_navUri`] = uri;\n }\n } else {\n clean[k] = v;\n }\n }\n return clean;\n }\n\n /**\n * Inject `_entity` into a sanitized binding context object by parsing the\n * OData context path. The path looks like `/FertilizerBlend(orderID='2466',...)`\n * or `/Farms('abc-123')` — the entity set name is the first path segment.\n */\n private static _withEntityName(\n obj: Record<string, unknown>,\n path: string,\n ): Record<string, unknown> {\n if (obj._entity) return obj; // already set (e.g. via setRecord())\n try {\n // Match the first path segment: /EntitySetName( or /EntitySetName\n const m = path.match(/^\\/([A-Za-z_][A-Za-z0-9_]*)(?:\\(|$|\\/)/);\n if (m?.[1]) return { _entity: m[1], ...obj };\n } catch {}\n return obj;\n }\n}\n","import type {\n EntitySchema,\n EntityProperty,\n NavProperty,\n AssociationInfo,\n ActionInfo,\n ParsedMetadata,\n AppDocument,\n} from \"../types\";\n\nexport class ODataProbe {\n private static _metaCache = new Map<string, ParsedMetadata>();\n\n // ── Public API ──────────────────────────────────────────────────────────────\n\n /**\n * Fetch and fully parse $metadata for a service URL.\n * Result is memory-cached for the page lifetime and persisted to sessionStorage.\n * Returns null on any network / parse failure.\n */\n static async fetchMetadata(\n serviceUrl: string,\n token?: string | null,\n ): Promise<ParsedMetadata | null> {\n const cacheKey = `btp-copilot-meta-v2-${serviceUrl}`;\n\n if (ODataProbe._metaCache.has(cacheKey)) {\n return ODataProbe._metaCache.get(cacheKey)!;\n }\n\n const stored = sessionStorage.getItem(cacheKey);\n if (stored) {\n try {\n // rawXml is intentionally excluded from sessionStorage (can be 100KB+).\n // Restore with empty rawXml — the memory cache always has the full value.\n const parsedFromStorage = JSON.parse(stored) as Omit<ParsedMetadata, \"rawXml\">;\n const parsed: ParsedMetadata = { ...parsedFromStorage, rawXml: \"\" };\n ODataProbe._metaCache.set(cacheKey, parsed);\n return parsed;\n } catch {}\n }\n\n try {\n const metaUrl = `${serviceUrl.replace(/\\/$/, \"\")}/$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 null;\n\n const xml = await resp.text();\n const parsed = ODataProbe._parseEDMX(xml, serviceUrl);\n\n ODataProbe._metaCache.set(cacheKey, parsed);\n try {\n // Strip rawXml before persisting to sessionStorage — it can be 100KB+\n // for complex SAP services and quickly fills the 5–10 MB quota.\n // The memory cache retains rawXml for same-page use (_registerMetadata).\n const { rawXml: _discarded, ...parsedForStorage } = parsed;\n sessionStorage.setItem(cacheKey, JSON.stringify(parsedForStorage));\n } catch {} // storage quota exceeded — ignore\n\n return parsed;\n } catch {\n return null;\n }\n }\n\n /**\n * Build schema hint documents from parsed metadata.\n * Used to populate fiori_context.extra.schema_hint for each chat message.\n */\n static buildSchemaDocuments(\n parsed: ParsedMetadata,\n serviceUrl: string,\n ): AppDocument[] {\n const docs: AppDocument[] = [];\n\n for (const schema of parsed.entities) {\n if (!schema.name) continue;\n const setName = schema.entitySetName ?? schema.name;\n const keyProps = schema.properties.filter((p) => p.isKey);\n const otherProps = schema.properties.filter((p) => !p.isKey);\n\n const lines = [\n `Entity: ${schema.name}`,\n `Entity set: ${setName}`,\n `OData service: ${serviceUrl}`,\n `Entity set path: ${serviceUrl}/${setName}`,\n `Count path: ${serviceUrl}/${setName}/$count`,\n ];\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((p) => `${p.name} (${p.type}${p.nullable ? \"\" : \", required\"})`)\n .join(\", \")}`,\n );\n }\n if (schema.navProperties.length) {\n lines.push(\n `Navigation: ${schema.navProperties\n .map((n) => `${n.name} → ${n.type}${n.cardinality === \"*\" ? \"[]\" : \"\"}`)\n .join(\", \")}`,\n );\n }\n\n docs.push({ title: `${schema.name} entity schema`, content: lines.join(\"\\n\") });\n }\n\n // Associations summary doc\n if (parsed.associations.length) {\n const assocLines = parsed.associations.map(\n (a) =>\n `${a.sourceEntity}.${a.navigationProperty} → ${a.targetEntity} (${a.cardinality === \"*\" ? \"many\" : \"one\"})`,\n );\n docs.push({\n title: \"Entity associations and navigation\",\n content: [\"Associations:\", ...assocLines].join(\"\\n\"),\n });\n }\n\n // Actions / Functions summary doc\n if (parsed.actions.length) {\n const actionLines = parsed.actions.map((a) => {\n const params = a.parameters.map((p) => `${p.name}: ${p.type}`).join(\", \");\n return `${a.name}(${params})${a.bound && a.entity ? ` [bound to ${a.entity}]` : \"\"}`;\n });\n docs.push({\n title: \"OData actions and functions\",\n content: [\"Actions/Functions:\", ...actionLines].join(\"\\n\"),\n });\n }\n\n // Entity set index doc\n if (parsed.entities.length > 0) {\n docs.push({\n title: \"Available OData entity sets\",\n content: [\n `OData service: ${serviceUrl}`,\n `Entities: ${parsed.entities.map((s) => s.entitySetName ?? s.name).join(\", \")}`,\n \"Patterns: GET {entitySet}/$count | ?$filter=field eq 'value' | ?$top=10&$skip=0 | ?$orderby=field desc\",\n ].join(\"\\n\"),\n });\n }\n\n return docs;\n }\n\n /**\n * Legacy helper kept for backward compatibility.\n * Prefer fetchMetadata() + buildSchemaDocuments() for new code.\n */\n static async fetchSchemaDocuments(\n serviceUrl: string,\n token?: string | null,\n ): Promise<AppDocument[]> {\n const parsed = await ODataProbe.fetchMetadata(serviceUrl, token);\n if (!parsed) return [];\n return ODataProbe.buildSchemaDocuments(parsed, serviceUrl);\n }\n\n /** Invalidate cached metadata for a service (call when metadata may have changed). */\n static invalidate(serviceUrl: string) {\n const key = `btp-copilot-meta-v2-${serviceUrl}`;\n ODataProbe._metaCache.delete(key);\n sessionStorage.removeItem(key);\n }\n\n /**\n * Fetch live entity data from an OData service with full error capture.\n *\n * Unlike a raw fetch(), this method:\n * - Returns { data, error } — never throws\n * - Captures the HTTP status and error body on failure\n * - Builds a human-readable error context string the chatbot can use to\n * explain to the user why data is unavailable, instead of returning\n * an empty result or crashing silently\n *\n * @example\n * const { data, error, errorContext } = await ODataProbe.fetchEntityData(\n * '/odata/v4/fertilizer-blend/Farms', token\n * );\n * if (error) ctx.extra.fetch_errors = [...(ctx.extra.fetch_errors ?? []), errorContext];\n */\n static async fetchEntityData(\n url: string,\n token?: string | null,\n options?: RequestInit,\n ): Promise<{ data: unknown; error: string | null; errorContext: string | null }> {\n try {\n const headers: Record<string, string> = { Accept: \"application/json\" };\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n\n const resp = await fetch(url, { ...options, headers: { ...headers, ...(options?.headers as Record<string, string> ?? {}) } });\n\n if (!resp.ok) {\n let body = \"\";\n try { body = await resp.text(); } catch {}\n const error = `HTTP ${resp.status} ${resp.statusText}`;\n const errorContext = [\n `OData fetch failed: ${url}`,\n `Status: ${error}`,\n body ? `Response: ${body.slice(0, 500)}` : \"\",\n `This entity's data cannot be displayed to the user right now.`,\n `The underlying service may have an API mismatch (e.g. invalid $expand).`,\n ].filter(Boolean).join(\"\\n\");\n return { data: null, error, errorContext };\n }\n\n const json = await resp.json();\n return { data: json, error: null, errorContext: null };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n const errorContext = [\n `OData fetch failed: ${url}`,\n `Error: ${message}`,\n `This entity's data cannot be displayed to the user right now.`,\n ].join(\"\\n\");\n return { data: null, error: message, errorContext };\n }\n }\n\n /**\n * Track an OData fetch error in sessionStorage so the ContextBridge can\n * include it in the next context push to the chatbot iframe.\n * Call this whenever a live data fetch in the host app fails.\n */\n static recordFetchError(entityName: string, url: string, reason: string): void {\n try {\n const key = \"btp-copilot-fetch-errors\";\n const existing: Array<{ entity: string; url: string; reason: string; at: string }> =\n JSON.parse(sessionStorage.getItem(key) ?? \"[]\");\n // Keep only the last 10 errors to avoid unbounded growth\n const updated = [\n ...existing.filter((e) => e.entity !== entityName),\n { entity: entityName, url, reason, at: new Date().toISOString() },\n ].slice(-10);\n sessionStorage.setItem(key, JSON.stringify(updated));\n } catch {}\n }\n\n /** Read all recorded fetch errors as a schema_hint-style string. */\n static getFetchErrorContext(): string | null {\n try {\n const key = \"btp-copilot-fetch-errors\";\n const errors: Array<{ entity: string; url: string; reason: string; at: string }> =\n JSON.parse(sessionStorage.getItem(key) ?? \"[]\");\n if (errors.length === 0) return null;\n const lines = [\n \"The following entities currently have backend errors and may not show live data:\",\n ...errors.map(\n (e) => `- ${e.entity}: ${e.reason} (${e.url}) [at ${e.at}]`,\n ),\n ];\n return lines.join(\"\\n\");\n } catch {\n return null;\n }\n }\n\n /**\n * Find all entities in the parsed metadata that link TO the given entity type.\n * These are the \"reverse\" associations — i.e. other entities that have a FK\n * pointing at `entityName`.\n *\n * For each such entity, returns the entity set name, the navigation property\n * name, and the FK / referenced-key pair so the caller can build an OData\n * $filter query like:\n * `GET /Farms?$filter=to_FertilizerBlend_orderID eq '2466'`\n *\n * @example\n * // User is viewing FertilizerBlend(orderID='2466')\n * const links = ODataProbe.findLinkedEntities(parsed, \"FertilizerBlend\");\n * // → [{ entitySetName: \"Farms\", navProperty: \"to_FertilizerBlend\",\n * // foreignKey: \"to_FertilizerBlend_orderID\", referencedKey: \"orderID\" }]\n */\n static findLinkedEntities(\n parsed: ParsedMetadata,\n entityName: string,\n ): Array<{\n entitySetName: string;\n navProperty: string;\n foreignKey: string;\n referencedKey: string;\n }> {\n const results: Array<{\n entitySetName: string;\n navProperty: string;\n foreignKey: string;\n referencedKey: string;\n }> = [];\n\n for (const assoc of parsed.associations) {\n if (\n assoc.targetEntity === entityName &&\n assoc.foreignKey &&\n assoc.referencedKey\n ) {\n const schema = parsed.entities.find(\n (e) => e.name === assoc.sourceEntity,\n );\n if (schema) {\n results.push({\n entitySetName: schema.entitySetName ?? schema.name,\n navProperty: assoc.navigationProperty,\n foreignKey: assoc.foreignKey,\n referencedKey: assoc.referencedKey,\n });\n }\n }\n }\n\n return results;\n }\n\n // ── EDMX Parser ─────────────────────────────────────────────────────────────\n\n private static _parseEDMX(xml: string, _serviceUrl: string): ParsedMetadata {\n const entities: EntitySchema[] = [];\n const associations: AssociationInfo[] = [];\n const actions: ActionInfo[] = [];\n\n try {\n const doc = new DOMParser().parseFromString(xml, \"text/xml\");\n\n // ── Build entityType → entitySetName map ────────────────────────────────\n const setNameMap = new Map<string, string>(); // typeName → setName\n doc.querySelectorAll(\"EntitySet\").forEach((es) => {\n const typeFull = es.getAttribute(\"EntityType\") ?? \"\";\n const typeName = typeFull.split(\".\").pop() ?? typeFull;\n const setName = es.getAttribute(\"Name\") ?? typeName;\n setNameMap.set(typeName, setName);\n });\n\n // ── Parse EntityTypes ───────────────────────────────────────────────────\n doc.querySelectorAll(\"EntityType\").forEach((et) => {\n const name = et.getAttribute(\"Name\") ?? \"\";\n if (!name) return;\n\n const keyRefs = new Set(\n Array.from(et.querySelectorAll(\"Key > PropertyRef\")).map(\n (k) => k.getAttribute(\"Name\") ?? \"\",\n ),\n );\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: keyRefs.has(p.getAttribute(\"Name\") ?? \"\"),\n nullable: p.getAttribute(\"Nullable\") !== \"false\",\n }));\n\n const navProperties: NavProperty[] = Array.from(\n et.querySelectorAll(\"NavigationProperty\"),\n ).map((n) => {\n const rawType = n.getAttribute(\"Type\") ?? n.getAttribute(\"ToRole\") ?? \"\";\n const isCollection = rawType.startsWith(\"Collection(\");\n // Parse ReferentialConstraint: the FK field on this entity and the\n // referenced field on the target entity. Present in OData v4 EDMX.\n const rc = n.querySelector(\"ReferentialConstraint\");\n return {\n name: n.getAttribute(\"Name\") ?? \"\",\n type: ODataProbe._shortType(rawType),\n cardinality: isCollection ? \"*\" : \"1\",\n partner: n.getAttribute(\"Partner\") ?? undefined,\n foreignKey: rc?.getAttribute(\"Property\") ?? undefined,\n referencedKey: rc?.getAttribute(\"ReferencedProperty\") ?? undefined,\n };\n });\n\n entities.push({\n name,\n entitySetName: setNameMap.get(name) ?? name,\n properties,\n navProperties,\n });\n });\n\n // ── Build associations from navigation properties ────────────────────────\n for (const entity of entities) {\n for (const nav of entity.navProperties) {\n const targetType = nav.type.replace(/\\[\\]$/, \"\");\n associations.push({\n sourceEntity: entity.name,\n navigationProperty: nav.name,\n targetEntity: targetType,\n cardinality: nav.cardinality === \"*\" ? \"*\" : \"1\",\n foreignKey: nav.foreignKey,\n referencedKey: nav.referencedKey,\n });\n }\n }\n\n // ── Parse Actions and Functions ─────────────────────────────────────────\n const parseCallable = (el: Element, bound: boolean): ActionInfo => {\n const name = el.getAttribute(\"Name\") ?? \"\";\n const params: { name: string; type: string }[] = [];\n let entity: string | undefined;\n\n el.querySelectorAll(\"Parameter\").forEach((p, idx) => {\n const paramName = p.getAttribute(\"Name\") ?? \"\";\n const paramType = ODataProbe._shortType(p.getAttribute(\"Type\") ?? \"\");\n if (bound && idx === 0) {\n // First parameter of a bound action is always the binding entity\n entity = paramType.replace(/\\[\\]$/, \"\");\n } else {\n params.push({ name: paramName, type: paramType });\n }\n });\n\n const retEl = el.querySelector(\"ReturnType\");\n const returnType = retEl\n ? ODataProbe._shortType(retEl.getAttribute(\"Type\") ?? \"\")\n : undefined;\n\n return { name, bound, entity, parameters: params, returnType };\n };\n\n doc.querySelectorAll(\"Action\").forEach((el) => {\n const bound = el.getAttribute(\"IsBound\") === \"true\";\n actions.push(parseCallable(el, bound));\n });\n doc.querySelectorAll(\"Function\").forEach((el) => {\n const bound = el.getAttribute(\"IsBound\") === \"true\";\n actions.push(parseCallable(el, bound));\n });\n // OData v2 FunctionImports\n doc.querySelectorAll(\"FunctionImport\").forEach((el) => {\n const name = el.getAttribute(\"Name\") ?? \"\";\n const params: { name: string; type: string }[] = [];\n el.querySelectorAll(\"Parameter\").forEach((p) => {\n params.push({\n name: p.getAttribute(\"Name\") ?? \"\",\n type: ODataProbe._shortType(p.getAttribute(\"Type\") ?? \"\"),\n });\n });\n actions.push({ name, bound: false, parameters: params });\n });\n } catch {\n // Return whatever was parsed so far\n }\n\n return { entities, associations, actions, rawXml: xml };\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","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 // ── SAP-specific probes (no-ops on non-SAP apps) ──────────────────────────\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 // ── Generic web context (works for any app) ───────────────────────────────\n // current_view: full path + search + hash (more useful than hash alone)\n try {\n const fullPath =\n window.location.pathname +\n window.location.search +\n window.location.hash;\n if (!ctx.current_view || ctx.current_view === \"\") {\n ctx.current_view = fullPath;\n }\n } catch {}\n\n // locale fallback\n try {\n if (!ctx.user_locale) {\n ctx.user_locale =\n navigator.language || (navigator as any).languages?.[0] || \"en\";\n }\n } catch {}\n\n // page_title and page_url give the LLM meaningful screen context\n try {\n ctx.extra = {\n ...(ctx.extra ?? {}),\n page_title:\n (ctx.extra as any)?.page_title ?? document.title ?? \"\",\n page_url:\n (ctx.extra as any)?.page_url ?? window.location.href ?? \"\",\n };\n } catch {}\n\n // ── Host-app injected context (highest priority) ──────────────────────────\n try {\n const injected = (window as any).__APP_CONTEXT__ as\n | Partial<HostAppContext>\n | undefined;\n if (injected) {\n // Use _safeMerge to prevent prototype pollution attacks via\n // __proto__, constructor, or prototype keys in the injected object.\n if (injected.entity_data)\n ctx.entity_data = ContextBridge._safeMerge(ctx.entity_data ?? {}, injected.entity_data);\n if (injected.current_view && !ctx.current_view)\n ctx.current_view = injected.current_view;\n if (injected.extra)\n ctx.extra = ContextBridge._safeMerge(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 parsed = await ODataProbe.fetchMetadata(ctx.service_url, token);\n if (parsed) {\n const docs = ODataProbe.buildSchemaDocuments(parsed, ctx.service_url);\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 // Register raw XML with backend once per session (non-blocking)\n const backendUrl = (ctx.extra as any)?.backend_url as string | undefined;\n if (backendUrl && parsed.rawXml) {\n const appId = ctx.app_id;\n const serviceUrl = ctx.service_url;\n ContextBridge._registerMetadata(backendUrl, appId, serviceUrl, parsed.rawXml, token);\n }\n\n // ── Fetch linked navigation data for the currently-viewed record ─────────\n // When the user is looking at a specific entity (e.g. a FertilizerBlend\n // detail page), proactively fetch the records that link to it via FK\n // (e.g. which Farms have to_FertilizerBlend_orderID = current key).\n // The chatbot can then answer “what farms are linked to this blend?”\n // without making any OData calls itself.\n const entityName = ctx.entity_data?._entity as string | undefined;\n if (entityName && ctx.service_url) {\n try {\n const linked = await ContextBridge._fetchLinkedEntities(\n ctx.service_url, entityName, ctx.entity_data!, parsed, token,\n );\n if (Object.keys(linked).length > 0) {\n ctx.entity_data = { ...(ctx.entity_data ?? {}), ...linked };\n }\n } catch {}\n }\n }\n } catch {}\n }\n\n try {\n const fetchErrors = ODataProbe.getFetchErrorContext();\n if (fetchErrors) {\n ctx.extra = { ...(ctx.extra ?? {}), fetch_errors: fetchErrors };\n }\n } catch {}\n\n return ctx;\n }\n\n /**\n * Safe shallow merge that blocks prototype pollution.\n * Skips __proto__, constructor, and prototype keys from the incoming object.\n */\n private static _safeMerge(\n base: Record<string, unknown>,\n incoming: unknown,\n ): Record<string, unknown> {\n if (!incoming || typeof incoming !== \"object\" || Array.isArray(incoming)) return base;\n const safe: Record<string, unknown> = { ...base };\n for (const [k, v] of Object.entries(incoming as Record<string, unknown>)) {\n if (k === \"__proto__\" || k === \"constructor\" || k === \"prototype\") continue;\n safe[k] = v;\n }\n return safe;\n }\n\n /** POST raw $metadata XML to the backend — fire-and-forget, at most once per session per service. */\n private static _registeredKeys = new Set<string>();\n\n private static _linkedEntityCache = new Map<\n string,\n { data: Record<string, unknown>; fetchedAt: number }\n >();\n private static readonly _LINKED_CACHE_TTL = 30_000;\n\n private static async _fetchLinkedEntities(\n serviceUrl: string,\n entityName: string,\n entityData: Record<string, unknown>,\n parsed: import(\"../types\").ParsedMetadata,\n token: string | null,\n ): Promise<Record<string, unknown>> {\n const schema = parsed.entities.find(\n (e) => e.name === entityName || e.entitySetName === entityName,\n );\n if (!schema) return {};\n\n const keyProp = schema.properties.find((p) => p.isKey);\n if (!keyProp) return {};\n const keyValue = entityData[keyProp.name];\n if (keyValue == null) return {};\n\n const cacheKey = `${entityName}::${keyValue}`;\n const now = Date.now();\n const cached = ContextBridge._linkedEntityCache.get(cacheKey);\n if (cached && now - cached.fetchedAt < ContextBridge._LINKED_CACHE_TTL) {\n return cached.data;\n }\n\n const linked: Record<string, unknown> = {};\n const keyLiteral =\n typeof keyValue === \"number\" ? String(keyValue) : `'${keyValue}'`;\n\n const reverseLinks = ODataProbe.findLinkedEntities(parsed, schema.name);\n await Promise.all(\n reverseLinks.map(async (link) => {\n try {\n const url =\n `${serviceUrl}/${link.entitySetName}` +\n `?$filter=${encodeURIComponent(`${link.foreignKey} eq ${keyLiteral}`)}` +\n `&$top=50`;\n const { data, error, errorContext } =\n await ODataProbe.fetchEntityData(url, token);\n if (error) {\n ODataProbe.recordFetchError(link.entitySetName, url, error);\n if (errorContext)\n linked[`linked_${link.entitySetName}_error`] = errorContext;\n } else if (data) {\n const records =\n (data as any).value ?? (Array.isArray(data) ? data : [data]);\n if (records.length > 0)\n linked[`linked_${link.entitySetName}`] = records;\n }\n } catch {}\n }),\n );\n\n const setName = schema.entitySetName ?? schema.name;\n const singleNavs = schema.navProperties.filter(\n (n) => n.cardinality !== \"*\",\n );\n await Promise.all(\n singleNavs.map(async (nav) => {\n if (linked[`linked_${nav.name}`] != null) return;\n try {\n const url = `${serviceUrl}/${setName}(${keyLiteral})/${nav.name}`;\n const { data, error } = await ODataProbe.fetchEntityData(url, token);\n if (!error && data) {\n const record = (data as any).value ?? data;\n if (record != null) linked[`linked_${nav.name}`] = record;\n }\n } catch {}\n }),\n );\n\n ContextBridge._linkedEntityCache.set(cacheKey, {\n data: linked,\n fetchedAt: now,\n });\n return linked;\n }\n\n private static async _registerMetadata(\n backendUrl: string,\n appId: string,\n serviceUrl: string,\n rawXml: string,\n token?: string | null,\n ): Promise<void> {\n const key = `${appId}::${serviceUrl}`;\n if (ContextBridge._registeredKeys.has(key)) return;\n ContextBridge._registeredKeys.add(key);\n\n try {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n await fetch(`${backendUrl}/api/apps/register-metadata`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ app_id: appId, service_url: serviceUrl, raw_xml: rawXml }),\n });\n } catch {\n // non-critical — remove key so next load can retry\n ContextBridge._registeredKeys.delete(key);\n }\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 /**\n * Listen for postMessage events from the BTP Copilot iframe.\n *\n * @param allowedOrigin The iframe's origin (e.g. \"https://your-chatbot.cfapps.eu10.hana.ondemand.com\").\n * Messages from any other origin are silently ignored.\n * Pass \"*\" only in trusted, same-origin deployments.\n */\n static listenForUpdates(\n onContextUpdate: (ctx: Partial<HostAppContext>) => void,\n onMessage: (text: string) => void,\n onOpen: () => void,\n onClose: () => void,\n allowedOrigin?: string,\n ): () => void {\n const handler = (event: MessageEvent) => {\n if (!event.data || typeof event.data !== \"object\") return;\n if (allowedOrigin && allowedOrigin !== \"*\" && event.origin !== allowedOrigin) 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 \"backend-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 /** Record pushed by the host app via setRecord() / pushData(). */\n private _manualRecord: Record<string, unknown> | null = null;\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 // Only accept messages from the configured iframe origin.\n // Falls back to accepting any origin only when iframeUrl is not yet set.\n const expectedOrigin = this._iframeOrigin();\n if (expectedOrigin !== \"*\" && event.origin !== expectedOrigin) 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 this._isFullscreen = false;\n const panel = this.shadowRoot!.querySelector(\".panel\")!;\n panel.classList.add(\"closed\");\n panel.classList.remove(\"fullscreen\");\n const fab = this.shadowRoot!.querySelector(\".toggle-btn\") as HTMLElement;\n fab.style.display = \"\"; // always restore FAB — covers minimize-from-fullscreen\n fab.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 this._iframeOrigin()\n );\n }, 100);\n }\n\n /**\n * Push the currently-viewed record into the chatbot context.\n *\n * Call this from your Fiori controller or CAP handler after a record is loaded.\n * The chatbot will have all field values and can answer questions like\n * \"what is the applicator?\" or \"what status is this order?\" immediately.\n *\n * @param entityName The OData entity set name, e.g. \"FertilizerBlend\"\n * @param data Plain object of field → value pairs (the record)\n *\n * @example // Fiori UI5 controller (1 line):\n * document.querySelector('btp-copilot')\n * .setRecord('FertilizerBlend', this.getView().getBindingContext().getObject());\n */\n setRecord(entityName: string, data: Record<string, unknown>): void {\n this._manualRecord = { _entity: entityName, ...data };\n this._pushContextToIframe();\n }\n\n /**\n * Push arbitrary key/value pairs into the chatbot context (without an entity name).\n * Useful for custom metadata, computed values, or non-OData context.\n *\n * @example\n * widget.pushData({ currentUser: 'John', selectedRegion: 'EU' });\n */\n pushData(data: Record<string, unknown>): void {\n this._manualRecord = { ...this._manualRecord, ...data };\n this._pushContextToIframe();\n }\n\n /** Remove the manually-set record so auto-context takes over again. */\n clearRecord(): void {\n this._manualRecord = null;\n this._pushContextToIframe();\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 // Always send an absolute service_url so the backend can make direct OData calls.\n // Attributes like service-url=\"/odata/v4/fleet-management\" are relative — prepend origin.\n const rawSvcUrl = this._config.serviceUrl ?? \"\";\n const serviceUrl = rawSvcUrl\n ? rawSvcUrl.startsWith(\"http\")\n ? rawSvcUrl\n : `${window.location.origin}${rawSvcUrl}`\n : undefined;\n return {\n app_id: this._config.appId,\n app_name: this._config.appName,\n service_url: serviceUrl,\n // Manually set record (via setRecord / pushData) — overrides auto-context entity_data\n ...(this._manualRecord ? { entity_data: this._manualRecord } : {}),\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 extra: {\n ...(token ? { auth_token: token } : {}),\n ...(this._config.backendUrl ? { backend_url: this._config.backendUrl } : {}),\n },\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 // Do NOT pass auth tokens as URL query params — they appear in server logs,\n // browser history, and Referer headers. The token is sent securely via\n // postMessage in _pushAuthToIframe() after the iframe loads.\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 backendUrl: get(\"backend-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, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\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","uri","path","m","_ODataProbe","serviceUrl","cacheKey","stored","parsed","metaUrl","headers","resp","xml","_discarded","parsedForStorage","docs","schema","setName","keyProps","p","otherProps","lines","n","assocLines","actionLines","params","s","key","options","body","error","errorContext","message","entityName","reason","updated","e","errors","results","assoc","_serviceUrl","entities","associations","actions","doc","setNameMap","es","typeFull","typeName","et","keyRefs","properties","navProperties","rawType","isCollection","rc","entity","targetType","parseCallable","bound","idx","paramName","paramType","retEl","returnType","full","ODataProbe","_ContextBridge","baseContext","hash","fullPath","injected","schemaHint","backendUrl","appId","linked","fetchErrors","base","incoming","safe","entityData","keyProp","keyValue","now","cached","keyLiteral","reverseLinks","link","data","records","singleNavs","record","rawXml","entries","manifest","sources","src","onContextUpdate","onMessage","onOpen","onClose","allowedOrigin","handler","event","type","payload","text","ContextBridge","widgetCss","OBSERVED","_BtpCopilotElement","msgHandler","expectedOrigin","_name","old","next","panel","fab","shadow","styleEl","wrapper","pos","rawSvcUrl","appName","origin","get","attr","style","newSrc","BtpCopilotElement"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cap-copilot-widget",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "BTP Copilot floating chat widget — Web Component (iframe launcher)",
5
5
  "main": "dist/btp-copilot.js",
6
6
  "module": "dist/btp-copilot.esm.js",
@@ -15,8 +15,8 @@
15
15
  "files": ["dist"],
16
16
  "scripts": {
17
17
  "dev": "vite --port 5174 --open",
18
- "build": "tsc --noEmit && vite build",
19
- "prepare": "tsc --noEmit && vite build",
18
+ "build": "tsc --emitDeclarationOnly && vite build",
19
+ "prepare": "tsc --emitDeclarationOnly && vite build",
20
20
  "preview": "vite preview",
21
21
  "clean": "rm -rf dist"
22
22
  },