@omni-commerce/sdk 0.6.0 → 0.7.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/embed.ts","../src/widget-chrome.ts","../src/widget.ts","../src/embed-code.ts"],"sourcesContent":["/** A hosted chat session. Keep its short-lived token in memory, never in iframe URLs. */\nexport { createOmniChatWidget, type OmniChatWidgetOptions } from \"./widget\";\nexport { getOmniChatEmbedCode, getOmniChatReactCode } from \"./embed-code\";\nexport interface OmniChatSession {\n token: string;\n threadId: string;\n expiresIn: number;\n}\nexport interface OmniChatEmbedOptions {\n deploymentId: string;\n baseUrl?: string;\n /** Optional authenticated session mint on the host application's server. */\n getSession?: () => Promise<OmniChatSession>;\n title?: string;\n onError?: (error: Error) => void;\n /** Floating widgets use this to close on Escape from the hosted chat. */\n onRequestClose?: () => void;\n}\nexport interface OmniChatEmbed {\n iframe: HTMLIFrameElement;\n /** Focus the hosted composer, including when reopening a retained chat. */\n focus(): void;\n destroy(): void;\n}\n\nexport function getOmniChatEmbedUrl(\n options: Pick<OmniChatEmbedOptions, \"baseUrl\" | \"deploymentId\">,\n parentOrigin?: string,\n): string {\n if (\n !/^[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}$/i.test(\n options.deploymentId,\n )\n )\n throw new Error(\"A valid chat deployment ID is required.\");\n const base = new URL(options.baseUrl ?? \"https://omnicommerce.sg\");\n if (\n (base.protocol !== \"https:\" &&\n !(\n base.protocol === \"http:\" &&\n [\"localhost\", \"127.0.0.1\"].includes(base.hostname)\n )) ||\n base.username ||\n base.password ||\n base.pathname !== \"/\" ||\n base.search ||\n base.hash\n )\n throw new Error(\"Chat baseUrl must be an HTTPS origin, or HTTP localhost.\");\n const url = new URL(`/embed/${options.deploymentId}`, base.origin);\n if (parentOrigin)\n url.searchParams.set(\"parentOrigin\", new URL(parentOrigin).origin);\n return url.toString();\n}\n\n/** Browser-only mounting; importing this entry point is safe during SSR. */\nexport function createOmniChatEmbed(\n container: HTMLElement,\n options: OmniChatEmbedOptions,\n): OmniChatEmbed {\n const document = container.ownerDocument;\n const host = document.defaultView;\n if (!host) throw new Error(\"A browser document is required to mount chat.\");\n const iframe = document.createElement(\"iframe\");\n iframe.src = getOmniChatEmbedUrl(options, host.location.origin);\n iframe.title = options.title ?? \"OmniCommerce assistant\";\n iframe.referrerPolicy = \"strict-origin-when-cross-origin\";\n iframe.setAttribute(\n \"sandbox\",\n \"allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox\",\n );\n Object.assign(iframe.style, {\n width: \"100%\",\n height: \"100%\",\n minHeight: \"320px\",\n border: \"0\",\n display: \"block\",\n });\n const chatOrigin = new URL(iframe.src).origin;\n let destroyed = false;\n let pending: Promise<OmniChatSession> | undefined;\n let previousToken: string | undefined;\n const controller = new AbortController();\n\n const mint = async (): Promise<OmniChatSession> => {\n if (options.getSession) return options.getSession();\n const response = await host.fetch(\n `${chatOrigin}/api/embed/${options.deploymentId}/session`,\n {\n method: \"POST\",\n credentials: \"include\",\n signal: controller.signal,\n headers: {\n \"Content-Type\": \"application/json\",\n ...(previousToken\n ? { Authorization: `Bearer ${previousToken}` }\n : {}),\n },\n body: \"{}\",\n },\n );\n const result = (await response.json()) as OmniChatSession & {\n error?: string;\n };\n if (!response.ok) {\n // A rejected renewal must not keep Retry bound to an obsolete session.\n // The next mint still performs the deployment's full access checks.\n if (response.status === 401 || response.status === 403)\n previousToken = undefined;\n throw new Error(result.error ?? \"Could not open the chat session.\");\n }\n return result;\n };\n const receive = (event: MessageEvent) => {\n if (\n destroyed ||\n event.source !== iframe.contentWindow ||\n event.origin !== chatOrigin ||\n event.data?.deploymentId !== options.deploymentId\n )\n return;\n if (event.data.type === \"omni-chat:close-request\") {\n options.onRequestClose?.();\n return;\n }\n if (event.data.type !== \"omni-chat:session-request\") return;\n pending ??= mint();\n void pending\n .then((session) => {\n if (destroyed) return;\n if (\n typeof session?.token !== \"string\" ||\n !session.token ||\n session.token.length > 4096 ||\n typeof session.threadId !== \"string\" ||\n !session.threadId ||\n !Number.isFinite(session.expiresIn) ||\n session.expiresIn <= 0\n )\n throw new Error(\"Invalid chat session response.\");\n previousToken = session.token;\n iframe.contentWindow?.postMessage(\n {\n type: \"omni-chat:session\",\n deploymentId: options.deploymentId,\n session,\n },\n chatOrigin,\n );\n })\n .catch((error: unknown) => {\n if (destroyed) return;\n const failure =\n error instanceof Error ? error : new Error(\"Could not open chat.\");\n options.onError?.(failure);\n iframe.contentWindow?.postMessage(\n {\n type: \"omni-chat:session-error\",\n deploymentId: options.deploymentId,\n error: failure.message,\n },\n chatOrigin,\n );\n })\n .finally(() => {\n pending = undefined;\n });\n };\n host.addEventListener(\"message\", receive);\n container.append(iframe);\n return {\n iframe,\n focus() {\n if (destroyed) return;\n iframe.focus();\n iframe.contentWindow?.postMessage(\n {\n type: \"omni-chat:focus-composer\",\n deploymentId: options.deploymentId,\n },\n chatOrigin,\n );\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\n controller.abort();\n previousToken = undefined;\n host.removeEventListener(\"message\", receive);\n iframe.remove();\n },\n };\n}\n","const iconPaths = {\n chat: \"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5Z\",\n close: \"m6 6 12 12M6 18 18 6\",\n collapse: \"m6 9 6 6 6-6\",\n};\n\nexport function widgetIcon(document: Document, name: keyof typeof iconPaths) {\n const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n svg.setAttribute(\"viewBox\", \"0 0 24 24\");\n svg.setAttribute(\"fill\", \"none\");\n svg.setAttribute(\"stroke\", \"currentColor\");\n svg.setAttribute(\"stroke-width\", \"1.8\");\n svg.setAttribute(\"stroke-linecap\", \"round\");\n svg.setAttribute(\"stroke-linejoin\", \"round\");\n svg.setAttribute(\"aria-hidden\", \"true\");\n const path = document.createElementNS(\"http://www.w3.org/2000/svg\", \"path\");\n path.setAttribute(\"d\", iconPaths[name]);\n svg.append(path);\n return svg;\n}\n\n/** Shadow DOM keeps a store's button, font and section CSS out of the widget. */\nexport const widgetStyles = `\n :host { all: initial; font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; color-scheme: light; }\n *, *::before, *::after { box-sizing: border-box; }\n button { font: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; }\n button:focus-visible { outline: 3px solid var(--omni-launcher-bg); outline-offset: 4px; }\n svg { display: block; width: 22px; height: 22px; flex: none; }\n .launcher {\n display: flex; align-items: center; justify-content: center; gap: 10px;\n height: 52px; padding: 0 20px; border: 1px solid rgba(255,255,255,.14);\n border-radius: 999px; background: var(--omni-launcher-bg); color: var(--omni-launcher-fg);\n font-size: 14px; font-weight: 600; line-height: 1; letter-spacing: -.01em;\n box-shadow: 0 6px 24px rgba(0,0,0,.16), 0 2px 6px rgba(0,0,0,.08);\n transition: transform 160ms ease, box-shadow 160ms ease;\n margin-left: auto;\n }\n .launcher:hover { transform: translateY(-2px); box-shadow: 0 10px 28px rgba(0,0,0,.2); }\n .launcher[hidden] { display: none; }\n .launcher[aria-expanded=\"true\"] { width: 52px; padding: 0; }\n .launcher[aria-expanded=\"true\"] .label { display: none; }\n .panel {\n position: absolute; bottom: 66px; right: 0; width: min(392px, calc(100vw - 40px));\n overflow: hidden; border: 1px solid rgba(0,0,0,.08); border-radius: 20px;\n background: var(--omni-panel-bg); box-shadow: 0 24px 80px rgba(0,0,0,.18), 0 4px 16px rgba(0,0,0,.06);\n animation: omni-chat-enter 180ms ease-out;\n }\n .panel[hidden] { display: none; }\n .frame { height: min(780px, calc(100dvh - 112px)); min-height: 240px; }\n .close {\n position: absolute; z-index: 1; top: 18px; right: 14px;\n display: flex; align-items: center; justify-content: center; width: 34px; height: 34px;\n border: 1px solid color-mix(in srgb, var(--omni-panel-fg) 10%, transparent); border-radius: 50%;\n background: var(--omni-panel-bg); color: var(--omni-panel-fg); transition: background 160ms ease;\n }\n .close svg { width: 17px; height: 17px; }\n .close:hover { background: color-mix(in srgb, var(--omni-panel-fg) 6%, var(--omni-panel-bg)); }\n :host([data-position=\"left\"]) .panel { right: auto; left: 0; }\n :host([data-position=\"left\"]) .launcher { margin-left: 0; }\n :host([data-presentation=\"sidebar\"]) .panel {\n position: fixed; top: 0; bottom: 0; right: 0; left: auto;\n width: min(440px, 100vw); border-radius: 0; border-top: 0; border-bottom: 0;\n animation: omni-sidebar-enter 180ms ease-out;\n }\n :host([data-presentation=\"sidebar\"]) .frame { height: 100dvh; min-height: 0; }\n :host([data-presentation=\"sidebar\"][data-position=\"left\"]) .panel {\n right: auto; left: 0; animation-name: omni-sidebar-enter-left;\n }\n @keyframes omni-sidebar-enter { from { opacity: 0; transform: translateX(100%); } to { opacity: 1; transform: none; } }\n @keyframes omni-sidebar-enter-left { from { opacity: 0; transform: translateX(-100%); } to { opacity: 1; transform: none; } }\n @keyframes omni-chat-enter { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }\n @media (max-width: 480px) { :host([data-presentation=\"floating\"]) .panel { width: calc(100vw - 40px); border-radius: 18px; } }\n @media (prefers-reduced-motion: reduce) { .panel, :host([data-presentation=\"sidebar\"]) .panel { animation: none; } .launcher { transition: none; } }\n`;\n","import {\n createOmniChatEmbed,\n getOmniChatEmbedUrl,\n type OmniChatEmbedOptions,\n type OmniChatEmbed,\n} from \"./embed\";\nimport { widgetIcon, widgetStyles } from \"./widget-chrome\";\n\nexport type OmniChatWidgetOptions = OmniChatEmbedOptions & {\n /** Floating window by default; sidebar fills the viewport height. */\n presentation?: \"floating\" | \"sidebar\";\n launcherLabel?: string;\n position?: \"left\" | \"right\";\n launcherBackground?: string;\n launcherForeground?: string;\n panelBackground?: string;\n panelForeground?: string;\n};\nlet widgetSequence = 0;\n/** A website launcher using the same hosted assistant as OmniChat. */\nexport function createOmniChatWidget(\n container: HTMLElement,\n options: OmniChatWidgetOptions,\n) {\n getOmniChatEmbedUrl(options);\n const document = container.ownerDocument;\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-omni-chat-widget\", \"\");\n root.setAttribute(\"data-position\", options.position ?? \"right\");\n root.setAttribute(\"data-presentation\", options.presentation ?? \"floating\");\n const shadow = root.attachShadow({ mode: \"open\" });\n const style = document.createElement(\"style\");\n style.textContent = widgetStyles;\n const launcher = document.createElement(\"button\");\n const panel = document.createElement(\"section\");\n const close = document.createElement(\"button\");\n const frame = document.createElement(\"div\");\n let embed: OmniChatEmbed | undefined;\n let destroyed = false;\n Object.assign(root.style, {\n position: \"fixed\",\n bottom: \"20px\",\n [options.position ?? \"right\"]: \"20px\",\n zIndex: \"2147483000\",\n });\n root.style.setProperty(\n \"--omni-launcher-bg\",\n options.launcherBackground ?? \"#2563eb\",\n );\n root.style.setProperty(\n \"--omni-launcher-fg\",\n options.launcherForeground ?? \"#ffffff\",\n );\n root.style.setProperty(\n \"--omni-panel-bg\",\n options.panelBackground ?? \"#ffffff\",\n );\n root.style.setProperty(\n \"--omni-panel-fg\",\n options.panelForeground ?? \"#171717\",\n );\n launcher.type = close.type = \"button\";\n launcher.className = \"launcher\";\n const label = document.createElement(\"span\");\n label.className = \"label\";\n label.textContent = options.launcherLabel ?? \"Chat with us\";\n launcher.append(widgetIcon(document, \"chat\"), label);\n launcher.setAttribute(\"aria-expanded\", \"false\");\n launcher.setAttribute(\"aria-label\", label.textContent);\n panel.hidden = true;\n panel.className = \"panel\";\n panel.setAttribute(\"role\", \"region\");\n panel.setAttribute(\"aria-label\", options.title ?? \"Assistant chat\");\n panel.id = `omni-chat-widget-${++widgetSequence}`;\n launcher.setAttribute(\"aria-controls\", panel.id);\n frame.className = \"frame\";\n close.className = \"close\";\n close.setAttribute(\"aria-label\", \"Close chat\");\n close.title = \"Close chat\";\n close.append(widgetIcon(document, \"close\"));\n const closeChat = () => {\n if (destroyed) return;\n panel.hidden = true;\n launcher.hidden = false;\n launcher.setAttribute(\"aria-expanded\", \"false\");\n launcher.setAttribute(\"aria-label\", label.textContent!);\n launcher.querySelector(\"svg\")?.replaceWith(widgetIcon(document, \"chat\"));\n launcher.focus();\n };\n const openChat = () => {\n if (destroyed) return;\n embed ??= createOmniChatEmbed(frame, {\n ...options,\n onRequestClose: closeChat,\n });\n embed.iframe.style.minHeight = \"0\";\n panel.hidden = false;\n launcher.hidden = options.presentation === \"sidebar\";\n launcher.setAttribute(\"aria-expanded\", \"true\");\n launcher.setAttribute(\"aria-label\", \"Close chat\");\n launcher\n .querySelector(\"svg\")\n ?.replaceWith(widgetIcon(document, \"collapse\"));\n embed.focus();\n };\n launcher.addEventListener(\"click\", () =>\n panel.hidden ? openChat() : closeChat(),\n );\n close.addEventListener(\"click\", closeChat);\n shadow.addEventListener(\"keydown\", (event) => {\n if ((event as KeyboardEvent).key === \"Escape\" && !panel.hidden) closeChat();\n });\n panel.append(close, frame);\n shadow.append(style, panel, launcher);\n container.append(root);\n return {\n open: openChat,\n close: closeChat,\n destroy() {\n destroyed = true;\n embed?.destroy();\n root.remove();\n },\n };\n}\n","import { getOmniChatEmbedUrl, type OmniChatEmbedOptions } from \"./embed\";\nimport type { OmniChatWidgetOptions } from \"./widget\";\n\ntype EmbedCodeOptions = Pick<\n OmniChatEmbedOptions,\n \"baseUrl\" | \"deploymentId\" | \"title\"\n> &\n Pick<\n OmniChatWidgetOptions,\n | \"presentation\"\n | \"launcherLabel\"\n | \"position\"\n | \"launcherBackground\"\n | \"launcherForeground\"\n | \"panelBackground\"\n | \"panelForeground\"\n >;\nconst scriptJson = (value: unknown) =>\n JSON.stringify(value, null, 2).replace(\n /[<>&\\u2028\\u2029]/g,\n (character) =>\n `\\\\u${character.charCodeAt(0).toString(16).padStart(4, \"0\")}`,\n );\n\n/** Copyable integrations contain only public deployment configuration. */\nexport function getOmniChatEmbedCode(\n options: EmbedCodeOptions,\n mode: \"widget\" | \"inline\" = \"widget\",\n) {\n const baseUrl = new URL(getOmniChatEmbedUrl(options)).origin;\n const config = { ...options, baseUrl };\n const id = `omni-chat-${options.deploymentId}`;\n const mount =\n mode === \"widget\"\n ? `OmniCommerceChat.createOmniChatWidget(document.body, ${scriptJson(config)});`\n : `OmniCommerceChat.createOmniChatEmbed(document.getElementById(${scriptJson(id)}), ${scriptJson(config)});`;\n return `${mode === \"inline\" ? `<div id=\"${id}\" style=\"height:600px\"></div>\\n` : \"\"}<script src=\"${baseUrl}/sdk/embed.global.js\"></script>\\n<script>\\n ${mount.replace(/\\n/g, \"\\n \")}\\n</script>`;\n}\nexport function getOmniChatReactCode(options: EmbedCodeOptions) {\n const baseUrl = new URL(getOmniChatEmbedUrl(options)).origin;\n return `import { OmniProvider, OmniChat } from \"@omni-commerce/sdk/react\";\\n\\n<OmniProvider deploymentId={${scriptJson(options.deploymentId)}}\\n baseUrl={${scriptJson(baseUrl)}}${options.title ? `\\n title={${scriptJson(options.title)}}` : \"\"}>\\n <OmniChat style={{ height: 600 }} />\\n</OmniProvider>`;\n}\n"],"mappings":"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","names":["embed_exports","__export","createOmniChatEmbed","createOmniChatWidget","getOmniChatEmbedCode","getOmniChatEmbedUrl","getOmniChatReactCode","iconPaths","widgetIcon","document","name","svg","path","widgetStyles","widgetSequence","createOmniChatWidget","container","options","getOmniChatEmbedUrl","document","root","shadow","style","widgetStyles","launcher","panel","close","frame","embed","destroyed","label","widgetIcon","closeChat","openChat","createOmniChatEmbed","event","scriptJson","value","character","getOmniChatEmbedCode","options","mode","baseUrl","getOmniChatEmbedUrl","config","id","mount","getOmniChatReactCode","getOmniChatEmbedUrl","options","parentOrigin","base","url","createOmniChatEmbed","container","document","host","iframe","chatOrigin","destroyed","pending","previousToken","controller","mint","response","result","receive","event","session","error","failure"]}
package/dist/embed.js ADDED
@@ -0,0 +1,332 @@
1
+ // src/widget-chrome.ts
2
+ var iconPaths = {
3
+ chat: "M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5Z",
4
+ close: "m6 6 12 12M6 18 18 6",
5
+ collapse: "m6 9 6 6 6-6"
6
+ };
7
+ function widgetIcon(document, name) {
8
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
9
+ svg.setAttribute("viewBox", "0 0 24 24");
10
+ svg.setAttribute("fill", "none");
11
+ svg.setAttribute("stroke", "currentColor");
12
+ svg.setAttribute("stroke-width", "1.8");
13
+ svg.setAttribute("stroke-linecap", "round");
14
+ svg.setAttribute("stroke-linejoin", "round");
15
+ svg.setAttribute("aria-hidden", "true");
16
+ const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
17
+ path.setAttribute("d", iconPaths[name]);
18
+ svg.append(path);
19
+ return svg;
20
+ }
21
+ var widgetStyles = `
22
+ :host { all: initial; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; color-scheme: light; }
23
+ *, *::before, *::after { box-sizing: border-box; }
24
+ button { font: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; }
25
+ button:focus-visible { outline: 3px solid var(--omni-launcher-bg); outline-offset: 4px; }
26
+ svg { display: block; width: 22px; height: 22px; flex: none; }
27
+ .launcher {
28
+ display: flex; align-items: center; justify-content: center; gap: 10px;
29
+ height: 52px; padding: 0 20px; border: 1px solid rgba(255,255,255,.14);
30
+ border-radius: 999px; background: var(--omni-launcher-bg); color: var(--omni-launcher-fg);
31
+ font-size: 14px; font-weight: 600; line-height: 1; letter-spacing: -.01em;
32
+ box-shadow: 0 6px 24px rgba(0,0,0,.16), 0 2px 6px rgba(0,0,0,.08);
33
+ transition: transform 160ms ease, box-shadow 160ms ease;
34
+ margin-left: auto;
35
+ }
36
+ .launcher:hover { transform: translateY(-2px); box-shadow: 0 10px 28px rgba(0,0,0,.2); }
37
+ .launcher[hidden] { display: none; }
38
+ .launcher[aria-expanded="true"] { width: 52px; padding: 0; }
39
+ .launcher[aria-expanded="true"] .label { display: none; }
40
+ .panel {
41
+ position: absolute; bottom: 66px; right: 0; width: min(392px, calc(100vw - 40px));
42
+ overflow: hidden; border: 1px solid rgba(0,0,0,.08); border-radius: 20px;
43
+ background: var(--omni-panel-bg); box-shadow: 0 24px 80px rgba(0,0,0,.18), 0 4px 16px rgba(0,0,0,.06);
44
+ animation: omni-chat-enter 180ms ease-out;
45
+ }
46
+ .panel[hidden] { display: none; }
47
+ .frame { height: min(780px, calc(100dvh - 112px)); min-height: 240px; }
48
+ .close {
49
+ position: absolute; z-index: 1; top: 18px; right: 14px;
50
+ display: flex; align-items: center; justify-content: center; width: 34px; height: 34px;
51
+ border: 1px solid color-mix(in srgb, var(--omni-panel-fg) 10%, transparent); border-radius: 50%;
52
+ background: var(--omni-panel-bg); color: var(--omni-panel-fg); transition: background 160ms ease;
53
+ }
54
+ .close svg { width: 17px; height: 17px; }
55
+ .close:hover { background: color-mix(in srgb, var(--omni-panel-fg) 6%, var(--omni-panel-bg)); }
56
+ :host([data-position="left"]) .panel { right: auto; left: 0; }
57
+ :host([data-position="left"]) .launcher { margin-left: 0; }
58
+ :host([data-presentation="sidebar"]) .panel {
59
+ position: fixed; top: 0; bottom: 0; right: 0; left: auto;
60
+ width: min(440px, 100vw); border-radius: 0; border-top: 0; border-bottom: 0;
61
+ animation: omni-sidebar-enter 180ms ease-out;
62
+ }
63
+ :host([data-presentation="sidebar"]) .frame { height: 100dvh; min-height: 0; }
64
+ :host([data-presentation="sidebar"][data-position="left"]) .panel {
65
+ right: auto; left: 0; animation-name: omni-sidebar-enter-left;
66
+ }
67
+ @keyframes omni-sidebar-enter { from { opacity: 0; transform: translateX(100%); } to { opacity: 1; transform: none; } }
68
+ @keyframes omni-sidebar-enter-left { from { opacity: 0; transform: translateX(-100%); } to { opacity: 1; transform: none; } }
69
+ @keyframes omni-chat-enter { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }
70
+ @media (max-width: 480px) { :host([data-presentation="floating"]) .panel { width: calc(100vw - 40px); border-radius: 18px; } }
71
+ @media (prefers-reduced-motion: reduce) { .panel, :host([data-presentation="sidebar"]) .panel { animation: none; } .launcher { transition: none; } }
72
+ `;
73
+
74
+ // src/widget.ts
75
+ var widgetSequence = 0;
76
+ function createOmniChatWidget(container, options) {
77
+ getOmniChatEmbedUrl(options);
78
+ const document = container.ownerDocument;
79
+ const root = document.createElement("div");
80
+ root.setAttribute("data-omni-chat-widget", "");
81
+ root.setAttribute("data-position", options.position ?? "right");
82
+ root.setAttribute("data-presentation", options.presentation ?? "floating");
83
+ const shadow = root.attachShadow({ mode: "open" });
84
+ const style = document.createElement("style");
85
+ style.textContent = widgetStyles;
86
+ const launcher = document.createElement("button");
87
+ const panel = document.createElement("section");
88
+ const close = document.createElement("button");
89
+ const frame = document.createElement("div");
90
+ let embed;
91
+ let destroyed = false;
92
+ Object.assign(root.style, {
93
+ position: "fixed",
94
+ bottom: "20px",
95
+ [options.position ?? "right"]: "20px",
96
+ zIndex: "2147483000"
97
+ });
98
+ root.style.setProperty(
99
+ "--omni-launcher-bg",
100
+ options.launcherBackground ?? "#2563eb"
101
+ );
102
+ root.style.setProperty(
103
+ "--omni-launcher-fg",
104
+ options.launcherForeground ?? "#ffffff"
105
+ );
106
+ root.style.setProperty(
107
+ "--omni-panel-bg",
108
+ options.panelBackground ?? "#ffffff"
109
+ );
110
+ root.style.setProperty(
111
+ "--omni-panel-fg",
112
+ options.panelForeground ?? "#171717"
113
+ );
114
+ launcher.type = close.type = "button";
115
+ launcher.className = "launcher";
116
+ const label = document.createElement("span");
117
+ label.className = "label";
118
+ label.textContent = options.launcherLabel ?? "Chat with us";
119
+ launcher.append(widgetIcon(document, "chat"), label);
120
+ launcher.setAttribute("aria-expanded", "false");
121
+ launcher.setAttribute("aria-label", label.textContent);
122
+ panel.hidden = true;
123
+ panel.className = "panel";
124
+ panel.setAttribute("role", "region");
125
+ panel.setAttribute("aria-label", options.title ?? "Assistant chat");
126
+ panel.id = `omni-chat-widget-${++widgetSequence}`;
127
+ launcher.setAttribute("aria-controls", panel.id);
128
+ frame.className = "frame";
129
+ close.className = "close";
130
+ close.setAttribute("aria-label", "Close chat");
131
+ close.title = "Close chat";
132
+ close.append(widgetIcon(document, "close"));
133
+ const closeChat = () => {
134
+ if (destroyed) return;
135
+ panel.hidden = true;
136
+ launcher.hidden = false;
137
+ launcher.setAttribute("aria-expanded", "false");
138
+ launcher.setAttribute("aria-label", label.textContent);
139
+ launcher.querySelector("svg")?.replaceWith(widgetIcon(document, "chat"));
140
+ launcher.focus();
141
+ };
142
+ const openChat = () => {
143
+ if (destroyed) return;
144
+ embed ?? (embed = createOmniChatEmbed(frame, {
145
+ ...options,
146
+ onRequestClose: closeChat
147
+ }));
148
+ embed.iframe.style.minHeight = "0";
149
+ panel.hidden = false;
150
+ launcher.hidden = options.presentation === "sidebar";
151
+ launcher.setAttribute("aria-expanded", "true");
152
+ launcher.setAttribute("aria-label", "Close chat");
153
+ launcher.querySelector("svg")?.replaceWith(widgetIcon(document, "collapse"));
154
+ embed.focus();
155
+ };
156
+ launcher.addEventListener(
157
+ "click",
158
+ () => panel.hidden ? openChat() : closeChat()
159
+ );
160
+ close.addEventListener("click", closeChat);
161
+ shadow.addEventListener("keydown", (event) => {
162
+ if (event.key === "Escape" && !panel.hidden) closeChat();
163
+ });
164
+ panel.append(close, frame);
165
+ shadow.append(style, panel, launcher);
166
+ container.append(root);
167
+ return {
168
+ open: openChat,
169
+ close: closeChat,
170
+ destroy() {
171
+ destroyed = true;
172
+ embed?.destroy();
173
+ root.remove();
174
+ }
175
+ };
176
+ }
177
+
178
+ // src/embed-code.ts
179
+ var scriptJson = (value) => JSON.stringify(value, null, 2).replace(
180
+ /[<>&\u2028\u2029]/g,
181
+ (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`
182
+ );
183
+ function getOmniChatEmbedCode(options, mode = "widget") {
184
+ const baseUrl = new URL(getOmniChatEmbedUrl(options)).origin;
185
+ const config = { ...options, baseUrl };
186
+ const id = `omni-chat-${options.deploymentId}`;
187
+ const mount = mode === "widget" ? `OmniCommerceChat.createOmniChatWidget(document.body, ${scriptJson(config)});` : `OmniCommerceChat.createOmniChatEmbed(document.getElementById(${scriptJson(id)}), ${scriptJson(config)});`;
188
+ return `${mode === "inline" ? `<div id="${id}" style="height:600px"></div>
189
+ ` : ""}<script src="${baseUrl}/sdk/embed.global.js"></script>
190
+ <script>
191
+ ${mount.replace(/\n/g, "\n ")}
192
+ </script>`;
193
+ }
194
+ function getOmniChatReactCode(options) {
195
+ const baseUrl = new URL(getOmniChatEmbedUrl(options)).origin;
196
+ return `import { OmniProvider, OmniChat } from "@omni-commerce/sdk/react";
197
+
198
+ <OmniProvider deploymentId={${scriptJson(options.deploymentId)}}
199
+ baseUrl={${scriptJson(baseUrl)}}${options.title ? `
200
+ title={${scriptJson(options.title)}}` : ""}>
201
+ <OmniChat style={{ height: 600 }} />
202
+ </OmniProvider>`;
203
+ }
204
+
205
+ // src/embed.ts
206
+ function getOmniChatEmbedUrl(options, parentOrigin) {
207
+ if (!/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/i.test(
208
+ options.deploymentId
209
+ ))
210
+ throw new Error("A valid chat deployment ID is required.");
211
+ const base = new URL(options.baseUrl ?? "https://omnicommerce.sg");
212
+ if (base.protocol !== "https:" && !(base.protocol === "http:" && ["localhost", "127.0.0.1"].includes(base.hostname)) || base.username || base.password || base.pathname !== "/" || base.search || base.hash)
213
+ throw new Error("Chat baseUrl must be an HTTPS origin, or HTTP localhost.");
214
+ const url = new URL(`/embed/${options.deploymentId}`, base.origin);
215
+ if (parentOrigin)
216
+ url.searchParams.set("parentOrigin", new URL(parentOrigin).origin);
217
+ return url.toString();
218
+ }
219
+ function createOmniChatEmbed(container, options) {
220
+ const document = container.ownerDocument;
221
+ const host = document.defaultView;
222
+ if (!host) throw new Error("A browser document is required to mount chat.");
223
+ const iframe = document.createElement("iframe");
224
+ iframe.src = getOmniChatEmbedUrl(options, host.location.origin);
225
+ iframe.title = options.title ?? "OmniCommerce assistant";
226
+ iframe.referrerPolicy = "strict-origin-when-cross-origin";
227
+ iframe.setAttribute(
228
+ "sandbox",
229
+ "allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
230
+ );
231
+ Object.assign(iframe.style, {
232
+ width: "100%",
233
+ height: "100%",
234
+ minHeight: "320px",
235
+ border: "0",
236
+ display: "block"
237
+ });
238
+ const chatOrigin = new URL(iframe.src).origin;
239
+ let destroyed = false;
240
+ let pending;
241
+ let previousToken;
242
+ const controller = new AbortController();
243
+ const mint = async () => {
244
+ if (options.getSession) return options.getSession();
245
+ const response = await host.fetch(
246
+ `${chatOrigin}/api/embed/${options.deploymentId}/session`,
247
+ {
248
+ method: "POST",
249
+ credentials: "include",
250
+ signal: controller.signal,
251
+ headers: {
252
+ "Content-Type": "application/json",
253
+ ...previousToken ? { Authorization: `Bearer ${previousToken}` } : {}
254
+ },
255
+ body: "{}"
256
+ }
257
+ );
258
+ const result = await response.json();
259
+ if (!response.ok) {
260
+ if (response.status === 401 || response.status === 403)
261
+ previousToken = void 0;
262
+ throw new Error(result.error ?? "Could not open the chat session.");
263
+ }
264
+ return result;
265
+ };
266
+ const receive = (event) => {
267
+ if (destroyed || event.source !== iframe.contentWindow || event.origin !== chatOrigin || event.data?.deploymentId !== options.deploymentId)
268
+ return;
269
+ if (event.data.type === "omni-chat:close-request") {
270
+ options.onRequestClose?.();
271
+ return;
272
+ }
273
+ if (event.data.type !== "omni-chat:session-request") return;
274
+ pending ?? (pending = mint());
275
+ void pending.then((session) => {
276
+ if (destroyed) return;
277
+ if (typeof session?.token !== "string" || !session.token || session.token.length > 4096 || typeof session.threadId !== "string" || !session.threadId || !Number.isFinite(session.expiresIn) || session.expiresIn <= 0)
278
+ throw new Error("Invalid chat session response.");
279
+ previousToken = session.token;
280
+ iframe.contentWindow?.postMessage(
281
+ {
282
+ type: "omni-chat:session",
283
+ deploymentId: options.deploymentId,
284
+ session
285
+ },
286
+ chatOrigin
287
+ );
288
+ }).catch((error) => {
289
+ if (destroyed) return;
290
+ const failure = error instanceof Error ? error : new Error("Could not open chat.");
291
+ options.onError?.(failure);
292
+ iframe.contentWindow?.postMessage(
293
+ {
294
+ type: "omni-chat:session-error",
295
+ deploymentId: options.deploymentId,
296
+ error: failure.message
297
+ },
298
+ chatOrigin
299
+ );
300
+ }).finally(() => {
301
+ pending = void 0;
302
+ });
303
+ };
304
+ host.addEventListener("message", receive);
305
+ container.append(iframe);
306
+ return {
307
+ iframe,
308
+ focus() {
309
+ if (destroyed) return;
310
+ iframe.focus();
311
+ iframe.contentWindow?.postMessage(
312
+ {
313
+ type: "omni-chat:focus-composer",
314
+ deploymentId: options.deploymentId
315
+ },
316
+ chatOrigin
317
+ );
318
+ },
319
+ destroy() {
320
+ if (destroyed) return;
321
+ destroyed = true;
322
+ controller.abort();
323
+ previousToken = void 0;
324
+ host.removeEventListener("message", receive);
325
+ iframe.remove();
326
+ }
327
+ };
328
+ }
329
+
330
+ export { createOmniChatEmbed, createOmniChatWidget, getOmniChatEmbedCode, getOmniChatEmbedUrl, getOmniChatReactCode };
331
+ //# sourceMappingURL=embed.js.map
332
+ //# sourceMappingURL=embed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/widget-chrome.ts","../src/widget.ts","../src/embed-code.ts","../src/embed.ts"],"names":[],"mappings":"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","file":"embed.js","sourcesContent":["const iconPaths = {\n chat: \"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5Z\",\n close: \"m6 6 12 12M6 18 18 6\",\n collapse: \"m6 9 6 6 6-6\",\n};\n\nexport function widgetIcon(document: Document, name: keyof typeof iconPaths) {\n const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n svg.setAttribute(\"viewBox\", \"0 0 24 24\");\n svg.setAttribute(\"fill\", \"none\");\n svg.setAttribute(\"stroke\", \"currentColor\");\n svg.setAttribute(\"stroke-width\", \"1.8\");\n svg.setAttribute(\"stroke-linecap\", \"round\");\n svg.setAttribute(\"stroke-linejoin\", \"round\");\n svg.setAttribute(\"aria-hidden\", \"true\");\n const path = document.createElementNS(\"http://www.w3.org/2000/svg\", \"path\");\n path.setAttribute(\"d\", iconPaths[name]);\n svg.append(path);\n return svg;\n}\n\n/** Shadow DOM keeps a store's button, font and section CSS out of the widget. */\nexport const widgetStyles = `\n :host { all: initial; font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; color-scheme: light; }\n *, *::before, *::after { box-sizing: border-box; }\n button { font: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; }\n button:focus-visible { outline: 3px solid var(--omni-launcher-bg); outline-offset: 4px; }\n svg { display: block; width: 22px; height: 22px; flex: none; }\n .launcher {\n display: flex; align-items: center; justify-content: center; gap: 10px;\n height: 52px; padding: 0 20px; border: 1px solid rgba(255,255,255,.14);\n border-radius: 999px; background: var(--omni-launcher-bg); color: var(--omni-launcher-fg);\n font-size: 14px; font-weight: 600; line-height: 1; letter-spacing: -.01em;\n box-shadow: 0 6px 24px rgba(0,0,0,.16), 0 2px 6px rgba(0,0,0,.08);\n transition: transform 160ms ease, box-shadow 160ms ease;\n margin-left: auto;\n }\n .launcher:hover { transform: translateY(-2px); box-shadow: 0 10px 28px rgba(0,0,0,.2); }\n .launcher[hidden] { display: none; }\n .launcher[aria-expanded=\"true\"] { width: 52px; padding: 0; }\n .launcher[aria-expanded=\"true\"] .label { display: none; }\n .panel {\n position: absolute; bottom: 66px; right: 0; width: min(392px, calc(100vw - 40px));\n overflow: hidden; border: 1px solid rgba(0,0,0,.08); border-radius: 20px;\n background: var(--omni-panel-bg); box-shadow: 0 24px 80px rgba(0,0,0,.18), 0 4px 16px rgba(0,0,0,.06);\n animation: omni-chat-enter 180ms ease-out;\n }\n .panel[hidden] { display: none; }\n .frame { height: min(780px, calc(100dvh - 112px)); min-height: 240px; }\n .close {\n position: absolute; z-index: 1; top: 18px; right: 14px;\n display: flex; align-items: center; justify-content: center; width: 34px; height: 34px;\n border: 1px solid color-mix(in srgb, var(--omni-panel-fg) 10%, transparent); border-radius: 50%;\n background: var(--omni-panel-bg); color: var(--omni-panel-fg); transition: background 160ms ease;\n }\n .close svg { width: 17px; height: 17px; }\n .close:hover { background: color-mix(in srgb, var(--omni-panel-fg) 6%, var(--omni-panel-bg)); }\n :host([data-position=\"left\"]) .panel { right: auto; left: 0; }\n :host([data-position=\"left\"]) .launcher { margin-left: 0; }\n :host([data-presentation=\"sidebar\"]) .panel {\n position: fixed; top: 0; bottom: 0; right: 0; left: auto;\n width: min(440px, 100vw); border-radius: 0; border-top: 0; border-bottom: 0;\n animation: omni-sidebar-enter 180ms ease-out;\n }\n :host([data-presentation=\"sidebar\"]) .frame { height: 100dvh; min-height: 0; }\n :host([data-presentation=\"sidebar\"][data-position=\"left\"]) .panel {\n right: auto; left: 0; animation-name: omni-sidebar-enter-left;\n }\n @keyframes omni-sidebar-enter { from { opacity: 0; transform: translateX(100%); } to { opacity: 1; transform: none; } }\n @keyframes omni-sidebar-enter-left { from { opacity: 0; transform: translateX(-100%); } to { opacity: 1; transform: none; } }\n @keyframes omni-chat-enter { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }\n @media (max-width: 480px) { :host([data-presentation=\"floating\"]) .panel { width: calc(100vw - 40px); border-radius: 18px; } }\n @media (prefers-reduced-motion: reduce) { .panel, :host([data-presentation=\"sidebar\"]) .panel { animation: none; } .launcher { transition: none; } }\n`;\n","import {\n createOmniChatEmbed,\n getOmniChatEmbedUrl,\n type OmniChatEmbedOptions,\n type OmniChatEmbed,\n} from \"./embed\";\nimport { widgetIcon, widgetStyles } from \"./widget-chrome\";\n\nexport type OmniChatWidgetOptions = OmniChatEmbedOptions & {\n /** Floating window by default; sidebar fills the viewport height. */\n presentation?: \"floating\" | \"sidebar\";\n launcherLabel?: string;\n position?: \"left\" | \"right\";\n launcherBackground?: string;\n launcherForeground?: string;\n panelBackground?: string;\n panelForeground?: string;\n};\nlet widgetSequence = 0;\n/** A website launcher using the same hosted assistant as OmniChat. */\nexport function createOmniChatWidget(\n container: HTMLElement,\n options: OmniChatWidgetOptions,\n) {\n getOmniChatEmbedUrl(options);\n const document = container.ownerDocument;\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-omni-chat-widget\", \"\");\n root.setAttribute(\"data-position\", options.position ?? \"right\");\n root.setAttribute(\"data-presentation\", options.presentation ?? \"floating\");\n const shadow = root.attachShadow({ mode: \"open\" });\n const style = document.createElement(\"style\");\n style.textContent = widgetStyles;\n const launcher = document.createElement(\"button\");\n const panel = document.createElement(\"section\");\n const close = document.createElement(\"button\");\n const frame = document.createElement(\"div\");\n let embed: OmniChatEmbed | undefined;\n let destroyed = false;\n Object.assign(root.style, {\n position: \"fixed\",\n bottom: \"20px\",\n [options.position ?? \"right\"]: \"20px\",\n zIndex: \"2147483000\",\n });\n root.style.setProperty(\n \"--omni-launcher-bg\",\n options.launcherBackground ?? \"#2563eb\",\n );\n root.style.setProperty(\n \"--omni-launcher-fg\",\n options.launcherForeground ?? \"#ffffff\",\n );\n root.style.setProperty(\n \"--omni-panel-bg\",\n options.panelBackground ?? \"#ffffff\",\n );\n root.style.setProperty(\n \"--omni-panel-fg\",\n options.panelForeground ?? \"#171717\",\n );\n launcher.type = close.type = \"button\";\n launcher.className = \"launcher\";\n const label = document.createElement(\"span\");\n label.className = \"label\";\n label.textContent = options.launcherLabel ?? \"Chat with us\";\n launcher.append(widgetIcon(document, \"chat\"), label);\n launcher.setAttribute(\"aria-expanded\", \"false\");\n launcher.setAttribute(\"aria-label\", label.textContent);\n panel.hidden = true;\n panel.className = \"panel\";\n panel.setAttribute(\"role\", \"region\");\n panel.setAttribute(\"aria-label\", options.title ?? \"Assistant chat\");\n panel.id = `omni-chat-widget-${++widgetSequence}`;\n launcher.setAttribute(\"aria-controls\", panel.id);\n frame.className = \"frame\";\n close.className = \"close\";\n close.setAttribute(\"aria-label\", \"Close chat\");\n close.title = \"Close chat\";\n close.append(widgetIcon(document, \"close\"));\n const closeChat = () => {\n if (destroyed) return;\n panel.hidden = true;\n launcher.hidden = false;\n launcher.setAttribute(\"aria-expanded\", \"false\");\n launcher.setAttribute(\"aria-label\", label.textContent!);\n launcher.querySelector(\"svg\")?.replaceWith(widgetIcon(document, \"chat\"));\n launcher.focus();\n };\n const openChat = () => {\n if (destroyed) return;\n embed ??= createOmniChatEmbed(frame, {\n ...options,\n onRequestClose: closeChat,\n });\n embed.iframe.style.minHeight = \"0\";\n panel.hidden = false;\n launcher.hidden = options.presentation === \"sidebar\";\n launcher.setAttribute(\"aria-expanded\", \"true\");\n launcher.setAttribute(\"aria-label\", \"Close chat\");\n launcher\n .querySelector(\"svg\")\n ?.replaceWith(widgetIcon(document, \"collapse\"));\n embed.focus();\n };\n launcher.addEventListener(\"click\", () =>\n panel.hidden ? openChat() : closeChat(),\n );\n close.addEventListener(\"click\", closeChat);\n shadow.addEventListener(\"keydown\", (event) => {\n if ((event as KeyboardEvent).key === \"Escape\" && !panel.hidden) closeChat();\n });\n panel.append(close, frame);\n shadow.append(style, panel, launcher);\n container.append(root);\n return {\n open: openChat,\n close: closeChat,\n destroy() {\n destroyed = true;\n embed?.destroy();\n root.remove();\n },\n };\n}\n","import { getOmniChatEmbedUrl, type OmniChatEmbedOptions } from \"./embed\";\nimport type { OmniChatWidgetOptions } from \"./widget\";\n\ntype EmbedCodeOptions = Pick<\n OmniChatEmbedOptions,\n \"baseUrl\" | \"deploymentId\" | \"title\"\n> &\n Pick<\n OmniChatWidgetOptions,\n | \"presentation\"\n | \"launcherLabel\"\n | \"position\"\n | \"launcherBackground\"\n | \"launcherForeground\"\n | \"panelBackground\"\n | \"panelForeground\"\n >;\nconst scriptJson = (value: unknown) =>\n JSON.stringify(value, null, 2).replace(\n /[<>&\\u2028\\u2029]/g,\n (character) =>\n `\\\\u${character.charCodeAt(0).toString(16).padStart(4, \"0\")}`,\n );\n\n/** Copyable integrations contain only public deployment configuration. */\nexport function getOmniChatEmbedCode(\n options: EmbedCodeOptions,\n mode: \"widget\" | \"inline\" = \"widget\",\n) {\n const baseUrl = new URL(getOmniChatEmbedUrl(options)).origin;\n const config = { ...options, baseUrl };\n const id = `omni-chat-${options.deploymentId}`;\n const mount =\n mode === \"widget\"\n ? `OmniCommerceChat.createOmniChatWidget(document.body, ${scriptJson(config)});`\n : `OmniCommerceChat.createOmniChatEmbed(document.getElementById(${scriptJson(id)}), ${scriptJson(config)});`;\n return `${mode === \"inline\" ? `<div id=\"${id}\" style=\"height:600px\"></div>\\n` : \"\"}<script src=\"${baseUrl}/sdk/embed.global.js\"></script>\\n<script>\\n ${mount.replace(/\\n/g, \"\\n \")}\\n</script>`;\n}\nexport function getOmniChatReactCode(options: EmbedCodeOptions) {\n const baseUrl = new URL(getOmniChatEmbedUrl(options)).origin;\n return `import { OmniProvider, OmniChat } from \"@omni-commerce/sdk/react\";\\n\\n<OmniProvider deploymentId={${scriptJson(options.deploymentId)}}\\n baseUrl={${scriptJson(baseUrl)}}${options.title ? `\\n title={${scriptJson(options.title)}}` : \"\"}>\\n <OmniChat style={{ height: 600 }} />\\n</OmniProvider>`;\n}\n","/** A hosted chat session. Keep its short-lived token in memory, never in iframe URLs. */\nexport { createOmniChatWidget, type OmniChatWidgetOptions } from \"./widget\";\nexport { getOmniChatEmbedCode, getOmniChatReactCode } from \"./embed-code\";\nexport interface OmniChatSession {\n token: string;\n threadId: string;\n expiresIn: number;\n}\nexport interface OmniChatEmbedOptions {\n deploymentId: string;\n baseUrl?: string;\n /** Optional authenticated session mint on the host application's server. */\n getSession?: () => Promise<OmniChatSession>;\n title?: string;\n onError?: (error: Error) => void;\n /** Floating widgets use this to close on Escape from the hosted chat. */\n onRequestClose?: () => void;\n}\nexport interface OmniChatEmbed {\n iframe: HTMLIFrameElement;\n /** Focus the hosted composer, including when reopening a retained chat. */\n focus(): void;\n destroy(): void;\n}\n\nexport function getOmniChatEmbedUrl(\n options: Pick<OmniChatEmbedOptions, \"baseUrl\" | \"deploymentId\">,\n parentOrigin?: string,\n): string {\n if (\n !/^[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}$/i.test(\n options.deploymentId,\n )\n )\n throw new Error(\"A valid chat deployment ID is required.\");\n const base = new URL(options.baseUrl ?? \"https://omnicommerce.sg\");\n if (\n (base.protocol !== \"https:\" &&\n !(\n base.protocol === \"http:\" &&\n [\"localhost\", \"127.0.0.1\"].includes(base.hostname)\n )) ||\n base.username ||\n base.password ||\n base.pathname !== \"/\" ||\n base.search ||\n base.hash\n )\n throw new Error(\"Chat baseUrl must be an HTTPS origin, or HTTP localhost.\");\n const url = new URL(`/embed/${options.deploymentId}`, base.origin);\n if (parentOrigin)\n url.searchParams.set(\"parentOrigin\", new URL(parentOrigin).origin);\n return url.toString();\n}\n\n/** Browser-only mounting; importing this entry point is safe during SSR. */\nexport function createOmniChatEmbed(\n container: HTMLElement,\n options: OmniChatEmbedOptions,\n): OmniChatEmbed {\n const document = container.ownerDocument;\n const host = document.defaultView;\n if (!host) throw new Error(\"A browser document is required to mount chat.\");\n const iframe = document.createElement(\"iframe\");\n iframe.src = getOmniChatEmbedUrl(options, host.location.origin);\n iframe.title = options.title ?? \"OmniCommerce assistant\";\n iframe.referrerPolicy = \"strict-origin-when-cross-origin\";\n iframe.setAttribute(\n \"sandbox\",\n \"allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox\",\n );\n Object.assign(iframe.style, {\n width: \"100%\",\n height: \"100%\",\n minHeight: \"320px\",\n border: \"0\",\n display: \"block\",\n });\n const chatOrigin = new URL(iframe.src).origin;\n let destroyed = false;\n let pending: Promise<OmniChatSession> | undefined;\n let previousToken: string | undefined;\n const controller = new AbortController();\n\n const mint = async (): Promise<OmniChatSession> => {\n if (options.getSession) return options.getSession();\n const response = await host.fetch(\n `${chatOrigin}/api/embed/${options.deploymentId}/session`,\n {\n method: \"POST\",\n credentials: \"include\",\n signal: controller.signal,\n headers: {\n \"Content-Type\": \"application/json\",\n ...(previousToken\n ? { Authorization: `Bearer ${previousToken}` }\n : {}),\n },\n body: \"{}\",\n },\n );\n const result = (await response.json()) as OmniChatSession & {\n error?: string;\n };\n if (!response.ok) {\n // A rejected renewal must not keep Retry bound to an obsolete session.\n // The next mint still performs the deployment's full access checks.\n if (response.status === 401 || response.status === 403)\n previousToken = undefined;\n throw new Error(result.error ?? \"Could not open the chat session.\");\n }\n return result;\n };\n const receive = (event: MessageEvent) => {\n if (\n destroyed ||\n event.source !== iframe.contentWindow ||\n event.origin !== chatOrigin ||\n event.data?.deploymentId !== options.deploymentId\n )\n return;\n if (event.data.type === \"omni-chat:close-request\") {\n options.onRequestClose?.();\n return;\n }\n if (event.data.type !== \"omni-chat:session-request\") return;\n pending ??= mint();\n void pending\n .then((session) => {\n if (destroyed) return;\n if (\n typeof session?.token !== \"string\" ||\n !session.token ||\n session.token.length > 4096 ||\n typeof session.threadId !== \"string\" ||\n !session.threadId ||\n !Number.isFinite(session.expiresIn) ||\n session.expiresIn <= 0\n )\n throw new Error(\"Invalid chat session response.\");\n previousToken = session.token;\n iframe.contentWindow?.postMessage(\n {\n type: \"omni-chat:session\",\n deploymentId: options.deploymentId,\n session,\n },\n chatOrigin,\n );\n })\n .catch((error: unknown) => {\n if (destroyed) return;\n const failure =\n error instanceof Error ? error : new Error(\"Could not open chat.\");\n options.onError?.(failure);\n iframe.contentWindow?.postMessage(\n {\n type: \"omni-chat:session-error\",\n deploymentId: options.deploymentId,\n error: failure.message,\n },\n chatOrigin,\n );\n })\n .finally(() => {\n pending = undefined;\n });\n };\n host.addEventListener(\"message\", receive);\n container.append(iframe);\n return {\n iframe,\n focus() {\n if (destroyed) return;\n iframe.focus();\n iframe.contentWindow?.postMessage(\n {\n type: \"omni-chat:focus-composer\",\n deploymentId: options.deploymentId,\n },\n chatOrigin,\n );\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\n controller.abort();\n previousToken = undefined;\n host.removeEventListener(\"message\", receive);\n iframe.remove();\n },\n };\n}\n"]}