@salesforce/webapp-template-feature-react-global-search-experimental 1.111.0 → 1.112.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.
@@ -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 **accessing-data** skill.
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
- - **exploring-graphql-schema** — Schema exploration (grep-only) after schema exists
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.1](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.112.0...v1.112.1) (2026-03-20)
7
+
8
+ **Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
9
+
10
+
11
+
12
+
13
+
14
+ # [1.112.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.111.0...v1.112.0) (2026-03-20)
15
+
16
+
17
+ ### Features
18
+
19
+ * 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))
20
+
21
+
22
+
23
+
24
+
6
25
  # [1.111.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.110.1...v1.111.0) (2026-03-19)
7
26
 
8
27
  **Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
@@ -15,8 +15,8 @@
15
15
  "graphql:schema": "node scripts/get-graphql-schema.mjs"
16
16
  },
17
17
  "dependencies": {
18
- "@salesforce/sdk-data": "^1.111.0",
19
- "@salesforce/webapp-experimental": "^1.111.0",
18
+ "@salesforce/sdk-data": "^1.112.1",
19
+ "@salesforce/webapp-experimental": "^1.112.1",
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.111.0",
46
+ "@salesforce/vite-plugin-webapp-experimental": "^1.112.1",
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",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@salesforce/webapp-template-base-sfdx-project-experimental",
3
- "version": "1.111.0",
3
+ "version": "1.112.1",
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.111.0",
9
+ "version": "1.112.1",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/webapp-template-base-sfdx-project-experimental",
3
- "version": "1.111.0",
3
+ "version": "1.112.1",
4
4
  "description": "Base SFDX project template",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "publishConfig": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/webapp-template-feature-react-global-search-experimental",
3
- "version": "1.111.0",
3
+ "version": "1.112.1",
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)