@omni-commerce/sdk 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.cjs CHANGED
@@ -27,6 +27,89 @@ __export(react_exports, {
27
27
  module.exports = __toCommonJS(react_exports);
28
28
  var import_react = require("react");
29
29
 
30
+ // src/application.ts
31
+ function boundedJson(value, maximum) {
32
+ const encoded = JSON.stringify(value);
33
+ if (typeof encoded !== "string" || new TextEncoder().encode(encoded).length > maximum || /data:[^"\s]{0,100};base64,/i.test(encoded))
34
+ throw new Error(
35
+ "Application data must be bounded JSON without base64 payloads."
36
+ );
37
+ return JSON.parse(encoded);
38
+ }
39
+ function createApplicationMessageHandler(input) {
40
+ const calls = /* @__PURE__ */ new Map();
41
+ return async (message) => {
42
+ if (typeof message.requestId !== "string" || message.requestId.length > 200)
43
+ return;
44
+ try {
45
+ if (message.type === "omni-chat:application-request") {
46
+ const application = input.options.application;
47
+ input.reply({
48
+ type: "omni-chat:application-response",
49
+ requestId: message.requestId,
50
+ application: application ? boundedJson(
51
+ {
52
+ name: application.name,
53
+ description: application.description,
54
+ context: await application.getContext() ?? null,
55
+ tools: Object.entries(input.options.frontendTools ?? {}).map(
56
+ ([name, definition]) => ({
57
+ name,
58
+ description: definition.description,
59
+ parameters: definition.parameters
60
+ })
61
+ )
62
+ },
63
+ 65536
64
+ ) : void 0
65
+ });
66
+ } else if (message.type === "omni-chat:tool-request") {
67
+ const name = message.toolName;
68
+ const toolCallId = message.toolCallId;
69
+ if (typeof name !== "string" || !/^app_[a-z][a-z0-9_]{0,59}$/.test(name) || typeof toolCallId !== "string" || !toolCallId || toolCallId.length > 200)
70
+ throw new Error("Invalid application tool request.");
71
+ const definition = Object.hasOwn(
72
+ input.options.frontendTools ?? {},
73
+ name
74
+ ) ? input.options.frontendTools?.[name] : void 0;
75
+ if (!input.options.application || !definition)
76
+ throw new Error("This application action is unavailable.");
77
+ const args = message.args;
78
+ if (!args || typeof args !== "object" || Array.isArray(args))
79
+ throw new Error("Invalid application action arguments.");
80
+ const signature = JSON.stringify({ name, args });
81
+ const prior = calls.get(toolCallId);
82
+ if (prior && prior.signature !== signature)
83
+ throw new Error("This tool call ID was already used.");
84
+ const result = prior?.result ?? Promise.resolve().then(
85
+ () => definition.execute(args, {
86
+ toolCallId,
87
+ abortSignal: input.signal
88
+ })
89
+ );
90
+ if (!prior) {
91
+ if (calls.size >= 200)
92
+ throw new Error("Start a new application chat.");
93
+ calls.set(toolCallId, { signature, result });
94
+ }
95
+ input.reply({
96
+ type: "omni-chat:tool-response",
97
+ requestId: message.requestId,
98
+ toolCallId,
99
+ result: boundedJson(await result ?? null, 12e3)
100
+ });
101
+ }
102
+ } catch (error) {
103
+ input.reply({
104
+ type: message.type === "omni-chat:application-request" ? "omni-chat:application-response" : "omni-chat:tool-response",
105
+ requestId: message.requestId,
106
+ toolCallId: message.toolCallId,
107
+ error: error instanceof Error ? error.message : "The application action failed."
108
+ });
109
+ }
110
+ };
111
+ }
112
+
30
113
  // src/embed.ts
31
114
  function getOmniChatEmbedUrl(options, parentOrigin) {
32
115
  if (!/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/i.test(
@@ -88,9 +171,24 @@ function createOmniChatEmbed(container, options) {
88
171
  }
89
172
  return result;
90
173
  };
174
+ const applicationMessage = createApplicationMessageHandler({
175
+ options,
176
+ signal: controller.signal,
177
+ reply: (message) => {
178
+ if (!destroyed)
179
+ iframe.contentWindow?.postMessage(
180
+ { ...message, deploymentId: options.deploymentId },
181
+ chatOrigin
182
+ );
183
+ }
184
+ });
91
185
  const receive = (event) => {
92
186
  if (destroyed || event.source !== iframe.contentWindow || event.origin !== chatOrigin || event.data?.deploymentId !== options.deploymentId)
93
187
  return;
188
+ if (event.data.type === "omni-chat:application-request" || event.data.type === "omni-chat:tool-request") {
189
+ void applicationMessage(event.data);
190
+ return;
191
+ }
94
192
  if (event.data.type === "omni-chat:close-request") {
95
193
  options.onRequestClose?.();
96
194
  return;
@@ -106,7 +204,8 @@ function createOmniChatEmbed(container, options) {
106
204
  {
107
205
  type: "omni-chat:session",
108
206
  deploymentId: options.deploymentId,
109
- session
207
+ session,
208
+ ...options.application ? { applicationEnabled: true } : {}
110
209
  },
111
210
  chatOrigin
112
211
  );
@@ -118,7 +217,8 @@ function createOmniChatEmbed(container, options) {
118
217
  {
119
218
  type: "omni-chat:session-error",
120
219
  deploymentId: options.deploymentId,
121
- error: failure.message
220
+ error: failure.message,
221
+ ...options.application ? { applicationEnabled: true } : {}
122
222
  },
123
223
  chatOrigin
124
224
  );
@@ -163,11 +263,18 @@ function OmniChat({ className, style, title }) {
163
263
  if (!options)
164
264
  throw new Error("OmniChat must be rendered inside OmniProvider.");
165
265
  const container = (0, import_react.useRef)(null);
166
- const { baseUrl, deploymentId, getSession, onError } = options;
167
- const callbacks = (0, import_react.useRef)({ getSession, onError });
266
+ const {
267
+ baseUrl,
268
+ deploymentId,
269
+ getSession,
270
+ onError,
271
+ application,
272
+ frontendTools
273
+ } = options;
274
+ const callbacks = (0, import_react.useRef)({ getSession, onError, application, frontendTools });
168
275
  (0, import_react.useEffect)(() => {
169
- callbacks.current = { getSession, onError };
170
- }, [getSession, onError]);
276
+ callbacks.current = { getSession, onError, application, frontendTools };
277
+ }, [getSession, onError, application, frontendTools]);
171
278
  const hasSessionBroker = Boolean(getSession);
172
279
  const frameTitle = title ?? options.title;
173
280
  (0, import_react.useEffect)(() => {
@@ -177,7 +284,13 @@ function OmniChat({ className, style, title }) {
177
284
  deploymentId,
178
285
  getSession: hasSessionBroker ? () => callbacks.current.getSession() : void 0,
179
286
  onError: (error) => callbacks.current.onError?.(error),
180
- title: frameTitle
287
+ title: frameTitle,
288
+ get application() {
289
+ return callbacks.current.application;
290
+ },
291
+ get frontendTools() {
292
+ return callbacks.current.frontendTools;
293
+ }
181
294
  });
182
295
  return () => embed.destroy();
183
296
  }, [baseUrl, deploymentId, frameTitle, hasSessionBroker]);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react.tsx","../src/embed.ts"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useContext,\n useEffect,\n useRef,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { createOmniChatEmbed, type OmniChatEmbedOptions } from \"./embed\";\n\nconst OmniChatContext = createContext<OmniChatEmbedOptions | null>(null);\nexport type OmniProviderProps = OmniChatEmbedOptions & { children: ReactNode };\n\nexport function OmniProvider({ children, ...options }: OmniProviderProps) {\n return (\n <OmniChatContext.Provider value={options}>\n {children}\n </OmniChatContext.Provider>\n );\n}\nexport interface OmniChatProps {\n className?: string;\n style?: CSSProperties;\n title?: string;\n}\n/** The hosted assistant owns its styles and runtime, so the host needs no Tailwind or assistant-ui dependencies. */\nexport function OmniChat({ className, style, title }: OmniChatProps) {\n const options = useContext(OmniChatContext);\n if (!options)\n throw new Error(\"OmniChat must be rendered inside OmniProvider.\");\n const container = useRef<HTMLDivElement>(null);\n const { baseUrl, deploymentId, getSession, onError } = options;\n const callbacks = useRef({ getSession, onError });\n useEffect(() => {\n callbacks.current = { getSession, onError };\n }, [getSession, onError]);\n const hasSessionBroker = Boolean(getSession);\n const frameTitle = title ?? options.title;\n useEffect(() => {\n if (!container.current) return;\n const embed = createOmniChatEmbed(container.current, {\n baseUrl,\n deploymentId,\n getSession: hasSessionBroker\n ? () => callbacks.current.getSession!()\n : undefined,\n onError: (error) => callbacks.current.onError?.(error),\n title: frameTitle,\n });\n return () => embed.destroy();\n }, [baseUrl, deploymentId, frameTitle, hasSessionBroker]);\n return (\n <div\n ref={container}\n className={className}\n style={{ height: \"100%\", minHeight: 320, ...style }}\n />\n );\n}\nexport type { OmniChatEmbedOptions, OmniChatSession } from \"./embed\";\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"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,mBAOO;;;ACgBA,SAAS,oBACd,SACA,cACQ;AACR,MACE,CAAC,6DAA6D;AAAA,IAC5D,QAAQ;AAAA,EACV;AAEA,UAAM,IAAI,MAAM,yCAAyC;AAC3D,QAAM,OAAO,IAAI,IAAI,QAAQ,WAAW,yBAAyB;AACjE,MACG,KAAK,aAAa,YACjB,EACE,KAAK,aAAa,WAClB,CAAC,aAAa,WAAW,EAAE,SAAS,KAAK,QAAQ,MAErD,KAAK,YACL,KAAK,YACL,KAAK,aAAa,OAClB,KAAK,UACL,KAAK;AAEL,UAAM,IAAI,MAAM,0DAA0D;AAC5E,QAAM,MAAM,IAAI,IAAI,UAAU,QAAQ,YAAY,IAAI,KAAK,MAAM;AACjE,MAAI;AACF,QAAI,aAAa,IAAI,gBAAgB,IAAI,IAAI,YAAY,EAAE,MAAM;AACnE,SAAO,IAAI,SAAS;AACtB;AAGO,SAAS,oBACd,WACA,SACe;AACf,QAAM,WAAW,UAAU;AAC3B,QAAM,OAAO,SAAS;AACtB,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,+CAA+C;AAC1E,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,MAAM,oBAAoB,SAAS,KAAK,SAAS,MAAM;AAC9D,SAAO,QAAQ,QAAQ,SAAS;AAChC,SAAO,iBAAiB;AACxB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACA,SAAO,OAAO,OAAO,OAAO;AAAA,IAC1B,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,EACX,CAAC;AACD,QAAM,aAAa,IAAI,IAAI,OAAO,GAAG,EAAE;AACvC,MAAI,YAAY;AAChB,MAAI;AACJ,MAAI;AACJ,QAAM,aAAa,IAAI,gBAAgB;AAEvC,QAAM,OAAO,YAAsC;AACjD,QAAI,QAAQ,WAAY,QAAO,QAAQ,WAAW;AAClD,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B,GAAG,UAAU,cAAc,QAAQ,YAAY;AAAA,MAC/C;AAAA,QACE,QAAQ;AAAA,QACR,aAAa;AAAA,QACb,QAAQ,WAAW;AAAA,QACnB,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,GAAI,gBACA,EAAE,eAAe,UAAU,aAAa,GAAG,IAC3C,CAAC;AAAA,QACP;AAAA,QACA,MAAM;AAAA,MACR;AAAA,IACF;AACA,UAAM,SAAU,MAAM,SAAS,KAAK;AAGpC,QAAI,CAAC,SAAS,IAAI;AAGhB,UAAI,SAAS,WAAW,OAAO,SAAS,WAAW;AACjD,wBAAgB;AAClB,YAAM,IAAI,MAAM,OAAO,SAAS,kCAAkC;AAAA,IACpE;AACA,WAAO;AAAA,EACT;AACA,QAAM,UAAU,CAAC,UAAwB;AACvC,QACE,aACA,MAAM,WAAW,OAAO,iBACxB,MAAM,WAAW,cACjB,MAAM,MAAM,iBAAiB,QAAQ;AAErC;AACF,QAAI,MAAM,KAAK,SAAS,2BAA2B;AACjD,cAAQ,iBAAiB;AACzB;AAAA,IACF;AACA,QAAI,MAAM,KAAK,SAAS,4BAA6B;AACrD,0BAAY,KAAK;AACjB,SAAK,QACF,KAAK,CAAC,YAAY;AACjB,UAAI,UAAW;AACf,UACE,OAAO,SAAS,UAAU,YAC1B,CAAC,QAAQ,SACT,QAAQ,MAAM,SAAS,QACvB,OAAO,QAAQ,aAAa,YAC5B,CAAC,QAAQ,YACT,CAAC,OAAO,SAAS,QAAQ,SAAS,KAClC,QAAQ,aAAa;AAErB,cAAM,IAAI,MAAM,gCAAgC;AAClD,sBAAgB,QAAQ;AACxB,aAAO,eAAe;AAAA,QACpB;AAAA,UACE,MAAM;AAAA,UACN,cAAc,QAAQ;AAAA,UACtB;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,UAAI,UAAW;AACf,YAAM,UACJ,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,sBAAsB;AACnE,cAAQ,UAAU,OAAO;AACzB,aAAO,eAAe;AAAA,QACpB;AAAA,UACE,MAAM;AAAA,UACN,cAAc,QAAQ;AAAA,UACtB,OAAO,QAAQ;AAAA,QACjB;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC,EACA,QAAQ,MAAM;AACb,gBAAU;AAAA,IACZ,CAAC;AAAA,EACL;AACA,OAAK,iBAAiB,WAAW,OAAO;AACxC,YAAU,OAAO,MAAM;AACvB,SAAO;AAAA,IACL;AAAA,IACA,QAAQ;AACN,UAAI,UAAW;AACf,aAAO,MAAM;AACb,aAAO,eAAe;AAAA,QACpB;AAAA,UACE,MAAM;AAAA,UACN,cAAc,QAAQ;AAAA,QACxB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA,UAAU;AACR,UAAI,UAAW;AACf,kBAAY;AACZ,iBAAW,MAAM;AACjB,sBAAgB;AAChB,WAAK,oBAAoB,WAAW,OAAO;AAC3C,aAAO,OAAO;AAAA,IAChB;AAAA,EACF;AACF;;;AD/KI;AALJ,IAAM,sBAAkB,4BAA2C,IAAI;AAGhE,SAAS,aAAa,EAAE,UAAU,GAAG,QAAQ,GAAsB;AACxE,SACE,4CAAC,gBAAgB,UAAhB,EAAyB,OAAO,SAC9B,UACH;AAEJ;AAOO,SAAS,SAAS,EAAE,WAAW,OAAO,MAAM,GAAkB;AACnE,QAAM,cAAU,yBAAW,eAAe;AAC1C,MAAI,CAAC;AACH,UAAM,IAAI,MAAM,gDAAgD;AAClE,QAAM,gBAAY,qBAAuB,IAAI;AAC7C,QAAM,EAAE,SAAS,cAAc,YAAY,QAAQ,IAAI;AACvD,QAAM,gBAAY,qBAAO,EAAE,YAAY,QAAQ,CAAC;AAChD,8BAAU,MAAM;AACd,cAAU,UAAU,EAAE,YAAY,QAAQ;AAAA,EAC5C,GAAG,CAAC,YAAY,OAAO,CAAC;AACxB,QAAM,mBAAmB,QAAQ,UAAU;AAC3C,QAAM,aAAa,SAAS,QAAQ;AACpC,8BAAU,MAAM;AACd,QAAI,CAAC,UAAU,QAAS;AACxB,UAAM,QAAQ,oBAAoB,UAAU,SAAS;AAAA,MACnD;AAAA,MACA;AAAA,MACA,YAAY,mBACR,MAAM,UAAU,QAAQ,WAAY,IACpC;AAAA,MACJ,SAAS,CAAC,UAAU,UAAU,QAAQ,UAAU,KAAK;AAAA,MACrD,OAAO;AAAA,IACT,CAAC;AACD,WAAO,MAAM,MAAM,QAAQ;AAAA,EAC7B,GAAG,CAAC,SAAS,cAAc,YAAY,gBAAgB,CAAC;AACxD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL;AAAA,MACA,OAAO,EAAE,QAAQ,QAAQ,WAAW,KAAK,GAAG,MAAM;AAAA;AAAA,EACpD;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/react.tsx","../src/application.ts","../src/embed.ts"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useContext,\n useEffect,\n useRef,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { createOmniChatEmbed, type OmniChatEmbedOptions } from \"./embed\";\n\nconst OmniChatContext = createContext<OmniChatEmbedOptions | null>(null);\nexport type OmniProviderProps = OmniChatEmbedOptions & { children: ReactNode };\n\nexport function OmniProvider({ children, ...options }: OmniProviderProps) {\n return (\n <OmniChatContext.Provider value={options}>\n {children}\n </OmniChatContext.Provider>\n );\n}\nexport interface OmniChatProps {\n className?: string;\n style?: CSSProperties;\n title?: string;\n}\n/** The hosted assistant owns its styles and runtime, so the host needs no Tailwind or assistant-ui dependencies. */\nexport function OmniChat({ className, style, title }: OmniChatProps) {\n const options = useContext(OmniChatContext);\n if (!options)\n throw new Error(\"OmniChat must be rendered inside OmniProvider.\");\n const container = useRef<HTMLDivElement>(null);\n const {\n baseUrl,\n deploymentId,\n getSession,\n onError,\n application,\n frontendTools,\n } = options;\n const callbacks = useRef({ getSession, onError, application, frontendTools });\n useEffect(() => {\n callbacks.current = { getSession, onError, application, frontendTools };\n }, [getSession, onError, application, frontendTools]);\n const hasSessionBroker = Boolean(getSession);\n const frameTitle = title ?? options.title;\n useEffect(() => {\n if (!container.current) return;\n const embed = createOmniChatEmbed(container.current, {\n baseUrl,\n deploymentId,\n getSession: hasSessionBroker\n ? () => callbacks.current.getSession!()\n : undefined,\n onError: (error) => callbacks.current.onError?.(error),\n title: frameTitle,\n get application() {\n return callbacks.current.application;\n },\n get frontendTools() {\n return callbacks.current.frontendTools;\n },\n });\n return () => embed.destroy();\n }, [baseUrl, deploymentId, frameTitle, hasSessionBroker]);\n return (\n <div\n ref={container}\n className={className}\n style={{ height: \"100%\", minHeight: 320, ...style }}\n />\n );\n}\nexport type {\n OmniFrontendTool,\n OmniChatApplication,\n OmniApplicationOptions,\n OmniChatEmbedOptions,\n OmniChatSession,\n} from \"./embed\";\n","/** Host-defined actions execute inside the application, never on the assistant server. */\nexport interface OmniFrontendTool {\n description: string;\n parameters: Record<string, unknown>;\n execute: (\n args: Record<string, unknown>,\n context: { toolCallId: string; abortSignal: AbortSignal },\n ) => unknown | Promise<unknown>;\n}\nexport interface OmniChatApplication {\n name: string;\n description: string;\n /** Return a small, explicitly selected snapshot. Do not include secrets. */\n getContext: () => unknown | Promise<unknown>;\n}\nexport interface OmniApplicationOptions {\n application?: OmniChatApplication;\n /** Names must start with app_; use array arguments for actions with multiple targets. */\n frontendTools?: Record<string, OmniFrontendTool>;\n}\n\nfunction boundedJson(value: unknown, maximum: number): unknown {\n const encoded = JSON.stringify(value);\n if (\n typeof encoded !== \"string\" ||\n new TextEncoder().encode(encoded).length > maximum ||\n /data:[^\"\\s]{0,100};base64,/i.test(encoded)\n )\n throw new Error(\n \"Application data must be bounded JSON without base64 payloads.\",\n );\n return JSON.parse(encoded);\n}\n\nexport function createApplicationMessageHandler(input: {\n options: OmniApplicationOptions;\n signal: AbortSignal;\n reply: (message: Record<string, unknown>) => void;\n}) {\n // A repeated parked call reuses its result instead of applying an action twice.\n const calls = new Map<\n string,\n { signature: string; result: Promise<unknown> }\n >();\n return async (message: Record<string, unknown>) => {\n if (typeof message.requestId !== \"string\" || message.requestId.length > 200)\n return;\n try {\n if (message.type === \"omni-chat:application-request\") {\n const application = input.options.application;\n input.reply({\n type: \"omni-chat:application-response\",\n requestId: message.requestId,\n application: application\n ? boundedJson(\n {\n name: application.name,\n description: application.description,\n context: (await application.getContext()) ?? null,\n tools: Object.entries(input.options.frontendTools ?? {}).map(\n ([name, definition]) => ({\n name,\n description: definition.description,\n parameters: definition.parameters,\n }),\n ),\n },\n 65536,\n )\n : undefined,\n });\n } else if (message.type === \"omni-chat:tool-request\") {\n const name = message.toolName;\n const toolCallId = message.toolCallId;\n if (\n typeof name !== \"string\" ||\n !/^app_[a-z][a-z0-9_]{0,59}$/.test(name) ||\n typeof toolCallId !== \"string\" ||\n !toolCallId ||\n toolCallId.length > 200\n )\n throw new Error(\"Invalid application tool request.\");\n const definition = Object.hasOwn(\n input.options.frontendTools ?? {},\n name,\n )\n ? input.options.frontendTools?.[name]\n : undefined;\n if (!input.options.application || !definition)\n throw new Error(\"This application action is unavailable.\");\n const args = message.args;\n if (!args || typeof args !== \"object\" || Array.isArray(args))\n throw new Error(\"Invalid application action arguments.\");\n const signature = JSON.stringify({ name, args });\n const prior = calls.get(toolCallId);\n if (prior && prior.signature !== signature)\n throw new Error(\"This tool call ID was already used.\");\n const result =\n prior?.result ??\n Promise.resolve().then(() =>\n definition.execute(args as Record<string, unknown>, {\n toolCallId,\n abortSignal: input.signal,\n }),\n );\n if (!prior) {\n if (calls.size >= 200)\n throw new Error(\"Start a new application chat.\");\n calls.set(toolCallId, { signature, result });\n }\n input.reply({\n type: \"omni-chat:tool-response\",\n requestId: message.requestId,\n toolCallId,\n result: boundedJson((await result) ?? null, 12000),\n });\n }\n } catch (error) {\n input.reply({\n type:\n message.type === \"omni-chat:application-request\"\n ? \"omni-chat:application-response\"\n : \"omni-chat:tool-response\",\n requestId: message.requestId,\n toolCallId: message.toolCallId,\n error:\n error instanceof Error\n ? error.message\n : \"The application action failed.\",\n });\n }\n };\n}\n","import {\n createApplicationMessageHandler,\n type OmniApplicationOptions,\n} from \"./application\";\nexport type {\n OmniFrontendTool,\n OmniChatApplication,\n OmniApplicationOptions,\n} from \"./application\";\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 extends OmniApplicationOptions {\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 applicationMessage = createApplicationMessageHandler({\n options,\n signal: controller.signal,\n reply: (message) => {\n if (!destroyed)\n iframe.contentWindow?.postMessage(\n { ...message, deploymentId: options.deploymentId },\n chatOrigin,\n );\n },\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 (\n event.data.type === \"omni-chat:application-request\" ||\n event.data.type === \"omni-chat:tool-request\"\n ) {\n void applicationMessage(event.data);\n return;\n }\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 ...(options.application ? { applicationEnabled: true } : {}),\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 ...(options.application ? {applicationEnabled: true} : {}),\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"],"mappings":"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","names":[]}
package/dist/react.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { CSSProperties, ReactNode } from 'react';
3
3
  import { OmniChatEmbedOptions } from './embed.cjs';
4
- export { OmniChatSession } from './embed.cjs';
4
+ export { OmniApplicationOptions, OmniChatApplication, OmniChatSession, OmniFrontendTool } from './embed.cjs';
5
5
 
6
6
  type OmniProviderProps = OmniChatEmbedOptions & {
7
7
  children: ReactNode;
package/dist/react.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { CSSProperties, ReactNode } from 'react';
3
3
  import { OmniChatEmbedOptions } from './embed.js';
4
- export { OmniChatSession } from './embed.js';
4
+ export { OmniApplicationOptions, OmniChatApplication, OmniChatSession, OmniFrontendTool } from './embed.js';
5
5
 
6
6
  type OmniProviderProps = OmniChatEmbedOptions & {
7
7
  children: ReactNode;
package/dist/react.js CHANGED
@@ -8,6 +8,89 @@ import {
8
8
  useRef
9
9
  } from "react";
10
10
 
11
+ // src/application.ts
12
+ function boundedJson(value, maximum) {
13
+ const encoded = JSON.stringify(value);
14
+ if (typeof encoded !== "string" || new TextEncoder().encode(encoded).length > maximum || /data:[^"\s]{0,100};base64,/i.test(encoded))
15
+ throw new Error(
16
+ "Application data must be bounded JSON without base64 payloads."
17
+ );
18
+ return JSON.parse(encoded);
19
+ }
20
+ function createApplicationMessageHandler(input) {
21
+ const calls = /* @__PURE__ */ new Map();
22
+ return async (message) => {
23
+ if (typeof message.requestId !== "string" || message.requestId.length > 200)
24
+ return;
25
+ try {
26
+ if (message.type === "omni-chat:application-request") {
27
+ const application = input.options.application;
28
+ input.reply({
29
+ type: "omni-chat:application-response",
30
+ requestId: message.requestId,
31
+ application: application ? boundedJson(
32
+ {
33
+ name: application.name,
34
+ description: application.description,
35
+ context: await application.getContext() ?? null,
36
+ tools: Object.entries(input.options.frontendTools ?? {}).map(
37
+ ([name, definition]) => ({
38
+ name,
39
+ description: definition.description,
40
+ parameters: definition.parameters
41
+ })
42
+ )
43
+ },
44
+ 65536
45
+ ) : void 0
46
+ });
47
+ } else if (message.type === "omni-chat:tool-request") {
48
+ const name = message.toolName;
49
+ const toolCallId = message.toolCallId;
50
+ if (typeof name !== "string" || !/^app_[a-z][a-z0-9_]{0,59}$/.test(name) || typeof toolCallId !== "string" || !toolCallId || toolCallId.length > 200)
51
+ throw new Error("Invalid application tool request.");
52
+ const definition = Object.hasOwn(
53
+ input.options.frontendTools ?? {},
54
+ name
55
+ ) ? input.options.frontendTools?.[name] : void 0;
56
+ if (!input.options.application || !definition)
57
+ throw new Error("This application action is unavailable.");
58
+ const args = message.args;
59
+ if (!args || typeof args !== "object" || Array.isArray(args))
60
+ throw new Error("Invalid application action arguments.");
61
+ const signature = JSON.stringify({ name, args });
62
+ const prior = calls.get(toolCallId);
63
+ if (prior && prior.signature !== signature)
64
+ throw new Error("This tool call ID was already used.");
65
+ const result = prior?.result ?? Promise.resolve().then(
66
+ () => definition.execute(args, {
67
+ toolCallId,
68
+ abortSignal: input.signal
69
+ })
70
+ );
71
+ if (!prior) {
72
+ if (calls.size >= 200)
73
+ throw new Error("Start a new application chat.");
74
+ calls.set(toolCallId, { signature, result });
75
+ }
76
+ input.reply({
77
+ type: "omni-chat:tool-response",
78
+ requestId: message.requestId,
79
+ toolCallId,
80
+ result: boundedJson(await result ?? null, 12e3)
81
+ });
82
+ }
83
+ } catch (error) {
84
+ input.reply({
85
+ type: message.type === "omni-chat:application-request" ? "omni-chat:application-response" : "omni-chat:tool-response",
86
+ requestId: message.requestId,
87
+ toolCallId: message.toolCallId,
88
+ error: error instanceof Error ? error.message : "The application action failed."
89
+ });
90
+ }
91
+ };
92
+ }
93
+
11
94
  // src/embed.ts
12
95
  function getOmniChatEmbedUrl(options, parentOrigin) {
13
96
  if (!/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/i.test(
@@ -69,9 +152,24 @@ function createOmniChatEmbed(container, options) {
69
152
  }
70
153
  return result;
71
154
  };
155
+ const applicationMessage = createApplicationMessageHandler({
156
+ options,
157
+ signal: controller.signal,
158
+ reply: (message) => {
159
+ if (!destroyed)
160
+ iframe.contentWindow?.postMessage(
161
+ { ...message, deploymentId: options.deploymentId },
162
+ chatOrigin
163
+ );
164
+ }
165
+ });
72
166
  const receive = (event) => {
73
167
  if (destroyed || event.source !== iframe.contentWindow || event.origin !== chatOrigin || event.data?.deploymentId !== options.deploymentId)
74
168
  return;
169
+ if (event.data.type === "omni-chat:application-request" || event.data.type === "omni-chat:tool-request") {
170
+ void applicationMessage(event.data);
171
+ return;
172
+ }
75
173
  if (event.data.type === "omni-chat:close-request") {
76
174
  options.onRequestClose?.();
77
175
  return;
@@ -87,7 +185,8 @@ function createOmniChatEmbed(container, options) {
87
185
  {
88
186
  type: "omni-chat:session",
89
187
  deploymentId: options.deploymentId,
90
- session
188
+ session,
189
+ ...options.application ? { applicationEnabled: true } : {}
91
190
  },
92
191
  chatOrigin
93
192
  );
@@ -99,7 +198,8 @@ function createOmniChatEmbed(container, options) {
99
198
  {
100
199
  type: "omni-chat:session-error",
101
200
  deploymentId: options.deploymentId,
102
- error: failure.message
201
+ error: failure.message,
202
+ ...options.application ? { applicationEnabled: true } : {}
103
203
  },
104
204
  chatOrigin
105
205
  );
@@ -144,11 +244,18 @@ function OmniChat({ className, style, title }) {
144
244
  if (!options)
145
245
  throw new Error("OmniChat must be rendered inside OmniProvider.");
146
246
  const container = useRef(null);
147
- const { baseUrl, deploymentId, getSession, onError } = options;
148
- const callbacks = useRef({ getSession, onError });
247
+ const {
248
+ baseUrl,
249
+ deploymentId,
250
+ getSession,
251
+ onError,
252
+ application,
253
+ frontendTools
254
+ } = options;
255
+ const callbacks = useRef({ getSession, onError, application, frontendTools });
149
256
  useEffect(() => {
150
- callbacks.current = { getSession, onError };
151
- }, [getSession, onError]);
257
+ callbacks.current = { getSession, onError, application, frontendTools };
258
+ }, [getSession, onError, application, frontendTools]);
152
259
  const hasSessionBroker = Boolean(getSession);
153
260
  const frameTitle = title ?? options.title;
154
261
  useEffect(() => {
@@ -158,7 +265,13 @@ function OmniChat({ className, style, title }) {
158
265
  deploymentId,
159
266
  getSession: hasSessionBroker ? () => callbacks.current.getSession() : void 0,
160
267
  onError: (error) => callbacks.current.onError?.(error),
161
- title: frameTitle
268
+ title: frameTitle,
269
+ get application() {
270
+ return callbacks.current.application;
271
+ },
272
+ get frontendTools() {
273
+ return callbacks.current.frontendTools;
274
+ }
162
275
  });
163
276
  return () => embed.destroy();
164
277
  }, [baseUrl, deploymentId, frameTitle, hasSessionBroker]);
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react.tsx","../src/embed.ts"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useContext,\n useEffect,\n useRef,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { createOmniChatEmbed, type OmniChatEmbedOptions } from \"./embed\";\n\nconst OmniChatContext = createContext<OmniChatEmbedOptions | null>(null);\nexport type OmniProviderProps = OmniChatEmbedOptions & { children: ReactNode };\n\nexport function OmniProvider({ children, ...options }: OmniProviderProps) {\n return (\n <OmniChatContext.Provider value={options}>\n {children}\n </OmniChatContext.Provider>\n );\n}\nexport interface OmniChatProps {\n className?: string;\n style?: CSSProperties;\n title?: string;\n}\n/** The hosted assistant owns its styles and runtime, so the host needs no Tailwind or assistant-ui dependencies. */\nexport function OmniChat({ className, style, title }: OmniChatProps) {\n const options = useContext(OmniChatContext);\n if (!options)\n throw new Error(\"OmniChat must be rendered inside OmniProvider.\");\n const container = useRef<HTMLDivElement>(null);\n const { baseUrl, deploymentId, getSession, onError } = options;\n const callbacks = useRef({ getSession, onError });\n useEffect(() => {\n callbacks.current = { getSession, onError };\n }, [getSession, onError]);\n const hasSessionBroker = Boolean(getSession);\n const frameTitle = title ?? options.title;\n useEffect(() => {\n if (!container.current) return;\n const embed = createOmniChatEmbed(container.current, {\n baseUrl,\n deploymentId,\n getSession: hasSessionBroker\n ? () => callbacks.current.getSession!()\n : undefined,\n onError: (error) => callbacks.current.onError?.(error),\n title: frameTitle,\n });\n return () => embed.destroy();\n }, [baseUrl, deploymentId, frameTitle, hasSessionBroker]);\n return (\n <div\n ref={container}\n className={className}\n style={{ height: \"100%\", minHeight: 320, ...style }}\n />\n );\n}\nexport type { OmniChatEmbedOptions, OmniChatSession } from \"./embed\";\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"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/react.tsx","../src/application.ts","../src/embed.ts"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useContext,\n useEffect,\n useRef,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { createOmniChatEmbed, type OmniChatEmbedOptions } from \"./embed\";\n\nconst OmniChatContext = createContext<OmniChatEmbedOptions | null>(null);\nexport type OmniProviderProps = OmniChatEmbedOptions & { children: ReactNode };\n\nexport function OmniProvider({ children, ...options }: OmniProviderProps) {\n return (\n <OmniChatContext.Provider value={options}>\n {children}\n </OmniChatContext.Provider>\n );\n}\nexport interface OmniChatProps {\n className?: string;\n style?: CSSProperties;\n title?: string;\n}\n/** The hosted assistant owns its styles and runtime, so the host needs no Tailwind or assistant-ui dependencies. */\nexport function OmniChat({ className, style, title }: OmniChatProps) {\n const options = useContext(OmniChatContext);\n if (!options)\n throw new Error(\"OmniChat must be rendered inside OmniProvider.\");\n const container = useRef<HTMLDivElement>(null);\n const {\n baseUrl,\n deploymentId,\n getSession,\n onError,\n application,\n frontendTools,\n } = options;\n const callbacks = useRef({ getSession, onError, application, frontendTools });\n useEffect(() => {\n callbacks.current = { getSession, onError, application, frontendTools };\n }, [getSession, onError, application, frontendTools]);\n const hasSessionBroker = Boolean(getSession);\n const frameTitle = title ?? options.title;\n useEffect(() => {\n if (!container.current) return;\n const embed = createOmniChatEmbed(container.current, {\n baseUrl,\n deploymentId,\n getSession: hasSessionBroker\n ? () => callbacks.current.getSession!()\n : undefined,\n onError: (error) => callbacks.current.onError?.(error),\n title: frameTitle,\n get application() {\n return callbacks.current.application;\n },\n get frontendTools() {\n return callbacks.current.frontendTools;\n },\n });\n return () => embed.destroy();\n }, [baseUrl, deploymentId, frameTitle, hasSessionBroker]);\n return (\n <div\n ref={container}\n className={className}\n style={{ height: \"100%\", minHeight: 320, ...style }}\n />\n );\n}\nexport type {\n OmniFrontendTool,\n OmniChatApplication,\n OmniApplicationOptions,\n OmniChatEmbedOptions,\n OmniChatSession,\n} from \"./embed\";\n","/** Host-defined actions execute inside the application, never on the assistant server. */\nexport interface OmniFrontendTool {\n description: string;\n parameters: Record<string, unknown>;\n execute: (\n args: Record<string, unknown>,\n context: { toolCallId: string; abortSignal: AbortSignal },\n ) => unknown | Promise<unknown>;\n}\nexport interface OmniChatApplication {\n name: string;\n description: string;\n /** Return a small, explicitly selected snapshot. Do not include secrets. */\n getContext: () => unknown | Promise<unknown>;\n}\nexport interface OmniApplicationOptions {\n application?: OmniChatApplication;\n /** Names must start with app_; use array arguments for actions with multiple targets. */\n frontendTools?: Record<string, OmniFrontendTool>;\n}\n\nfunction boundedJson(value: unknown, maximum: number): unknown {\n const encoded = JSON.stringify(value);\n if (\n typeof encoded !== \"string\" ||\n new TextEncoder().encode(encoded).length > maximum ||\n /data:[^\"\\s]{0,100};base64,/i.test(encoded)\n )\n throw new Error(\n \"Application data must be bounded JSON without base64 payloads.\",\n );\n return JSON.parse(encoded);\n}\n\nexport function createApplicationMessageHandler(input: {\n options: OmniApplicationOptions;\n signal: AbortSignal;\n reply: (message: Record<string, unknown>) => void;\n}) {\n // A repeated parked call reuses its result instead of applying an action twice.\n const calls = new Map<\n string,\n { signature: string; result: Promise<unknown> }\n >();\n return async (message: Record<string, unknown>) => {\n if (typeof message.requestId !== \"string\" || message.requestId.length > 200)\n return;\n try {\n if (message.type === \"omni-chat:application-request\") {\n const application = input.options.application;\n input.reply({\n type: \"omni-chat:application-response\",\n requestId: message.requestId,\n application: application\n ? boundedJson(\n {\n name: application.name,\n description: application.description,\n context: (await application.getContext()) ?? null,\n tools: Object.entries(input.options.frontendTools ?? {}).map(\n ([name, definition]) => ({\n name,\n description: definition.description,\n parameters: definition.parameters,\n }),\n ),\n },\n 65536,\n )\n : undefined,\n });\n } else if (message.type === \"omni-chat:tool-request\") {\n const name = message.toolName;\n const toolCallId = message.toolCallId;\n if (\n typeof name !== \"string\" ||\n !/^app_[a-z][a-z0-9_]{0,59}$/.test(name) ||\n typeof toolCallId !== \"string\" ||\n !toolCallId ||\n toolCallId.length > 200\n )\n throw new Error(\"Invalid application tool request.\");\n const definition = Object.hasOwn(\n input.options.frontendTools ?? {},\n name,\n )\n ? input.options.frontendTools?.[name]\n : undefined;\n if (!input.options.application || !definition)\n throw new Error(\"This application action is unavailable.\");\n const args = message.args;\n if (!args || typeof args !== \"object\" || Array.isArray(args))\n throw new Error(\"Invalid application action arguments.\");\n const signature = JSON.stringify({ name, args });\n const prior = calls.get(toolCallId);\n if (prior && prior.signature !== signature)\n throw new Error(\"This tool call ID was already used.\");\n const result =\n prior?.result ??\n Promise.resolve().then(() =>\n definition.execute(args as Record<string, unknown>, {\n toolCallId,\n abortSignal: input.signal,\n }),\n );\n if (!prior) {\n if (calls.size >= 200)\n throw new Error(\"Start a new application chat.\");\n calls.set(toolCallId, { signature, result });\n }\n input.reply({\n type: \"omni-chat:tool-response\",\n requestId: message.requestId,\n toolCallId,\n result: boundedJson((await result) ?? null, 12000),\n });\n }\n } catch (error) {\n input.reply({\n type:\n message.type === \"omni-chat:application-request\"\n ? \"omni-chat:application-response\"\n : \"omni-chat:tool-response\",\n requestId: message.requestId,\n toolCallId: message.toolCallId,\n error:\n error instanceof Error\n ? error.message\n : \"The application action failed.\",\n });\n }\n };\n}\n","import {\n createApplicationMessageHandler,\n type OmniApplicationOptions,\n} from \"./application\";\nexport type {\n OmniFrontendTool,\n OmniChatApplication,\n OmniApplicationOptions,\n} from \"./application\";\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 extends OmniApplicationOptions {\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 applicationMessage = createApplicationMessageHandler({\n options,\n signal: controller.signal,\n reply: (message) => {\n if (!destroyed)\n iframe.contentWindow?.postMessage(\n { ...message, deploymentId: options.deploymentId },\n chatOrigin,\n );\n },\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 (\n event.data.type === \"omni-chat:application-request\" ||\n event.data.type === \"omni-chat:tool-request\"\n ) {\n void applicationMessage(event.data);\n return;\n }\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 ...(options.application ? { applicationEnabled: true } : {}),\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 ...(options.application ? {applicationEnabled: true} : {}),\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"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omni-commerce/sdk",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "TypeScript SDK for the OmniCommerce API. Generated from the public OpenAPI spec.",
5
5
  "license": "MIT",
6
6
  "private": false,