@salesforce/webapp-template-feature-react-global-search-experimental 1.110.1 → 1.112.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/.a4drules/skills/creating-webapp/SKILL.md +1 -2
- package/dist/.a4drules/skills/deploying-to-salesforce/SKILL.md +1 -2
- package/dist/.a4drules/skills/using-salesforce-data/SKILL.md +268 -0
- package/dist/CHANGELOG.md +19 -0
- package/dist/force-app/main/default/webapplications/feature-react-global-search/package.json +3 -3
- package/dist/package-lock.json +2 -2
- package/dist/package.json +1 -1
- package/package.json +1 -1
- package/dist/.a4drules/skills/accessing-data/SKILL.md +0 -178
- package/dist/.a4drules/skills/exploring-graphql-schema/SKILL.md +0 -149
- package/dist/.a4drules/skills/fetching-rest-api/SKILL.md +0 -167
- package/dist/.a4drules/skills/generating-graphql-mutation-query/SKILL.md +0 -258
- package/dist/.a4drules/skills/generating-graphql-read-query/SKILL.md +0 -253
- package/dist/.a4drules/skills/using-graphql/SKILL.md +0 -324
- package/dist/.a4drules/skills/using-graphql/shared-schema.graphqls +0 -1150
|
@@ -111,7 +111,7 @@ Apps run behind dynamic base paths. Router navigation (`<Link to>`, `navigate()`
|
|
|
111
111
|
|
|
112
112
|
## Module Restrictions
|
|
113
113
|
|
|
114
|
-
React apps must NOT import Salesforce platform modules like `lightning/*` or `@wire` (LWC-only). For data access, invoke the **
|
|
114
|
+
React apps must NOT import Salesforce platform modules like `lightning/*` or `@wire` (LWC-only). For data access, invoke the **using-salesforce-data** skill.
|
|
115
115
|
|
|
116
116
|
# Frontend Aesthetics
|
|
117
117
|
|
|
@@ -138,4 +138,3 @@ Only stop when:
|
|
|
138
138
|
- All checklist items are completed and quality gates pass, or
|
|
139
139
|
- A blocking error cannot be resolved after reasonable remediation, or
|
|
140
140
|
- The user explicitly asks to pause.
|
|
141
|
-
|
|
@@ -225,5 +225,4 @@ The project includes `scripts/setup-cli.mjs` which runs this sequence in batch.
|
|
|
225
225
|
|
|
226
226
|
## Related Skills
|
|
227
227
|
|
|
228
|
-
- **
|
|
229
|
-
- **using-graphql** — Full GraphQL workflow (explore, query, codegen, lint)
|
|
228
|
+
- **using-salesforce-data** — Full data access workflow (GraphQL queries/mutations, REST APIs, schema exploration, webapp integration)
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: using-salesforce-data
|
|
3
|
+
description: Salesforce data access for reads, mutations, and REST APIs. Use when the user wants to fetch, display, create, update, or delete Salesforce records; add data fetching to a component; query Accounts, Contacts, Opportunities, or custom objects; call Chatter, Connect, or Apex REST APIs; or integrate Salesforce data into a webapp.
|
|
4
|
+
paths:
|
|
5
|
+
- "**/*.ts"
|
|
6
|
+
- "**/*.tsx"
|
|
7
|
+
- "**/*.graphql"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Salesforce Data Access
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
Use this skill when the user wants to:
|
|
15
|
+
|
|
16
|
+
- **Fetch or display Salesforce data** — Query records (Account, Contact, Opportunity, custom objects) to show in a component
|
|
17
|
+
- **Create, update, or delete records** — Perform mutations on Salesforce data
|
|
18
|
+
- **Add data fetching to a component** — Wire up a React component to Salesforce data
|
|
19
|
+
- **Call REST APIs** — Use Chatter, Connect, Apex REST, or UI API endpoints
|
|
20
|
+
- **Explore the org schema** — Discover available objects, fields, or relationships
|
|
21
|
+
|
|
22
|
+
## Data SDK Requirement
|
|
23
|
+
|
|
24
|
+
> **All Salesforce data access MUST use the Data SDK** (`@salesforce/sdk-data`). The SDK handles authentication, CSRF, and base URL resolution. Never use `fetch()` or `axios` directly.
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { createDataSDK, gql } from "@salesforce/sdk-data";
|
|
28
|
+
|
|
29
|
+
const sdk = await createDataSDK();
|
|
30
|
+
|
|
31
|
+
// GraphQL for record queries/mutations (PREFERRED)
|
|
32
|
+
const response = await sdk.graphql?.<ResponseType>(query, variables);
|
|
33
|
+
|
|
34
|
+
// REST for Chatter, Connect, Apex REST (when GraphQL insufficient)
|
|
35
|
+
const res = await sdk.fetch?.("/services/data/v65.0/chatter/users/me");
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Always use optional chaining** (`sdk.graphql?.()`, `sdk.fetch?.()`) — these methods may be undefined in some surfaces.
|
|
39
|
+
|
|
40
|
+
## Decision: GraphQL vs REST
|
|
41
|
+
|
|
42
|
+
| Need | Method | Example |
|
|
43
|
+
|------|--------|---------|
|
|
44
|
+
| Query/mutate records | `sdk.graphql` | Account, Contact, custom objects |
|
|
45
|
+
| Chatter API | `sdk.fetch` | `/chatter/users/me` |
|
|
46
|
+
| Connect REST | `sdk.fetch` | `/connect/file/upload/config` |
|
|
47
|
+
| Apex REST | `sdk.fetch` | `/services/apexrest/auth/login` |
|
|
48
|
+
| Einstein LLM | `sdk.fetch` | `/einstein/llm/prompt/generations` |
|
|
49
|
+
|
|
50
|
+
**GraphQL is preferred** for record operations. Use REST only when GraphQL doesn't cover the use case.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## GraphQL Workflow
|
|
55
|
+
|
|
56
|
+
### Step 1: Acquire Schema
|
|
57
|
+
|
|
58
|
+
The `schema.graphql` file (265K+ lines) is the source of truth. **Use grep only** — never open or parse the file directly.
|
|
59
|
+
|
|
60
|
+
1. Check if `schema.graphql` exists at the SFDX project root
|
|
61
|
+
2. If missing, run from the **webapp dir**: `npm run graphql:schema`
|
|
62
|
+
3. Custom objects appear only after metadata is deployed
|
|
63
|
+
|
|
64
|
+
### Step 2: Identify & Introspect Entities
|
|
65
|
+
|
|
66
|
+
Map user intent to PascalCase names ("accounts" → `Account`). Validate via grep:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# From project root — find entity fields
|
|
70
|
+
grep -nE '^type Account implements Record' ./schema.graphql -A 100
|
|
71
|
+
|
|
72
|
+
# Find filter options
|
|
73
|
+
grep -nE '^input Account_Filter' ./schema.graphql -A 50
|
|
74
|
+
|
|
75
|
+
# Find mutation input
|
|
76
|
+
grep -nE '^input AccountCreateInput' ./schema.graphql -A 50
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Maximum 3 introspection cycles.** If entities remain unknown, ask the user.
|
|
80
|
+
|
|
81
|
+
### Step 3: Generate Query
|
|
82
|
+
|
|
83
|
+
Use the templates below. Every field name **must** be verified via grep.
|
|
84
|
+
|
|
85
|
+
#### Read Query Template
|
|
86
|
+
|
|
87
|
+
```graphql
|
|
88
|
+
query GetAccounts {
|
|
89
|
+
uiapi {
|
|
90
|
+
query {
|
|
91
|
+
Account(where: { Industry: { eq: "Technology" } }, first: 10) {
|
|
92
|
+
edges {
|
|
93
|
+
node {
|
|
94
|
+
Id
|
|
95
|
+
Name @optional { value }
|
|
96
|
+
Industry @optional { value }
|
|
97
|
+
# Parent relationship
|
|
98
|
+
Owner @optional { Name { value } }
|
|
99
|
+
# Child relationship
|
|
100
|
+
Contacts @optional {
|
|
101
|
+
edges { node { Name @optional { value } } }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**FLS Resilience**: Apply `@optional` to all record fields. The server omits inaccessible fields instead of failing. Consuming code must use optional chaining:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
const name = node.Name?.value ?? "";
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Mutation Template
|
|
118
|
+
|
|
119
|
+
```graphql
|
|
120
|
+
mutation CreateAccount($input: AccountCreateInput!) {
|
|
121
|
+
uiapi {
|
|
122
|
+
AccountCreate(input: $input) {
|
|
123
|
+
Record { Id Name { value } }
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Mutation constraints:**
|
|
130
|
+
- Create: Include required fields, only `createable` fields, no child relationships
|
|
131
|
+
- Update: Include `Id`, only `updateable` fields
|
|
132
|
+
- Delete: Include `Id` only
|
|
133
|
+
|
|
134
|
+
### Step 4: Validate & Test
|
|
135
|
+
|
|
136
|
+
1. **Lint**: `npx eslint <file>` from webapp dir
|
|
137
|
+
2. **Test**: Ask user before testing. For mutations, request input values — never fabricate data.
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# From project root
|
|
141
|
+
sf api request rest /services/data/v65.0/graphql \
|
|
142
|
+
--method POST \
|
|
143
|
+
--body '{"query":"..."}'
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Webapp Integration (React)
|
|
149
|
+
|
|
150
|
+
### Pattern 1: External .graphql File (Recommended)
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { createDataSDK, type NodeOfConnection } from "@salesforce/sdk-data";
|
|
154
|
+
import GET_ACCOUNTS from "./query/getAccounts.graphql?raw";
|
|
155
|
+
import type { GetAccountsQuery } from "../graphql-operations-types";
|
|
156
|
+
|
|
157
|
+
const sdk = await createDataSDK();
|
|
158
|
+
const response = await sdk.graphql?.<GetAccountsQuery>(GET_ACCOUNTS);
|
|
159
|
+
|
|
160
|
+
if (response?.errors?.length) {
|
|
161
|
+
throw new Error(response.errors.map(e => e.message).join("; "));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const accounts = response?.data?.uiapi?.query?.Account?.edges?.map(e => e.node) ?? [];
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
After creating/modifying `.graphql` files, run: `npm run graphql:codegen`
|
|
168
|
+
|
|
169
|
+
### Pattern 2: Inline gql Tag
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
import { createDataSDK, gql } from "@salesforce/sdk-data";
|
|
173
|
+
|
|
174
|
+
const GET_CURRENT_USER = gql`
|
|
175
|
+
query CurrentUser {
|
|
176
|
+
uiapi { currentUser { Id Name { value } } }
|
|
177
|
+
}
|
|
178
|
+
`;
|
|
179
|
+
|
|
180
|
+
const response = await sdk.graphql?.<CurrentUserQuery>(GET_CURRENT_USER);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Must use `gql` tag** — plain template strings bypass ESLint validation.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## REST API Patterns
|
|
188
|
+
|
|
189
|
+
Use `sdk.fetch` when GraphQL is insufficient:
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
declare const __SF_API_VERSION__: string;
|
|
193
|
+
const API_VERSION = typeof __SF_API_VERSION__ !== "undefined" ? __SF_API_VERSION__ : "65.0";
|
|
194
|
+
|
|
195
|
+
// Chatter — current user
|
|
196
|
+
const res = await sdk.fetch?.(`/services/data/v${API_VERSION}/chatter/users/me`);
|
|
197
|
+
|
|
198
|
+
// Connect — file upload config
|
|
199
|
+
const res = await sdk.fetch?.(`/services/data/v${API_VERSION}/connect/file/upload/config`);
|
|
200
|
+
|
|
201
|
+
// Apex REST (no version in path)
|
|
202
|
+
const res = await sdk.fetch?.("/services/apexrest/auth/login", {
|
|
203
|
+
method: "POST",
|
|
204
|
+
body: JSON.stringify({ email, password }),
|
|
205
|
+
headers: { "Content-Type": "application/json" },
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Einstein LLM
|
|
209
|
+
const res = await sdk.fetch?.(`/services/data/v${API_VERSION}/einstein/llm/prompt/generations`, {
|
|
210
|
+
method: "POST",
|
|
211
|
+
body: JSON.stringify({ promptTextorId: prompt }),
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Directory Structure
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
<project-root>/ ← SFDX project root
|
|
221
|
+
├── schema.graphql ← grep target (lives here)
|
|
222
|
+
├── sfdx-project.json
|
|
223
|
+
└── force-app/main/default/webapplications/<app-name>/ ← webapp dir
|
|
224
|
+
├── package.json ← npm scripts
|
|
225
|
+
├── codegen.yml
|
|
226
|
+
└── src/
|
|
227
|
+
└── api/graphql-operations-types.ts ← generated types
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
| Command | Run From | Why |
|
|
231
|
+
|---------|----------|-----|
|
|
232
|
+
| `npm run graphql:schema` | webapp dir | Script in webapp's package.json |
|
|
233
|
+
| `npm run graphql:codegen` | webapp dir | Reads codegen.yml |
|
|
234
|
+
| `npx eslint <file>` | webapp dir | Reads eslint.config.js |
|
|
235
|
+
| `grep ... schema.graphql` | project root | Schema lives at root |
|
|
236
|
+
| `sf api request rest` | project root | Needs sfdx-project.json |
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Quick Reference
|
|
241
|
+
|
|
242
|
+
### Grep Patterns (from project root)
|
|
243
|
+
|
|
244
|
+
| Pattern | Context | Purpose |
|
|
245
|
+
|---------|---------|---------|
|
|
246
|
+
| `^type <Entity> implements Record` | `-A 100` | Entity fields |
|
|
247
|
+
| `^input <Entity>_Filter` | `-A 50` | Filter options |
|
|
248
|
+
| `^input <Entity>_OrderBy` | `-A 30` | Sort options |
|
|
249
|
+
| `^input <Entity>CreateInput` | `-A 50` | Create mutation input |
|
|
250
|
+
| `^input <Entity>UpdateInput` | `-A 50` | Update mutation input |
|
|
251
|
+
|
|
252
|
+
### Error Categories
|
|
253
|
+
|
|
254
|
+
| Error Contains | Resolution |
|
|
255
|
+
|----------------|------------|
|
|
256
|
+
| `invalid syntax` | Fix syntax per error message |
|
|
257
|
+
| `validation error` | Re-grep to verify field name |
|
|
258
|
+
| `VariableTypeMismatch` | Correct argument type from schema |
|
|
259
|
+
| `invalid cross reference id` | Entity deleted — ask for valid Id |
|
|
260
|
+
|
|
261
|
+
### Checklist
|
|
262
|
+
|
|
263
|
+
- [ ] All field names verified via grep
|
|
264
|
+
- [ ] `@optional` applied to record fields (reads)
|
|
265
|
+
- [ ] Optional chaining in consuming code
|
|
266
|
+
- [ ] `gql` tag used (not plain strings)
|
|
267
|
+
- [ ] Lint passes: `npx eslint <file>`
|
|
268
|
+
- [ ] Types generated: `npm run graphql:codegen`
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
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.112.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.111.0...v1.112.0) (2026-03-20)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* unify 4 GraphQL skills into single using-graphql skill ([#325](https://github.com/salesforce-experience-platform-emu/webapps/issues/325)) ([3935407](https://github.com/salesforce-experience-platform-emu/webapps/commit/393540779c2da76d7f181f62738aa3d4613a2805))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [1.111.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.110.1...v1.111.0) (2026-03-19)
|
|
18
|
+
|
|
19
|
+
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
6
25
|
## [1.110.1](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.110.0...v1.110.1) (2026-03-19)
|
|
7
26
|
|
|
8
27
|
|
package/dist/force-app/main/default/webapplications/feature-react-global-search/package.json
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"graphql:schema": "node scripts/get-graphql-schema.mjs"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@salesforce/sdk-data": "^1.
|
|
19
|
-
"@salesforce/webapp-experimental": "^1.
|
|
18
|
+
"@salesforce/sdk-data": "^1.112.0",
|
|
19
|
+
"@salesforce/webapp-experimental": "^1.112.0",
|
|
20
20
|
"@tailwindcss/vite": "^4.1.17",
|
|
21
21
|
"class-variance-authority": "^0.7.1",
|
|
22
22
|
"clsx": "^2.1.1",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@graphql-eslint/eslint-plugin": "^4.1.0",
|
|
44
44
|
"@graphql-tools/utils": "^11.0.0",
|
|
45
45
|
"@playwright/test": "^1.49.0",
|
|
46
|
-
"@salesforce/vite-plugin-webapp-experimental": "^1.
|
|
46
|
+
"@salesforce/vite-plugin-webapp-experimental": "^1.112.0",
|
|
47
47
|
"@testing-library/jest-dom": "^6.6.3",
|
|
48
48
|
"@testing-library/react": "^16.1.0",
|
|
49
49
|
"@testing-library/user-event": "^14.5.2",
|
package/dist/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/webapp-template-base-sfdx-project-experimental",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.112.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@salesforce/webapp-template-base-sfdx-project-experimental",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.112.0",
|
|
10
10
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"@lwc/eslint-plugin-lwc": "^3.3.0",
|
package/dist/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/webapp-template-feature-react-global-search-experimental",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.112.0",
|
|
4
4
|
"description": "Global search feature for Salesforce objects with filtering and pagination",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"author": "",
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: accessing-data
|
|
3
|
-
description: Salesforce data access patterns. Use when adding or modifying any code that fetches data from Salesforce (records, Chatter, Connect API, etc.).
|
|
4
|
-
paths:
|
|
5
|
-
- "**/*.ts"
|
|
6
|
-
- "**/*.tsx"
|
|
7
|
-
- "**/*.graphql"
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# Salesforce Data Access
|
|
11
|
-
|
|
12
|
-
Guidance for accessing Salesforce data from web apps. **All Salesforce data fetches MUST use the Data SDK** (`@salesforce/sdk-data`). The SDK provides authentication, CSRF handling, and correct base URL resolution — direct `fetch` or `axios` calls bypass these and are not allowed.
|
|
13
|
-
|
|
14
|
-
## Mandatory: Use the Data SDK
|
|
15
|
-
|
|
16
|
-
> **Every Salesforce data fetch must go through the Data SDK.** Obtain it via `createDataSDK()`, then use `sdk.graphql?.()` or `sdk.fetch?.()`. Never call `fetch()` or `axios` directly for Salesforce endpoints.
|
|
17
|
-
|
|
18
|
-
## Optional Chaining and Graceful Handling
|
|
19
|
-
|
|
20
|
-
**Always use optional chaining** when calling `sdk.graphql` or `sdk.fetch` — these methods may be undefined in some surfaces (e.g., Salesforce ACC, MCP Apps). Handle the case where they are not available gracefully:
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
const sdk = await createDataSDK();
|
|
24
|
-
|
|
25
|
-
// ✅ Use optional chaining
|
|
26
|
-
const response = await sdk.graphql?.(query);
|
|
27
|
-
|
|
28
|
-
// ✅ Check before using fetch
|
|
29
|
-
if (!sdk.fetch) {
|
|
30
|
-
throw new Error("Data SDK fetch is not available in this context");
|
|
31
|
-
}
|
|
32
|
-
const res = await sdk.fetch(url);
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
For GraphQL, if `sdk.graphql` is undefined, the call returns `undefined` — handle that in your logic (e.g., throw a clear error or return a fallback). For `sdk.fetch`, check availability before calling when the operation is required.
|
|
36
|
-
|
|
37
|
-
## Preference: GraphQL First
|
|
38
|
-
|
|
39
|
-
**GraphQL is the preferred method** for querying and mutating Salesforce records. Use it when:
|
|
40
|
-
|
|
41
|
-
- Querying records (Account, Contact, Opportunity, custom objects)
|
|
42
|
-
- Creating, updating, or deleting records (when GraphQL supports the operation)
|
|
43
|
-
- Fetching related data, filters, sorting, pagination
|
|
44
|
-
|
|
45
|
-
**Use `sdk.fetch` only when GraphQL is not sufficient.** For REST API usage, invoke the `fetching-rest-api` skill, which documents:
|
|
46
|
-
|
|
47
|
-
- Chatter API (e.g., `/services/data/v65.0/chatter/users/me`)
|
|
48
|
-
- Connect REST API (e.g., `/services/data/v65.0/connect/file/upload/config`)
|
|
49
|
-
- Apex REST (e.g., `/services/apexrest/auth/login`)
|
|
50
|
-
- UI API REST (e.g., `/services/data/v65.0/ui-api/records/{recordId}`)
|
|
51
|
-
- Einstein LLM Gateway
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## Getting the SDK
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
import { createDataSDK } from "@salesforce/sdk-data";
|
|
59
|
-
|
|
60
|
-
const sdk = await createDataSDK();
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## Example 1: GraphQL (Preferred)
|
|
66
|
-
|
|
67
|
-
For record queries and mutations, use GraphQL via the Data SDK. Invoke the `using-graphql` skill for the full workflow (schema exploration, query authoring, codegen, lint validate).
|
|
68
|
-
|
|
69
|
-
```typescript
|
|
70
|
-
import { createDataSDK, gql } from "@salesforce/sdk-data";
|
|
71
|
-
import type { GetAccountsQuery } from "../graphql-operations-types";
|
|
72
|
-
|
|
73
|
-
const GET_ACCOUNTS = gql`
|
|
74
|
-
query GetAccounts {
|
|
75
|
-
uiapi {
|
|
76
|
-
query {
|
|
77
|
-
Account(first: 10) {
|
|
78
|
-
edges {
|
|
79
|
-
node {
|
|
80
|
-
Id
|
|
81
|
-
Name { value }
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
`;
|
|
89
|
-
|
|
90
|
-
export async function getAccounts() {
|
|
91
|
-
const sdk = await createDataSDK();
|
|
92
|
-
const response = await sdk.graphql?.<GetAccountsQuery>(GET_ACCOUNTS);
|
|
93
|
-
|
|
94
|
-
if (response?.errors?.length) {
|
|
95
|
-
throw new Error(response.errors.map((e) => e.message).join("; "));
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return response?.data?.uiapi?.query?.Account?.edges?.map((e) => e?.node) ?? [];
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
## Example 2: Fetch (When GraphQL Is Not Sufficient)
|
|
105
|
-
|
|
106
|
-
For REST endpoints that have no GraphQL equivalent, use `sdk.fetch`. **Invoke the `fetching-rest-api` skill** for full documentation of Chatter, Connect REST, Apex REST, UI API REST, and Einstein LLM endpoints.
|
|
107
|
-
|
|
108
|
-
```typescript
|
|
109
|
-
import { createDataSDK } from "@salesforce/sdk-data";
|
|
110
|
-
|
|
111
|
-
declare const __SF_API_VERSION__: string;
|
|
112
|
-
const API_VERSION = typeof __SF_API_VERSION__ !== "undefined" ? __SF_API_VERSION__ : "65.0";
|
|
113
|
-
|
|
114
|
-
export async function getCurrentUser() {
|
|
115
|
-
const sdk = await createDataSDK();
|
|
116
|
-
const response = await sdk.fetch?.(`/services/data/v${API_VERSION}/chatter/users/me`);
|
|
117
|
-
|
|
118
|
-
if (!response?.ok) throw new Error(`HTTP ${response?.status}`);
|
|
119
|
-
const data = await response.json();
|
|
120
|
-
return { id: data.id, name: data.name };
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
## Anti-Patterns (Forbidden)
|
|
127
|
-
|
|
128
|
-
### Direct fetch to Salesforce
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
// ❌ FORBIDDEN — bypasses Data SDK auth and CSRF
|
|
132
|
-
const res = await fetch("/services/data/v65.0/chatter/users/me");
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Direct axios to Salesforce
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
// ❌ FORBIDDEN — bypasses Data SDK
|
|
139
|
-
const res = await axios.get("/services/data/v65.0/chatter/users/me");
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### Correct approach
|
|
143
|
-
|
|
144
|
-
```typescript
|
|
145
|
-
// ✅ CORRECT — use Data SDK
|
|
146
|
-
const sdk = await createDataSDK();
|
|
147
|
-
const res = await sdk.fetch?.("/services/data/v65.0/chatter/users/me");
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
---
|
|
151
|
-
|
|
152
|
-
## Clarifying Vague Data Requests
|
|
153
|
-
|
|
154
|
-
When a user asks about data and the request is vague, **clarify before implementing**. Ask which of the following they want:
|
|
155
|
-
|
|
156
|
-
- **Application code** — Add or modify code in a specific web app so the app performs the data interaction at runtime (e.g., GraphQL query in the React app)
|
|
157
|
-
- **Local SF CLI** — Run Salesforce CLI commands locally (e.g., `sf data query`, `sf data import tree`) to interact with the org from the terminal
|
|
158
|
-
- **Local example data** — Update or add local fixture/example data files (e.g., JSON in `data/`) for development or testing
|
|
159
|
-
- **Other** — Data export, report generation, setup script, etc.
|
|
160
|
-
|
|
161
|
-
Do not assume. A request like "fetch accounts" could mean: (1) add a GraphQL query to the app, (2) run `sf data query` in the terminal, or (3) update sample data files. Confirm the intent before proceeding.
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
## Decision Flow
|
|
166
|
-
|
|
167
|
-
1. **Need to query or mutate Salesforce records?** → Use GraphQL via the Data SDK. Invoke the `using-graphql` skill.
|
|
168
|
-
2. **Need Chatter, Connect REST, Apex REST, UI API REST, or Einstein LLM?** → Use `sdk.fetch`. Invoke the `fetching-rest-api` skill.
|
|
169
|
-
3. **Never** use `fetch`, `axios`, or similar directly for Salesforce API calls.
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
## Reference
|
|
174
|
-
|
|
175
|
-
- GraphQL workflow: invoke the `using-graphql` skill (`.a4drules/skills/using-graphql/`)
|
|
176
|
-
- REST API via fetch: invoke the `fetching-rest-api` skill (`.a4drules/skills/fetching-rest-api/`)
|
|
177
|
-
- Data SDK package: `@salesforce/sdk-data` (`createDataSDK`, `gql`, `NodeOfConnection`)
|
|
178
|
-
- `createRecord` for UI API record creation: `@salesforce/webapp-experimental/api` (uses Data SDK internally)
|