@salesforce/agentforce-conversation-client 11.49.4 → 11.51.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/ui-bundle.d.ts +93 -0
- package/dist/ui-bundle.d.ts.map +1 -0
- package/dist/ui-bundle.js +141 -0
- package/package.json +5 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Framework-agnostic glue for embedding the Agentforce Conversation Client (ACC)
|
|
8
|
+
* via Lightning Out. This is the shared orchestration that used to be duplicated
|
|
9
|
+
* across the React `AgentforceConversationClient` component and the Angular
|
|
10
|
+
* `AgentforceEmbedService`:
|
|
11
|
+
*
|
|
12
|
+
* - a window-scoped singleton so exactly one embed happens per window, no matter
|
|
13
|
+
* how many client wrappers mount;
|
|
14
|
+
* - a shared body-level host for floating mode (created on demand);
|
|
15
|
+
* - auth resolution — the dev frontdoor URL (`/__lo/frontdoor`) on localhost,
|
|
16
|
+
* `SFDC_ENV.orgUrl` otherwise — merged with caller overrides;
|
|
17
|
+
* - detection of an already-embedded client (`lightning-out-application[data-lo="acc"]`)
|
|
18
|
+
* and cleanup of a partially-created element so the next mount can retry.
|
|
19
|
+
*
|
|
20
|
+
* Shipped as the `@salesforce/agentforce-conversation-client/ui-bundle` subpath
|
|
21
|
+
* so it lives alongside the low-level `embedAgentforceClient` it orchestrates.
|
|
22
|
+
* It still takes that embed function by dependency injection rather than
|
|
23
|
+
* importing it directly, which keeps the glue framework-agnostic and unit-testable
|
|
24
|
+
* with a mock embed function. The React/Angular feature templates own the import
|
|
25
|
+
* and hand the function to {@link createAccEmbedder}.
|
|
26
|
+
*/
|
|
27
|
+
/** ACC ready callback — receives the Lightning Out ready detail. */
|
|
28
|
+
export type AccReadyHandler = (detail: unknown) => void;
|
|
29
|
+
/** ACC error callback — receives the Lightning Out error event. */
|
|
30
|
+
export type AccErrorHandler = (error: unknown) => void;
|
|
31
|
+
/** Auth options resolved at embed time (frontdoor in dev, org URL in prod). */
|
|
32
|
+
export interface AccEmbedOverrides {
|
|
33
|
+
salesforceOrigin?: string;
|
|
34
|
+
frontdoorUrl?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Optional ready/error handlers forwarded to the embed function. Declared with
|
|
38
|
+
* method syntax so a caller's handler typed against a *narrower* event type
|
|
39
|
+
* (e.g. ACC's `AgentforceErrorHandler`, whose param is a concrete error event)
|
|
40
|
+
* remains assignable — the glue only forwards these callbacks, never invokes
|
|
41
|
+
* them itself, so bivariance here is safe.
|
|
42
|
+
*/
|
|
43
|
+
export interface AccEmbedHandlers {
|
|
44
|
+
onReady?(detail: unknown): void;
|
|
45
|
+
onError?(error: unknown): void;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Minimal structural shape the glue needs to read off the client config
|
|
49
|
+
* (rendering mode + agent id). Kept intentionally loose so the concrete
|
|
50
|
+
* `AgentforceClientConfig` satisfies it structurally.
|
|
51
|
+
*/
|
|
52
|
+
export interface AccConfigShape {
|
|
53
|
+
agentId?: string;
|
|
54
|
+
renderingConfig?: {
|
|
55
|
+
mode?: string;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** Options the injected embed function is called with. */
|
|
59
|
+
export interface AccEmbedRequest<TConfig extends AccConfigShape> {
|
|
60
|
+
container: HTMLElement;
|
|
61
|
+
salesforceOrigin?: string;
|
|
62
|
+
frontdoorUrl?: string;
|
|
63
|
+
agentforceClientConfig?: TConfig;
|
|
64
|
+
onReady?: AccReadyHandler;
|
|
65
|
+
onError?: AccErrorHandler;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The low-level embed function (structurally, ACC's `embedAgentforceClient`),
|
|
69
|
+
* supplied by the caller. Its return value is ignored by the glue.
|
|
70
|
+
*/
|
|
71
|
+
export type AccEmbedFn<TConfig extends AccConfigShape> = (options: AccEmbedRequest<TConfig>) => unknown;
|
|
72
|
+
/** A configured embedder that guarantees a single embed per window. */
|
|
73
|
+
export interface AccEmbedder<TConfig extends AccConfigShape> {
|
|
74
|
+
/**
|
|
75
|
+
* Embed the client once. Subsequent calls are no-ops while an embed is in
|
|
76
|
+
* flight or already complete. For inline mode, `host` is the container the
|
|
77
|
+
* client renders into; when omitted (floating mode) a shared body-level host
|
|
78
|
+
* is used. `overrides` win over the resolved defaults.
|
|
79
|
+
*/
|
|
80
|
+
embedAcc(config: TConfig, overrides?: AccEmbedOverrides, host?: HTMLElement | null, handlers?: AccEmbedHandlers): void;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Create an embedder bound to a low-level embed function.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* import { embedAgentforceClient } from "@salesforce/agentforce-conversation-client";
|
|
87
|
+
* import { createAccEmbedder } from "@salesforce/agentforce-conversation-client/ui-bundle";
|
|
88
|
+
*
|
|
89
|
+
* const embedder = createAccEmbedder(embedAgentforceClient);
|
|
90
|
+
* embedder.embedAcc(config, { salesforceOrigin }, hostEl, { onReady, onError });
|
|
91
|
+
*/
|
|
92
|
+
export declare function createAccEmbedder<TConfig extends AccConfigShape>(embedFn: AccEmbedFn<TConfig>): AccEmbedder<TConfig>;
|
|
93
|
+
//# sourceMappingURL=ui-bundle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-bundle.d.ts","sourceRoot":"","sources":["../src/ui-bundle.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,oEAAoE;AACpE,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;AAExD,mEAAmE;AACnE,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;AAEvD,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAChC,OAAO,CAAC,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,OAAO,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACpC;AAED,0DAA0D;AAC1D,MAAM,WAAW,eAAe,CAAC,OAAO,SAAS,cAAc;IAC9D,SAAS,EAAE,WAAW,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,OAAO,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,OAAO,SAAS,cAAc,IAAI,CACxD,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC,KAC7B,OAAO,CAAC;AAEb,uEAAuE;AACvE,MAAM,WAAW,WAAW,CAAC,OAAO,SAAS,cAAc;IAC1D;;;;;OAKG;IACH,QAAQ,CACP,MAAM,EAAE,OAAO,EACf,SAAS,CAAC,EAAE,iBAAiB,EAC7B,IAAI,CAAC,EAAE,WAAW,GAAG,IAAI,EACzB,QAAQ,CAAC,EAAE,gBAAgB,GACzB,IAAI,CAAC;CACR;AAqDD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,SAAS,cAAc,EAC/D,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,GAC1B,WAAW,CAAC,OAAO,CAAC,CAuGtB"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
const GLOBAL_HOST_ID = "agentforce-conversation-client-global-host";
|
|
7
|
+
const EXISTING_EMBED_SELECTOR = 'lightning-out-application[data-lo="acc"]';
|
|
8
|
+
const SINGLETON_KEY = "__agentforceConversationClientSingleton";
|
|
9
|
+
const INLINE_MODE = "inline";
|
|
10
|
+
/**
|
|
11
|
+
* Window-scoped singleton. Storing this on `window` (rather than in a module
|
|
12
|
+
* closure) preserves the original React "one embed per window" behavior even
|
|
13
|
+
* across multiple embedder instances or module re-evaluation (HMR).
|
|
14
|
+
*/
|
|
15
|
+
function getSingleton() {
|
|
16
|
+
const win = window;
|
|
17
|
+
if (!win[SINGLETON_KEY]) {
|
|
18
|
+
win[SINGLETON_KEY] = { initialized: false };
|
|
19
|
+
}
|
|
20
|
+
return win[SINGLETON_KEY];
|
|
21
|
+
}
|
|
22
|
+
function getOrCreateGlobalHost() {
|
|
23
|
+
let host = document.getElementById(GLOBAL_HOST_ID);
|
|
24
|
+
if (!host) {
|
|
25
|
+
host = document.createElement("div");
|
|
26
|
+
host.id = GLOBAL_HOST_ID;
|
|
27
|
+
document.body.appendChild(host);
|
|
28
|
+
}
|
|
29
|
+
return host;
|
|
30
|
+
}
|
|
31
|
+
function getDefaultEmbedOptions() {
|
|
32
|
+
const sfdcEnv = globalThis.SFDC_ENV;
|
|
33
|
+
return { salesforceOrigin: sfdcEnv?.orgUrl };
|
|
34
|
+
}
|
|
35
|
+
/** Drop keys with undefined/null values so they don't clobber defaults when spread. */
|
|
36
|
+
function stripUndefined(opts) {
|
|
37
|
+
return Object.fromEntries(Object.entries(opts).filter(([, v]) => v != null));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create an embedder bound to a low-level embed function.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* import { embedAgentforceClient } from "@salesforce/agentforce-conversation-client";
|
|
44
|
+
* import { createAccEmbedder } from "@salesforce/agentforce-conversation-client/ui-bundle";
|
|
45
|
+
*
|
|
46
|
+
* const embedder = createAccEmbedder(embedAgentforceClient);
|
|
47
|
+
* embedder.embedAcc(config, { salesforceOrigin }, hostEl, { onReady, onError });
|
|
48
|
+
*/
|
|
49
|
+
export function createAccEmbedder(embedFn) {
|
|
50
|
+
function embedAcc(config, overrides = {}, host, handlers) {
|
|
51
|
+
if (!config.agentId) {
|
|
52
|
+
throw new Error("AgentforceConversationClient requires agentId. " +
|
|
53
|
+
"Pass flat props only (agentId, agentLabel, inline, headerEnabled, showHeaderIcon, width, height, styleTokens).");
|
|
54
|
+
}
|
|
55
|
+
const inline = config.renderingConfig?.mode === INLINE_MODE;
|
|
56
|
+
if (inline && !host) {
|
|
57
|
+
// Inline host not yet in the DOM — the wrapper retries after render.
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const singleton = getSingleton();
|
|
61
|
+
if (singleton.initialized || singleton.initPromise) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const initialize = (options) => {
|
|
65
|
+
if (singleton.initialized) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (document.querySelector(EXISTING_EMBED_SELECTOR)) {
|
|
69
|
+
singleton.initialized = true;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const container = inline ? host : getOrCreateGlobalHost();
|
|
73
|
+
try {
|
|
74
|
+
// Lightning Out treats `org-url` and `frontdoor-url` as mutually
|
|
75
|
+
// exclusive — setting both throws. The dev frontdoor URL (localhost)
|
|
76
|
+
// wins when present; otherwise fall back to the org URL.
|
|
77
|
+
const useFrontdoor = Boolean(options.frontdoorUrl);
|
|
78
|
+
embedFn({
|
|
79
|
+
container,
|
|
80
|
+
salesforceOrigin: useFrontdoor ? undefined : options.salesforceOrigin,
|
|
81
|
+
frontdoorUrl: options.frontdoorUrl,
|
|
82
|
+
agentforceClientConfig: config,
|
|
83
|
+
onReady: handlers?.onReady,
|
|
84
|
+
onError: handlers?.onError,
|
|
85
|
+
});
|
|
86
|
+
singleton.initialized = true;
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
// Strip a partially-created LO element so the next mount can retry.
|
|
90
|
+
document.querySelector(EXISTING_EMBED_SELECTOR)?.remove();
|
|
91
|
+
console.error("AgentforceConversationClient: initialization failed", err);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const safeInitialize = (options) => {
|
|
95
|
+
try {
|
|
96
|
+
initialize(options);
|
|
97
|
+
}
|
|
98
|
+
catch (initErr) {
|
|
99
|
+
console.error("AgentforceConversationClient: initialization failed", initErr);
|
|
100
|
+
singleton.initialized = false;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const resolved = { ...getDefaultEmbedOptions(), ...stripUndefined(overrides) };
|
|
104
|
+
const shouldFetchFrontdoor = window.location.hostname === "localhost";
|
|
105
|
+
if (shouldFetchFrontdoor) {
|
|
106
|
+
singleton.initPromise = fetch("/__lo/frontdoor")
|
|
107
|
+
.then(async (res) => {
|
|
108
|
+
if (!res.ok) {
|
|
109
|
+
console.error("frontdoor fetch failed");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const { frontdoorUrl: resolvedFrontdoorUrl } = await res.json();
|
|
113
|
+
// An explicit caller-supplied frontdoorUrl override wins over the dev
|
|
114
|
+
// `/__lo/frontdoor` value; otherwise fall back to the fetched one.
|
|
115
|
+
safeInitialize({
|
|
116
|
+
...resolved,
|
|
117
|
+
frontdoorUrl: resolved.frontdoorUrl ?? resolvedFrontdoorUrl,
|
|
118
|
+
});
|
|
119
|
+
})
|
|
120
|
+
.catch((err) => {
|
|
121
|
+
console.error("AgentforceConversationClient: failed to fetch frontdoor URL", err);
|
|
122
|
+
})
|
|
123
|
+
.finally(() => {
|
|
124
|
+
singleton.initPromise = undefined;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
singleton.initPromise = Promise.resolve()
|
|
129
|
+
.then(() => {
|
|
130
|
+
safeInitialize(resolved);
|
|
131
|
+
})
|
|
132
|
+
.catch((err) => {
|
|
133
|
+
console.error("AgentforceConversationClient: failed to embed Agentforce client", err);
|
|
134
|
+
})
|
|
135
|
+
.finally(() => {
|
|
136
|
+
singleton.initPromise = undefined;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return { embedAcc };
|
|
141
|
+
}
|
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": "11.
|
|
4
|
+
"version": "11.51.0",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
13
13
|
"import": "./dist/index.js"
|
|
14
14
|
},
|
|
15
|
+
"./ui-bundle": {
|
|
16
|
+
"types": "./dist/ui-bundle.d.ts",
|
|
17
|
+
"import": "./dist/ui-bundle.js"
|
|
18
|
+
},
|
|
15
19
|
"./package.json": "./package.json"
|
|
16
20
|
},
|
|
17
21
|
"files": [
|