@salesforce/webapp-template-app-react-sample-b2x-experimental 1.79.2 → 1.80.1
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/.a4drules/features/feature-react-agentforce-conversation-client-embedded-agent-rule.md +7 -21
- package/dist/.a4drules/skills/feature-react-agentforce-conversation-client-embedded-agent/SKILL.md +69 -29
- package/dist/.a4drules/skills/feature-react-agentforce-conversation-client-embedded-agent/docs/embed-examples.md +42 -32
- package/dist/.a4drules/skills/feature-react-agentforce-conversation-client-embedded-agent/docs/troubleshooting.md +51 -0
- package/dist/CHANGELOG.md +16 -0
- package/dist/force-app/main/default/classes/WebAppAuthUtils.cls +68 -0
- package/dist/force-app/main/default/classes/WebAppAuthUtils.cls-meta.xml +5 -0
- package/dist/force-app/main/default/classes/WebAppChangePassword.cls +77 -0
- package/dist/force-app/main/default/classes/WebAppChangePassword.cls-meta.xml +5 -0
- package/dist/force-app/main/default/classes/WebAppForgotPassword.cls +71 -0
- package/dist/force-app/main/default/classes/WebAppForgotPassword.cls-meta.xml +5 -0
- package/dist/force-app/main/default/classes/WebAppLogin.cls +105 -0
- package/dist/force-app/main/default/classes/WebAppLogin.cls-meta.xml +5 -0
- package/dist/force-app/main/default/classes/WebAppRegistration.cls +162 -0
- package/dist/force-app/main/default/classes/WebAppRegistration.cls-meta.xml +5 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/package.json +3 -3
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/api/leadApi.ts +15 -6
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/app.tsx +4 -1
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/appLayout.tsx +155 -88
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/api/userProfileApi.ts +81 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/authHelpers.ts +73 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/authenticationConfig.ts +61 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/context/AuthContext.tsx +95 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/footers/footer-link.tsx +36 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/forms/auth-form.tsx +81 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/forms/submit-button.tsx +49 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/hooks/form.tsx +120 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/hooks/useCountdownTimer.ts +266 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/hooks/useRetryWithBackoff.ts +109 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/layout/card-skeleton.tsx +38 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/layout/centered-page-layout.tsx +87 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/layouts/AuthAppLayout.tsx +12 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/layouts/authenticationRouteLayout.tsx +21 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/layouts/privateRouteLayout.tsx +36 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/pages/ChangePassword.tsx +107 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/pages/ForgotPassword.tsx +73 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/pages/Login.tsx +97 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/pages/Profile.tsx +139 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/pages/Register.tsx +133 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/pages/ResetPassword.tsx +107 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/sessionTimeout/SessionTimeoutValidator.tsx +616 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/sessionTimeout/sessionTimeService.ts +161 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/sessionTimeout/sessionTimeoutConfig.ts +77 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/features/authentication/utils/helpers.ts +121 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/pages/Contact.tsx +201 -114
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/routes.tsx +67 -13
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/.a4drules/features/feature-react-agentforce-conversation-client-embedded-agent-rule.md
CHANGED
|
@@ -6,27 +6,13 @@ paths:
|
|
|
6
6
|
|
|
7
7
|
# Agentforce Conversation Client (standards)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## DO NOT build a chat UI from scratch
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
When the user asks for a chat UI, chat widget, chatbot, agent, or conversational interface — **always use the existing `AgentforceConversationClient` component** from `@salesforce/webapp-template-feature-react-agentforce-conversation-client-experimental`. Never generate a custom chat implementation, third-party chat library, WebSocket/REST chat, or direct calls to `embedAgentforceClient`.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
- Install with `npm install @salesforce/webapp-template-feature-react-agentforce-conversation-client-experimental`. The underlying SDK (`@salesforce/agentforce-conversation-client`) is included automatically as a dependency.
|
|
13
|
+
## Hard constraints
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
## Rendering mode
|
|
22
|
-
|
|
23
|
-
- Pass `agentforceClientConfig.renderingConfig.mode` to select **floating** (default) or **inline**. Do not apply custom positioning CSS to override the built-in layout.
|
|
24
|
-
- For inline mode, set `width` and `height` in `renderingConfig`. Do not override iframe dimensions with external CSS.
|
|
25
|
-
|
|
26
|
-
## Agent selection
|
|
27
|
-
|
|
28
|
-
- Use `agentforceClientConfig.agentId` to select a specific agent. Ask the user for the agent ID; if not provided, note that the org's default agent is used.
|
|
29
|
-
|
|
30
|
-
## Placement
|
|
31
|
-
|
|
32
|
-
- Render `<AgentforceConversationClient />` inside the existing app layout (e.g. alongside `<Outlet />`). Do not replace the entire page shell with the chat client.
|
|
15
|
+
- **`agentId` is required.** The component will not work without it. Always ask the user for their agent ID before generating code. Do not proceed without one.
|
|
16
|
+
- **Use the React wrapper only.** Import `AgentforceConversationClient` from the package. Never call `embedAgentforceClient` directly.
|
|
17
|
+
- **One instance per window.** Render in the app layout alongside `<Outlet />`, not on individual pages. The component is a singleton.
|
|
18
|
+
- **No auth hard-coding.** The component resolves `salesforceOrigin` and `frontdoorUrl` automatically.
|
package/dist/.a4drules/skills/feature-react-agentforce-conversation-client-embedded-agent/SKILL.md
CHANGED
|
@@ -1,13 +1,45 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: feature-react-agentforce-conversation-client-embedded-agent
|
|
3
|
-
description: Embed an Agentforce conversation client (chat UI) into a React web application. Use when the user wants to add an employee agent, a chat client, chatbot, chat widget, chat component, conversation client, or conversational interface to their React app. Also applies when the user asks to embed or integrate any Salesforce agent — including employee agent, travel agent, HR agent,
|
|
3
|
+
description: Embed an Agentforce conversation client (chat UI) into a React web application. Use when the user wants to add an employee agent, a chat client, chatbot, chat widget, chat component, conversation client, or conversational interface to their React app. Also applies when the user asks to embed or integrate any Salesforce agent — including employee agent, travel agent, HR agent, or any custom-named agent — or mentions Agentforce, Agentforce widget, Agentforce chat, or agent chat. ALWAYS use this skill instead of building a chat UI from scratch. Do NOT generate custom chat components, use third-party chat libraries, or create WebSocket/REST chat implementations. Do NOT use for non-React contexts or Lightning Web Components without React.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Embedded Agentforce chat (workflow)
|
|
7
7
|
|
|
8
8
|
When the user wants an embedded Agentforce chat client in a React app, follow this workflow.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## DO NOT build a chat UI from scratch
|
|
11
|
+
|
|
12
|
+
When the user asks for a chat UI, chat widget, chatbot, conversational interface, agent embed, or anything related to an embedded agent — **always use the `AgentforceConversationClient` component** from `@salesforce/webapp-template-feature-react-agentforce-conversation-client-experimental`.
|
|
13
|
+
|
|
14
|
+
**Never do any of the following:**
|
|
15
|
+
|
|
16
|
+
- Build a custom chat component from scratch (no custom message bubbles, input boxes, or chat layouts)
|
|
17
|
+
- Use third-party chat libraries (e.g. `react-chat-widget`, `stream-chat`, `chatscope`, or similar)
|
|
18
|
+
- Create WebSocket, polling, or REST-based chat implementations
|
|
19
|
+
- Generate custom HTML/CSS chat UIs
|
|
20
|
+
- Write a wrapper around `embedAgentforceClient` directly — always use the provided React component
|
|
21
|
+
|
|
22
|
+
If the user asks for chat functionality that goes beyond what `AgentforceConversationClient` supports (e.g. custom message rendering, message history, typing indicators), explain that the embedded Agentforce client handles all of this internally and cannot be customized beyond the supported `agentforceClientConfig` options (`renderingConfig`, `styleTokens`, `agentId`).
|
|
23
|
+
|
|
24
|
+
## CRITICAL: Agent ID is required
|
|
25
|
+
|
|
26
|
+
The Agentforce Conversation Client **will not work** without an `agentId`. There is no default agent — the component renders nothing and silently fails if `agentId` is missing. **Always ask the user for their agent ID before writing any code.**
|
|
27
|
+
|
|
28
|
+
> **Before proceeding:** Ask the user for their Salesforce agent ID (18-character record ID starting with `0Xx`). If they do not have one, direct them to **Setup → Agents** in their Salesforce org to find or create one. Do not generate code without an `agentId`.
|
|
29
|
+
|
|
30
|
+
## 1. Collect the agent ID
|
|
31
|
+
|
|
32
|
+
Ask the user:
|
|
33
|
+
|
|
34
|
+
- "What is your Salesforce agent ID? (You can find it in Setup → Agents → select an agent → copy the ID from the URL. It's an 18-character ID starting with `0Xx`.)"
|
|
35
|
+
|
|
36
|
+
If the user does not provide one:
|
|
37
|
+
|
|
38
|
+
- Explain that the conversation client **requires** an agent ID and will not function without it.
|
|
39
|
+
- Direct them to **Setup → Agents** in their org.
|
|
40
|
+
- Do **not** proceed to generate the embed code until an agent ID is provided.
|
|
41
|
+
|
|
42
|
+
## 2. Install the package
|
|
11
43
|
|
|
12
44
|
```bash
|
|
13
45
|
npm install @salesforce/webapp-template-feature-react-agentforce-conversation-client-experimental
|
|
@@ -15,16 +47,16 @@ npm install @salesforce/webapp-template-feature-react-agentforce-conversation-cl
|
|
|
15
47
|
|
|
16
48
|
This single install also brings in `@salesforce/agentforce-conversation-client` (the underlying SDK) automatically.
|
|
17
49
|
|
|
18
|
-
##
|
|
50
|
+
## 3. Use the shared wrapper
|
|
19
51
|
|
|
20
52
|
Use the `AgentforceConversationClient` React component. It resolves auth automatically:
|
|
21
53
|
|
|
22
54
|
- **Dev (localhost)**: fetches `frontdoorUrl` from `/__lo/frontdoor`
|
|
23
55
|
- **Prod (hosted in org)**: uses `salesforceOrigin` from `window.location.origin`
|
|
24
56
|
|
|
25
|
-
##
|
|
57
|
+
## 4. Embed in the layout
|
|
26
58
|
|
|
27
|
-
Render `<AgentforceConversationClient />` in the app layout so the chat client loads globally. Keep it alongside the existing layout (do not replace the page shell).
|
|
59
|
+
Render `<AgentforceConversationClient />` in the app layout so the chat client loads globally. Keep it alongside the existing layout (do not replace the page shell). **Always pass `agentId`.**
|
|
28
60
|
|
|
29
61
|
```tsx
|
|
30
62
|
import { Outlet } from "react-router";
|
|
@@ -34,37 +66,51 @@ export default function AppLayout() {
|
|
|
34
66
|
return (
|
|
35
67
|
<>
|
|
36
68
|
<Outlet />
|
|
37
|
-
<AgentforceConversationClient
|
|
69
|
+
<AgentforceConversationClient
|
|
70
|
+
agentforceClientConfig={{
|
|
71
|
+
agentId: "0Xx000000000000AAA",
|
|
72
|
+
}}
|
|
73
|
+
/>
|
|
38
74
|
</>
|
|
39
75
|
);
|
|
40
76
|
}
|
|
41
77
|
```
|
|
42
78
|
|
|
43
|
-
|
|
79
|
+
Replace `"0Xx000000000000AAA"` with the agent ID provided by the user.
|
|
44
80
|
|
|
45
|
-
|
|
81
|
+
## 5. Configure rendering and theming (optional)
|
|
46
82
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
| `agentId` |
|
|
52
|
-
| `
|
|
83
|
+
Pass additional options via the `agentforceClientConfig` prop:
|
|
84
|
+
|
|
85
|
+
| Option | Purpose | Required |
|
|
86
|
+
| ---------------------------------- | ---------------------------------------------------------- | -------- |
|
|
87
|
+
| `agentId` | The agent to load — **required, will not work without it** | **Yes** |
|
|
88
|
+
| `renderingConfig.mode` | `"floating"` (default) or `"inline"` | No |
|
|
89
|
+
| `renderingConfig.width` / `height` | Inline dimensions (number for px, string for CSS) | No |
|
|
90
|
+
| `styleTokens` | Theme colors and style overrides | No |
|
|
53
91
|
|
|
54
92
|
See [embed-examples.md](docs/embed-examples.md) for complete examples of each mode.
|
|
55
93
|
|
|
56
|
-
##
|
|
94
|
+
## 6. Validate prerequisites
|
|
95
|
+
|
|
96
|
+
Before the conversation client will work, the user must verify all of the following in their Salesforce org:
|
|
57
97
|
|
|
58
|
-
|
|
98
|
+
1. **Agent is active:** The org must have the agent referenced by `agentId` in an **Active** state and deployed to the correct channel (**Setup → Agents**).
|
|
99
|
+
2. **Trusted domains:** The org must allow `localhost:<PORT>` in **Trusted Domains for Inline Frames** (**Setup → Session Settings → Trusted Domains for Inline Frames**). Required for local development.
|
|
100
|
+
3. **First-party cookies disabled:** **"Require first party use of Salesforce cookies"** must be **unchecked/disabled** in **Setup → My Domain**. If this setting is enabled, the embedded conversation client will fail to authenticate and will not load.
|
|
59
101
|
|
|
60
102
|
## Quick reference: rendering modes
|
|
61
103
|
|
|
62
|
-
### Floating (default)
|
|
104
|
+
### Floating (default rendering mode)
|
|
63
105
|
|
|
64
|
-
A persistent chat widget overlay pinned to the bottom-right corner.
|
|
106
|
+
A persistent chat widget overlay pinned to the bottom-right corner. Floating is the default rendering mode — but `agentId` is still required.
|
|
65
107
|
|
|
66
108
|
```tsx
|
|
67
|
-
<AgentforceConversationClient
|
|
109
|
+
<AgentforceConversationClient
|
|
110
|
+
agentforceClientConfig={{
|
|
111
|
+
agentId: "0Xx000000000000AAA",
|
|
112
|
+
}}
|
|
113
|
+
/>
|
|
68
114
|
```
|
|
69
115
|
|
|
70
116
|
### Inline
|
|
@@ -74,6 +120,7 @@ The chat renders within the page layout at a specific size.
|
|
|
74
120
|
```tsx
|
|
75
121
|
<AgentforceConversationClient
|
|
76
122
|
agentforceClientConfig={{
|
|
123
|
+
agentId: "0Xx000000000000AAA",
|
|
77
124
|
renderingConfig: { mode: "inline", width: 420, height: 600 },
|
|
78
125
|
}}
|
|
79
126
|
/>
|
|
@@ -86,6 +133,7 @@ Use `styleTokens` to customize the chat appearance.
|
|
|
86
133
|
```tsx
|
|
87
134
|
<AgentforceConversationClient
|
|
88
135
|
agentforceClientConfig={{
|
|
136
|
+
agentId: "0Xx000000000000AAA",
|
|
89
137
|
styleTokens: {
|
|
90
138
|
headerBlockBackground: "#0176d3",
|
|
91
139
|
headerBlockTextColor: "#ffffff",
|
|
@@ -95,14 +143,6 @@ Use `styleTokens` to customize the chat appearance.
|
|
|
95
143
|
/>
|
|
96
144
|
```
|
|
97
145
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
Pass `agentId` to load a specific agent (e.g. travel agent, HR agent).
|
|
146
|
+
## Troubleshooting
|
|
101
147
|
|
|
102
|
-
|
|
103
|
-
<AgentforceConversationClient
|
|
104
|
-
agentforceClientConfig={{
|
|
105
|
-
agentId: "0Xx000000000000",
|
|
106
|
-
}}
|
|
107
|
-
/>
|
|
108
|
-
```
|
|
148
|
+
If the chat widget does not appear, fails to authenticate, or behaves unexpectedly, see [troubleshooting.md](docs/troubleshooting.md).
|
|
@@ -2,16 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
Detailed examples for configuring the Agentforce Conversation Client. All examples use the `AgentforceConversationClient` React component; the underlying `embedAgentforceClient` API accepts the same `agentforceClientConfig` shape.
|
|
4
4
|
|
|
5
|
+
> **Important:** Every example requires an `agentId`. The component will not render without one. There is no default agent. Replace `"0Xx000000000000AAA"` in every example with the user's actual agent ID.
|
|
6
|
+
|
|
5
7
|
---
|
|
6
8
|
|
|
7
|
-
## Floating mode (default)
|
|
9
|
+
## Floating mode (default rendering mode)
|
|
8
10
|
|
|
9
|
-
A floating chat widget appears in the bottom-right corner. It starts minimized and expands when the user clicks it.
|
|
11
|
+
A floating chat widget appears in the bottom-right corner. It starts minimized and expands when the user clicks it. Floating is the default rendering mode — no `renderingConfig` is needed — but `agentId` is always required.
|
|
10
12
|
|
|
11
|
-
### Minimal
|
|
13
|
+
### Minimal
|
|
12
14
|
|
|
13
15
|
```tsx
|
|
14
|
-
<AgentforceConversationClient
|
|
16
|
+
<AgentforceConversationClient
|
|
17
|
+
agentforceClientConfig={{
|
|
18
|
+
agentId: "0Xx000000000000AAA",
|
|
19
|
+
}}
|
|
20
|
+
/>
|
|
15
21
|
```
|
|
16
22
|
|
|
17
23
|
### Explicit floating
|
|
@@ -19,18 +25,19 @@ A floating chat widget appears in the bottom-right corner. It starts minimized a
|
|
|
19
25
|
```tsx
|
|
20
26
|
<AgentforceConversationClient
|
|
21
27
|
agentforceClientConfig={{
|
|
28
|
+
agentId: "0Xx000000000000AAA",
|
|
22
29
|
renderingConfig: { mode: "floating" },
|
|
23
30
|
}}
|
|
24
31
|
/>
|
|
25
32
|
```
|
|
26
33
|
|
|
27
|
-
### Floating with
|
|
34
|
+
### Floating with theming
|
|
28
35
|
|
|
29
36
|
```tsx
|
|
30
37
|
<AgentforceConversationClient
|
|
31
38
|
agentforceClientConfig={{
|
|
39
|
+
agentId: "0Xx000000000000AAA",
|
|
32
40
|
renderingConfig: { mode: "floating" },
|
|
33
|
-
agentId: "0Xx000000000000",
|
|
34
41
|
styleTokens: {
|
|
35
42
|
headerBlockBackground: "#032D60",
|
|
36
43
|
headerBlockTextColor: "#ffffff",
|
|
@@ -50,6 +57,7 @@ The chat renders inside the parent container at a specific size. Use this when t
|
|
|
50
57
|
```tsx
|
|
51
58
|
<AgentforceConversationClient
|
|
52
59
|
agentforceClientConfig={{
|
|
60
|
+
agentId: "0Xx000000000000AAA",
|
|
53
61
|
renderingConfig: { mode: "inline", width: 420, height: 600 },
|
|
54
62
|
}}
|
|
55
63
|
/>
|
|
@@ -60,6 +68,7 @@ The chat renders inside the parent container at a specific size. Use this when t
|
|
|
60
68
|
```tsx
|
|
61
69
|
<AgentforceConversationClient
|
|
62
70
|
agentforceClientConfig={{
|
|
71
|
+
agentId: "0Xx000000000000AAA",
|
|
63
72
|
renderingConfig: { mode: "inline", width: "100%", height: "80vh" },
|
|
64
73
|
}}
|
|
65
74
|
/>
|
|
@@ -73,6 +82,7 @@ The chat renders inside the parent container at a specific size. Use this when t
|
|
|
73
82
|
<aside style={{ width: 400 }}>
|
|
74
83
|
<AgentforceConversationClient
|
|
75
84
|
agentforceClientConfig={{
|
|
85
|
+
agentId: "0Xx000000000000AAA",
|
|
76
86
|
renderingConfig: { mode: "inline", width: "100%", height: "100%" },
|
|
77
87
|
}}
|
|
78
88
|
/>
|
|
@@ -91,6 +101,7 @@ Use `styleTokens` to customize colors. Tokens are passed directly to the Agentfo
|
|
|
91
101
|
```tsx
|
|
92
102
|
<AgentforceConversationClient
|
|
93
103
|
agentforceClientConfig={{
|
|
104
|
+
agentId: "0Xx000000000000AAA",
|
|
94
105
|
styleTokens: {
|
|
95
106
|
headerBlockBackground: "#0176d3",
|
|
96
107
|
headerBlockTextColor: "#ffffff",
|
|
@@ -104,6 +115,7 @@ Use `styleTokens` to customize colors. Tokens are passed directly to the Agentfo
|
|
|
104
115
|
```tsx
|
|
105
116
|
<AgentforceConversationClient
|
|
106
117
|
agentforceClientConfig={{
|
|
118
|
+
agentId: "0Xx000000000000AAA",
|
|
107
119
|
styleTokens: {
|
|
108
120
|
headerBlockBackground: "#0176d3",
|
|
109
121
|
headerBlockTextColor: "#ffffff",
|
|
@@ -118,6 +130,7 @@ Use `styleTokens` to customize colors. Tokens are passed directly to the Agentfo
|
|
|
118
130
|
```tsx
|
|
119
131
|
<AgentforceConversationClient
|
|
120
132
|
agentforceClientConfig={{
|
|
133
|
+
agentId: "0Xx000000000000AAA",
|
|
121
134
|
styleTokens: {
|
|
122
135
|
headerBlockBackground: "#1a1a2e",
|
|
123
136
|
headerBlockTextColor: "#e0e0e0",
|
|
@@ -129,40 +142,37 @@ Use `styleTokens` to customize colors. Tokens are passed directly to the Agentfo
|
|
|
129
142
|
|
|
130
143
|
---
|
|
131
144
|
|
|
132
|
-
##
|
|
133
|
-
|
|
134
|
-
Use `agentId` to load a specific agent from the org. If omitted, the org's default employee agent is used.
|
|
135
|
-
|
|
136
|
-
### Specific agent by ID
|
|
137
|
-
|
|
138
|
-
```tsx
|
|
139
|
-
<AgentforceConversationClient
|
|
140
|
-
agentforceClientConfig={{
|
|
141
|
-
agentId: "0Xx000000000000",
|
|
142
|
-
}}
|
|
143
|
-
/>
|
|
144
|
-
```
|
|
145
|
+
## Full layout example
|
|
145
146
|
|
|
146
|
-
|
|
147
|
+
Shows the recommended pattern: agent ID passed directly, single render in the app layout.
|
|
147
148
|
|
|
148
149
|
```tsx
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
150
|
+
import { Outlet } from "react-router";
|
|
151
|
+
import { AgentforceConversationClient } from "@salesforce/webapp-template-feature-react-agentforce-conversation-client-experimental";
|
|
152
|
+
|
|
153
|
+
export default function AppLayout() {
|
|
154
|
+
return (
|
|
155
|
+
<>
|
|
156
|
+
<Outlet />
|
|
157
|
+
<AgentforceConversationClient
|
|
158
|
+
agentforceClientConfig={{
|
|
159
|
+
agentId: "0Xx000000000000AAA",
|
|
160
|
+
styleTokens: {
|
|
161
|
+
headerBlockBackground: "#0176d3",
|
|
162
|
+
headerBlockTextColor: "#ffffff",
|
|
163
|
+
},
|
|
164
|
+
}}
|
|
165
|
+
/>
|
|
166
|
+
</>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
159
169
|
```
|
|
160
170
|
|
|
161
171
|
---
|
|
162
172
|
|
|
163
173
|
## Using the low-level `embedAgentforceClient` API
|
|
164
174
|
|
|
165
|
-
The React component wraps `embedAgentforceClient`. If you need the raw API (e.g. in a non-React context), the config shape is the same:
|
|
175
|
+
The React component wraps `embedAgentforceClient`. If you need the raw API (e.g. in a non-React context), the config shape is the same — `agentId` is still required:
|
|
166
176
|
|
|
167
177
|
```ts
|
|
168
178
|
import { embedAgentforceClient } from "@salesforce/agentforce-conversation-client";
|
|
@@ -171,7 +181,7 @@ const { loApp, chatClientComponent } = embedAgentforceClient({
|
|
|
171
181
|
container: "#agentforce-container",
|
|
172
182
|
salesforceOrigin: "https://myorg.my.salesforce.com",
|
|
173
183
|
agentforceClientConfig: {
|
|
174
|
-
agentId: "
|
|
184
|
+
agentId: "0Xx000000000000AAA",
|
|
175
185
|
renderingConfig: { mode: "floating" },
|
|
176
186
|
styleTokens: {
|
|
177
187
|
headerBlockBackground: "#0176d3",
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Common issues when using the Agentforce Conversation Client.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
### Chat widget does not appear
|
|
8
|
+
|
|
9
|
+
**Cause:** Missing or invalid `agentId`. The component will not render anything without a valid agent ID.
|
|
10
|
+
|
|
11
|
+
**Solution:**
|
|
12
|
+
|
|
13
|
+
1. Verify `agentId` is passed in `agentforceClientConfig` — it is required
|
|
14
|
+
2. Confirm the ID is correct (18-character Salesforce record ID, starts with `0Xx`)
|
|
15
|
+
3. Check that the agent exists and is **Active** in **Setup → Agents**
|
|
16
|
+
|
|
17
|
+
### Chat loads but shows "agent not available"
|
|
18
|
+
|
|
19
|
+
**Cause:** The agent exists but is not deployed or is inactive.
|
|
20
|
+
|
|
21
|
+
**Solution:**
|
|
22
|
+
|
|
23
|
+
1. In **Setup → Agents**, ensure the agent status is **Active**
|
|
24
|
+
2. Verify the agent is deployed to the correct channel
|
|
25
|
+
|
|
26
|
+
### Authentication error on localhost
|
|
27
|
+
|
|
28
|
+
**Cause:** `localhost:<PORT>` is not in the org's trusted domains for inline frames.
|
|
29
|
+
|
|
30
|
+
**Solution:**
|
|
31
|
+
|
|
32
|
+
1. Go to **Setup → Session Settings → Trusted Domains for Inline Frames**
|
|
33
|
+
2. Add `localhost:<PORT>` (e.g. `localhost:3000`)
|
|
34
|
+
3. Restart the dev server
|
|
35
|
+
|
|
36
|
+
### Chat fails to authenticate / blank iframe
|
|
37
|
+
|
|
38
|
+
**Cause:** "Require first party use of Salesforce cookies" is enabled in the org's session settings. This blocks the embedded client from establishing a session.
|
|
39
|
+
|
|
40
|
+
**Solution:**
|
|
41
|
+
|
|
42
|
+
1. Go to **Setup → Session Settings**
|
|
43
|
+
2. Find **"Require first party use of Salesforce cookies"**
|
|
44
|
+
3. **Uncheck / disable** this setting
|
|
45
|
+
4. Save and reload the app
|
|
46
|
+
|
|
47
|
+
### Multiple chat widgets appear
|
|
48
|
+
|
|
49
|
+
**Cause:** `AgentforceConversationClient` is rendered in multiple places.
|
|
50
|
+
|
|
51
|
+
**Solution:** Render it once in the app layout, not on individual pages. The component uses a singleton pattern — only one instance should exist per window.
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.80.1](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.80.0...v1.80.1) (2026-03-09)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# [1.80.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.79.2...v1.80.0) (2026-03-07)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
## [1.79.2](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.79.1...v1.79.2) (2026-03-06)
|
|
7
23
|
|
|
8
24
|
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility class for Web Application authentication REST endpoints.
|
|
3
|
+
*/
|
|
4
|
+
public without sharing class WebAppAuthUtils {
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Exception for authentication errors with HTTP status code support.
|
|
8
|
+
*/
|
|
9
|
+
public class AuthException extends Exception {
|
|
10
|
+
public Integer statusCode { get; private set; } // HTTP status code (e.g. 400, 500)
|
|
11
|
+
public List<String> messages { get; private set; } // List of error messages
|
|
12
|
+
|
|
13
|
+
public AuthException(Integer statusCode, String message) {
|
|
14
|
+
this.statusCode = statusCode;
|
|
15
|
+
this.messages = new List<String>{ message };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public AuthException(Integer statusCode, List<String> messages) {
|
|
19
|
+
this.statusCode = statusCode;
|
|
20
|
+
this.messages = new List<String>(messages);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Validates and sanitizes redirect URL to prevent open redirect vulnerabilities.
|
|
26
|
+
* @param url The URL to validate.
|
|
27
|
+
* @param defaultUrl Fallback URL if validation fails.
|
|
28
|
+
* @return Sanitized URL or defaultUrl if invalid.
|
|
29
|
+
*/
|
|
30
|
+
public static String getSanitizedStartUrl(String url, String defaultUrl) {
|
|
31
|
+
if (String.isBlank(url) || url.equals('/')) { return defaultUrl; }
|
|
32
|
+
|
|
33
|
+
String decoded; // Decode URL to catch encoded bypasses (%2f%2f -> //)
|
|
34
|
+
try {
|
|
35
|
+
decoded = EncodingUtil.urlDecode(url, 'UTF-8');
|
|
36
|
+
} catch (Exception e) {
|
|
37
|
+
return defaultUrl;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Must start with / but not // (protocol-relative)
|
|
41
|
+
if (!decoded.startsWith('/') || decoded.startsWith('//')) { return defaultUrl; }
|
|
42
|
+
// Reject backslashes (some browsers treat \ as /)
|
|
43
|
+
if (decoded.contains('\\')) { return defaultUrl; }
|
|
44
|
+
// Reject @ which can indicate user info in URL (//user@evil.com)
|
|
45
|
+
if (decoded.contains('@')) { return defaultUrl; }
|
|
46
|
+
// Reject : which could indicate protocol or port manipulation
|
|
47
|
+
if (decoded.contains(':')) { return defaultUrl; }
|
|
48
|
+
// Reject control characters (ASCII < 32) and DEL (127)
|
|
49
|
+
for (Integer i = 0; i < decoded.length(); i++) {
|
|
50
|
+
Integer charCode = decoded.charAt(i);
|
|
51
|
+
if (charCode < 32 || charCode == 127) { return defaultUrl; }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return defaultUrl + url;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Logs an error message and stack trace to the system debug log.
|
|
59
|
+
* It is only captured if a Trace Flag is active for the user.
|
|
60
|
+
*
|
|
61
|
+
* @param ex The exception to log.
|
|
62
|
+
* @param level The logging level to use.
|
|
63
|
+
*/
|
|
64
|
+
public static void debugLog(Exception ex, LoggingLevel level) {
|
|
65
|
+
System.debug(level, 'Message: ' + ex.getMessage());
|
|
66
|
+
System.debug(level, 'Stack Trace: ' + ex.getStackTraceString());
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Applications REST endpoint for authenticated user password changes.
|
|
3
|
+
*
|
|
4
|
+
* Endpoint: POST /services/apexrest/auth/change-password
|
|
5
|
+
*
|
|
6
|
+
* Allows authenticated users to change their password by providing their current password
|
|
7
|
+
* and a new password. The new password is validated against org password policies.
|
|
8
|
+
*
|
|
9
|
+
* Security: Uses 'with sharing' to enforce user-level security. Only authenticated users
|
|
10
|
+
* can change their own password.
|
|
11
|
+
*/
|
|
12
|
+
@RestResource(urlMapping='/auth/change-password')
|
|
13
|
+
global with sharing class WebAppChangePassword {
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Changes the password for the currently authenticated user.
|
|
17
|
+
*
|
|
18
|
+
* @param newPassword The new password to set.
|
|
19
|
+
* @param currentPassword The user's current password for verification.
|
|
20
|
+
* @return SuccessPasswordChangeResponse on success, ErrorPasswordChangeResponse on failure.
|
|
21
|
+
*/
|
|
22
|
+
@HttpPost
|
|
23
|
+
global static PasswordChangeResponse changePassword(String newPassword, String currentPassword) {
|
|
24
|
+
Savepoint sp = Database.setSavepoint();
|
|
25
|
+
try {
|
|
26
|
+
// newPassword and confirmPassword should be validated to be the same value on the client
|
|
27
|
+
Site.changePassword(newPassword, newPassword, currentPassword);
|
|
28
|
+
return new SuccessPasswordChangeResponse();
|
|
29
|
+
} catch (Exception ex) {
|
|
30
|
+
Database.rollback(sp);
|
|
31
|
+
|
|
32
|
+
// System.SecurityException is a user error but treat others as system errors
|
|
33
|
+
if (ex instanceof System.SecurityException) {
|
|
34
|
+
RestContext.response.statusCode = 400;
|
|
35
|
+
return new ErrorPasswordChangeResponse(ex.getMessage());
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Logs are only captured if a Trace Flag is active for the user
|
|
39
|
+
WebAppAuthUtils.debugLog(ex, LoggingLevel.ERROR);
|
|
40
|
+
|
|
41
|
+
RestContext.response.statusCode = 500;
|
|
42
|
+
return new ErrorPasswordChangeResponse('Password change failed');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Base response class for password change operations. */
|
|
47
|
+
global abstract class PasswordChangeResponse {
|
|
48
|
+
|
|
49
|
+
/** Success or failure of the password change operation */
|
|
50
|
+
protected final Boolean success;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Success response for password change. */
|
|
54
|
+
global class SuccessPasswordChangeResponse extends PasswordChangeResponse {
|
|
55
|
+
|
|
56
|
+
/** Constructs a success response. */
|
|
57
|
+
private SuccessPasswordChangeResponse() {
|
|
58
|
+
this.success = true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Error response for password change. */
|
|
63
|
+
global class ErrorPasswordChangeResponse extends PasswordChangeResponse {
|
|
64
|
+
|
|
65
|
+
/** Error message describing the failure reason */
|
|
66
|
+
private final String error;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Constructs an error response with the specified error message.
|
|
70
|
+
* @param error The error message to return to the client.
|
|
71
|
+
*/
|
|
72
|
+
private ErrorPasswordChangeResponse(String error) {
|
|
73
|
+
this.success = false;
|
|
74
|
+
this.error = error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|