@salesforce/agentforce-conversation-client 9.9.3 → 9.10.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/README.md CHANGED
@@ -355,6 +355,38 @@ const { loApp } = embedAgentforceClient({
355
355
 
356
356
  ### Listening for Events
357
357
 
358
+ #### Callback props (recommended)
359
+
360
+ Use the `onReady` and `onError` callback options for a simpler, declarative approach:
361
+
362
+ ```typescript
363
+ import { embedAgentforceClient } from "@salesforce/agentforce-conversation-client";
364
+
365
+ embedAgentforceClient({
366
+ container: "#agentforce-container",
367
+ salesforceOrigin: "https://myorg.my.salesforce.com",
368
+ onReady: (detail) => {
369
+ console.log("Lightning Out is ready", detail);
370
+ },
371
+ onError: (error) => {
372
+ // error.type is "lo.application.error" or "lo.iframe.error"
373
+ // error.detail contains the error payload from Lightning Out
374
+ console.error(`[${error.type}]`, error.detail);
375
+ },
376
+ });
377
+ ```
378
+
379
+ | Callback | Fires when | Argument shape |
380
+ | --------- | --------------------------------------------------------------- | ------------------------------------------------------------------------ |
381
+ | `onReady` | Lightning Out application has finished loading | `detail: unknown` — the raw detail from the `lo.application.ready` event |
382
+ | `onError` | An application-level or iframe-level Lightning Out error occurs | `{ type: "lo.application.error" \| "lo.iframe.error", detail: unknown }` |
383
+
384
+ Both callbacks are optional.
385
+
386
+ #### Low-level event listeners
387
+
388
+ For finer-grained control (e.g. `lo.component.ready`, `lo.application.logout`), use the returned `loApp` element directly:
389
+
358
390
  ```typescript
359
391
  const { loApp } = embedAgentforceClient({
360
392
  container: "#agentforce-container",
@@ -401,6 +433,8 @@ Embeds the Agentforce Conversation Client by creating a Lightning Out 2.0 app an
401
433
  | `agentforceClientConfig.renderingConfig.headerEnabled` | `boolean` | No | Show or hide the chat header bar. Defaults to hidden in inline mode. Set `true` to show it |
402
434
  | `agentforceClientConfig.renderingConfig.showHeaderIcon` | `boolean` | No | Show or hide the icon in the header. Omit or set `false` to hide |
403
435
  | `agentforceClientConfig.renderingConfig.showAvatar` | `boolean` | No | Show or hide avatars in message rows. Defaults to `true` |
436
+ | `options.onReady` | `AgentforceReadyHandler` | No | Callback invoked when the Lightning Out application is ready. Receives the event detail |
437
+ | `options.onError` | `AgentforceErrorHandler` | No | Callback invoked on Lightning Out errors. Receives `{ type, detail }` with the error source and payload |
404
438
 
405
439
  #### Returns
406
440
 
@@ -432,6 +466,15 @@ interface AgentforceClientConfig {
432
466
  };
433
467
  }
434
468
 
469
+ // Error event passed to the onError callback
470
+ interface AgentforceLoErrorEvent {
471
+ type: "lo.application.error" | "lo.iframe.error";
472
+ detail: unknown;
473
+ }
474
+
475
+ type AgentforceErrorHandler = (error: AgentforceLoErrorEvent) => void;
476
+ type AgentforceReadyHandler = (detail: unknown) => void;
477
+
435
478
  interface EmbedAgentforceClientOptions {
436
479
  container: string | HTMLElement;
437
480
  salesforceOrigin?: string;
@@ -439,6 +482,8 @@ interface EmbedAgentforceClientOptions {
439
482
  frontdoorUrl?: string;
440
483
  sitePrefix?: string;
441
484
  agentforceClientConfig?: AgentforceClientConfig;
485
+ onReady?: AgentforceReadyHandler;
486
+ onError?: AgentforceErrorHandler;
442
487
  }
443
488
 
444
489
  interface EmbedAgentforceClientResult {
package/dist/index.d.ts CHANGED
@@ -29,6 +29,12 @@ export interface AgentforceClientConfig {
29
29
  };
30
30
  channel?: string;
31
31
  }
32
+ export interface AgentforceLoErrorEvent {
33
+ type: "lo.application.error" | "lo.iframe.error";
34
+ detail: unknown;
35
+ }
36
+ export type AgentforceErrorHandler = (error: AgentforceLoErrorEvent) => void;
37
+ export type AgentforceReadyHandler = (detail: unknown) => void;
32
38
  export interface EmbedAgentforceClientOptions {
33
39
  container: string | HTMLElement;
34
40
  salesforceOrigin?: string;
@@ -36,6 +42,8 @@ export interface EmbedAgentforceClientOptions {
36
42
  frontdoorUrl?: string;
37
43
  sitePrefix?: string;
38
44
  agentforceClientConfig?: AgentforceClientConfig;
45
+ onError?: AgentforceErrorHandler;
46
+ onReady?: AgentforceReadyHandler;
39
47
  }
40
48
  export interface EmbedAgentforceClientResult {
41
49
  loApp: LightningOutApplication;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAMrE,eAAO,MAAM,6BAA6B,oCAAoC,CAAC;AAC/E,eAAO,MAAM,2BAA2B,oBAAoB,CAAC;AAC7D,eAAO,MAAM,gCAAgC,kBAAkB,CAAC;AAChE,eAAO,MAAM,2BAA2B,YAAY,CAAC;AACrD,eAAO,MAAM,sCAAsC,qEAA2G,CAAC;AAE/J,eAAO,MAAM,aAAa;;;EAGf,CAAC;AAEZ,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC;AAMpF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEjD,MAAM,WAAW,sBAAsB;IACtC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE;QACjB,IAAI,CAAC,EAAE,kBAAkB,CAAC;QAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACxB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACzB,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,UAAU,CAAC,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,4BAA4B;IAC5C,SAAS,EAAE,MAAM,GAAG,WAAW,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;CAChD;AAED,MAAM,WAAW,2BAA2B;IAC3C,KAAK,EAAE,uBAAuB,CAAC;IAC/B,mBAAmB,EAAE,WAAW,CAAC;CACjC;AA6UD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACpC,OAAO,CAAC,EAAE,4BAA4B,GAAG,IAAI,GAC3C,2BAA2B,CAyB7B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAMrE,eAAO,MAAM,6BAA6B,oCAAoC,CAAC;AAC/E,eAAO,MAAM,2BAA2B,oBAAoB,CAAC;AAC7D,eAAO,MAAM,gCAAgC,kBAAkB,CAAC;AAChE,eAAO,MAAM,2BAA2B,YAAY,CAAC;AACrD,eAAO,MAAM,sCAAsC,qEAA2G,CAAC;AAE/J,eAAO,MAAM,aAAa;;;EAGf,CAAC;AAEZ,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC;AAMpF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEjD,MAAM,WAAW,sBAAsB;IACtC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE;QACjB,IAAI,CAAC,EAAE,kBAAkB,CAAC;QAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACxB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACzB,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,UAAU,CAAC,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACtC,IAAI,EAAE,sBAAsB,GAAG,iBAAiB,CAAC;IACjD,MAAM,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,MAAM,sBAAsB,GAAG,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;AAC7E,MAAM,MAAM,sBAAsB,GAAG,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;AAE/D,MAAM,WAAW,4BAA4B;IAC5C,SAAS,EAAE,MAAM,GAAG,WAAW,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC,OAAO,CAAC,EAAE,sBAAsB,CAAC;CACjC;AAED,MAAM,WAAW,2BAA2B;IAC3C,KAAK,EAAE,uBAAuB,CAAC;IAC/B,mBAAmB,EAAE,WAAW,CAAC;CACjC;AAyVD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACpC,OAAO,CAAC,EAAE,4BAA4B,GAAG,IAAI,GAC3C,2BAA2B,CA6B7B"}
package/dist/index.js CHANGED
@@ -211,7 +211,7 @@ function createAndMountFrame(container, clientConfig, loApp) {
211
211
  // ═══════════════════════════════════════════════════════════════════════════════
212
212
  // LIGHTNING OUT – LO app creation and error handling
213
213
  // ═══════════════════════════════════════════════════════════════════════════════
214
- function createAndMountLoApp(container, salesforceOrigin, appId, frontdoorUrl, sitePrefix) {
214
+ function createAndMountLoApp(container, salesforceOrigin, appId, frontdoorUrl, sitePrefix, onError, onReady) {
215
215
  const loApp = new LightningOutApplication();
216
216
  if (salesforceOrigin)
217
217
  loApp.setAttribute("org-url", salesforceOrigin);
@@ -225,19 +225,25 @@ function createAndMountLoApp(container, salesforceOrigin, appId, frontdoorUrl, s
225
225
  loApp.setAttribute("site-prefix", sitePrefix);
226
226
  loApp.style.opacity = "0";
227
227
  loApp.style.pointerEvents = "none";
228
- attachLoEventHandlers(loApp);
228
+ attachLoEventHandlers(loApp, onError, onReady);
229
229
  container.appendChild(loApp);
230
230
  return loApp;
231
231
  }
232
- function attachLoEventHandlers(loApp) {
232
+ function attachLoEventHandlers(loApp, onError, onReady) {
233
233
  loApp.addEventListener("lo.application.ready", (e) => {
234
- console.log("Agentforce Conversation Client: Lightning Out ready", e.detail != null ? e.detail : "");
234
+ const detail = e.detail;
235
+ console.log("Agentforce Conversation Client: Lightning Out ready", detail != null ? detail : "");
236
+ onReady?.(detail);
235
237
  });
236
238
  loApp.addEventListener("lo.application.error", (e) => {
237
- console.error("Agentforce Conversation Client: Lightning Out error:", e.detail);
239
+ const detail = e.detail;
240
+ console.error("Agentforce Conversation Client: Lightning Out error:", detail);
241
+ onError?.({ type: "lo.application.error", detail });
238
242
  });
239
243
  loApp.addEventListener("lo.iframe.error", (e) => {
240
- console.error("Agentforce Conversation Client: Lightning Out iframe error:", e.detail);
244
+ const detail = e.detail;
245
+ console.error("Agentforce Conversation Client: Lightning Out iframe error:", detail);
246
+ onError?.({ type: "lo.iframe.error", detail });
241
247
  });
242
248
  }
243
249
  // ═══════════════════════════════════════════════════════════════════════════════
@@ -251,9 +257,9 @@ function resolveContainer(container) {
251
257
  return null;
252
258
  }
253
259
  function embedIntoContainer(containerElement, options) {
254
- const { salesforceOrigin, appId, frontdoorUrl, sitePrefix, agentforceClientConfig = {}, } = options;
260
+ const { salesforceOrigin, appId, frontdoorUrl, sitePrefix, agentforceClientConfig = {}, onError, onReady, } = options;
255
261
  containerElement.classList.add("acc-container");
256
- const loApp = createAndMountLoApp(containerElement, salesforceOrigin, appId, frontdoorUrl, sitePrefix);
262
+ const loApp = createAndMountLoApp(containerElement, salesforceOrigin, appId, frontdoorUrl, sitePrefix, onError, onReady);
257
263
  const chatClientComponent = createAndMountFrame(containerElement, agentforceClientConfig, loApp);
258
264
  return { loApp, chatClientComponent };
259
265
  }
@@ -272,7 +278,7 @@ function embedIntoContainer(containerElement, options) {
272
278
  * });
273
279
  */
274
280
  export function embedAgentforceClient(options) {
275
- const { container, salesforceOrigin, appId, frontdoorUrl, sitePrefix, agentforceClientConfig = {}, } = options ?? {};
281
+ const { container, salesforceOrigin, appId, frontdoorUrl, sitePrefix, agentforceClientConfig = {}, onError, onReady, } = options ?? {};
276
282
  if (!container)
277
283
  throw new Error("Agentforce Conversation Client: container is required");
278
284
  if (!salesforceOrigin && !frontdoorUrl) {
@@ -289,5 +295,7 @@ export function embedAgentforceClient(options) {
289
295
  frontdoorUrl,
290
296
  sitePrefix,
291
297
  agentforceClientConfig,
298
+ onError,
299
+ onReady,
292
300
  });
293
301
  }
@@ -157,4 +157,65 @@ describe("Agentforce Conversation Client SDK", () => {
157
157
  expect(container.style.getPropertyValue("--acc-height")).toBe("600px");
158
158
  expect(container.style.getPropertyValue("--agentic-chat-container-height")).toBe("600px");
159
159
  });
160
+ it("registers lo.application.ready listener when onReady is provided", () => {
161
+ const onReady = vi.fn();
162
+ embedAgentforceClient({
163
+ container: "#test-container",
164
+ salesforceOrigin: "https://test.salesforce.com",
165
+ onReady,
166
+ });
167
+ expect(mockAddEventListener).toHaveBeenCalledWith("lo.application.ready", expect.any(Function));
168
+ });
169
+ it("registers lo.application.error and lo.iframe.error listeners when onError is provided", () => {
170
+ const onError = vi.fn();
171
+ embedAgentforceClient({
172
+ container: "#test-container",
173
+ salesforceOrigin: "https://test.salesforce.com",
174
+ onError,
175
+ });
176
+ expect(mockAddEventListener).toHaveBeenCalledWith("lo.application.error", expect.any(Function));
177
+ expect(mockAddEventListener).toHaveBeenCalledWith("lo.iframe.error", expect.any(Function));
178
+ });
179
+ it("invokes onReady with detail when lo.application.ready fires", () => {
180
+ const onReady = vi.fn();
181
+ embedAgentforceClient({
182
+ container: "#test-container",
183
+ salesforceOrigin: "https://test.salesforce.com",
184
+ onReady,
185
+ });
186
+ const readyHandler = mockAddEventListener.mock.calls.find(([name]) => name === "lo.application.ready")?.[1];
187
+ readyHandler?.(new CustomEvent("lo.application.ready", { detail: { foo: "bar" } }));
188
+ expect(onReady).toHaveBeenCalledWith({ foo: "bar" });
189
+ });
190
+ it("invokes onError with type and detail when lo.application.error fires", () => {
191
+ const onError = vi.fn();
192
+ embedAgentforceClient({
193
+ container: "#test-container",
194
+ salesforceOrigin: "https://test.salesforce.com",
195
+ onError,
196
+ });
197
+ const errorHandler = mockAddEventListener.mock.calls.find(([name]) => name === "lo.application.error")?.[1];
198
+ errorHandler?.(new CustomEvent("lo.application.error", { detail: { code: 500 } }));
199
+ expect(onError).toHaveBeenCalledWith({
200
+ type: "lo.application.error",
201
+ detail: { code: 500 },
202
+ });
203
+ });
204
+ it("invokes onError with type=lo.iframe.error when iframe error fires", () => {
205
+ const onError = vi.fn();
206
+ embedAgentforceClient({
207
+ container: "#test-container",
208
+ salesforceOrigin: "https://test.salesforce.com",
209
+ onError,
210
+ });
211
+ const iframeErrorHandler = mockAddEventListener.mock.calls.find(([name]) => name === "lo.iframe.error")?.[1];
212
+ iframeErrorHandler?.(new CustomEvent("lo.iframe.error", { detail: "boom" }));
213
+ expect(onError).toHaveBeenCalledWith({ type: "lo.iframe.error", detail: "boom" });
214
+ });
215
+ it("does not throw when onError/onReady are omitted (backward compatible)", () => {
216
+ expect(() => embedAgentforceClient({
217
+ container: "#test-container",
218
+ salesforceOrigin: "https://test.salesforce.com",
219
+ })).not.toThrow();
220
+ });
160
221
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@salesforce/agentforce-conversation-client",
3
3
  "description": "Agentforce Conversation Client SDK for embedding via Lightning Out 2.0",
4
- "version": "9.9.3",
4
+ "version": "9.10.0",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",