@salesforce/webapp-template-feature-react-authentication-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.
@@ -1,253 +0,0 @@
1
- ---
2
- name: generating-graphql-read-query
3
- description: Generate Salesforce GraphQL read queries. Use when the query to generate is a read query. Schema exploration must complete first — invoke exploring-graphql-schema first.
4
- paths:
5
- - "**/*.ts"
6
- - "**/*.tsx"
7
- - "**/*.graphql"
8
- ---
9
-
10
- # Salesforce GraphQL Read Query Generation
11
-
12
- **Triggering conditions**
13
-
14
- 1. Only if the schema exploration phase completed successfully (invoke `exploring-graphql-schema` first)
15
- 2. Only if the query to generate is a read query
16
-
17
- ## Schema Access Policy
18
-
19
- > ⚠️ **GREP ONLY** — During query generation you may need to verify field names, types, or relationships. All schema lookups **MUST** use the grep-only commands defined in the `exploring-graphql-schema` skill. Do NOT open, read, stream, or parse `./schema.graphql` with any tool other than grep.
20
-
21
- ## Field-Level Security and @optional
22
-
23
- Field-level security (FLS) restricts which fields different users can see. Use the `@optional` directive on Salesforce record fields when possible. The server omits the field when the user lacks access, allowing the query to succeed instead of failing. Apply `@optional` to scalar fields, value-type fields (e.g. `Name { value }`), parent relationships, and child relationships. Available in API v65.0+.
24
-
25
- **Consuming code must defend against missing fields.** When a field is omitted due to FLS, it will be `undefined` (or absent) in the response. Use optional chaining (`?.`), nullish coalescing (`??`), and explicit null/undefined checks when reading query results. Never assume an optional field is present — otherwise the app may crash or behave incorrectly for users without field access.
26
-
27
- ```ts
28
- // ✅ Defend against missing fields
29
- const name = node.Name?.value ?? '';
30
- const relatedName = node.RelationshipName?.Name?.value ?? 'N/A';
31
-
32
- // ❌ Unsafe — will throw if field omitted due to FLS
33
- const name = node.Name.value;
34
- ```
35
-
36
- ## Your Role
37
-
38
- You are a GraphQL expert. Generate Salesforce-compatible read queries. Schema exploration must complete first. If the schema exploration has not been executed yet, you **MUST** run the full exploration workflow from the `exploring-graphql-schema` skill first, then return here for read query generation.
39
-
40
- ## Read Query Generation Workflow
41
-
42
- Strictly follow the rules below when generating the GraphQL read query:
43
-
44
- 1. **No Proliferation** - Only generate for the explicitly requested fields, nothing else. Do NOT add fields the user did not ask for.
45
- 2. **Unique Query** - Leverage child relationships to query entities in one single query
46
- 3. **Navigate Entities** - Always use `relationshipName` to access reference fields and child entities
47
- 1. **Exception** - if the `relationshipName` field is null, you can't navigate the related entity, and will have to return the `Id` itself
48
- 4. **Leverage Fragments** - Generate one fragment per possible type on polymorphic fields (field with `dataType="REFERENCE"` and more than one entry in `referenceToInfos` introspection attribute)
49
- 5. **Type Consistency** - Make sure variables used as query arguments and their related fields share the same GraphQL type. Verify types against grep output from the schema — do not assume types
50
- 6. **Type Enforcement** - Make sure to leverage field type information from introspection and GraphQL schema to generate field access
51
- 7. **Field Name Validation** - Every field name in the generated query **MUST** match a field confirmed via grep lookup in the schema. Do NOT guess or assume field names exist
52
- 8. **@optional for FLS** - Apply `@optional` on all Salesforce record fields when possible (see [Field-Level Security and @optional](#field-level-security-and-optional)). This lets the query succeed when the user lacks field-level access; the server omits inaccessible fields instead of failing
53
- 9. **Consuming code defense** - When generating or modifying code that consumes read query results, defend against missing fields (see [Field-Level Security and @optional](#field-level-security-and-optional)). Use optional chaining, nullish coalescing, and null/undefined checks — never assume optional fields are present
54
- 10. **Semi and anti joins** - Use the semi-join or anti-join templates to filter an entity with conditions on child entities
55
- 11. **Query Generation** - Use the [template](#read-query-template) to generate the query
56
- 12. **Output Format** - Use the [standalone](#read-standalone-default-output-format---clean-code-only)
57
- 13. **Lint Validation** - After writing the query to a file, run `npx eslint <file>` from the webapp dir to validate it against the schema. Fix any reported errors before proceeding. See [Lint Validation](#lint-validation) for details
58
- 14. **Test the Query** - Use the [Generated Read Query Testing](#generated-read-query-testing) workflow to test the generated query
59
- 1. **Report First** - Always output the generated query in the proper output format BEFORE initiating any test
60
-
61
- ## Read Query Template
62
-
63
- ```graphql
64
- query QueryName {
65
- uiapi {
66
- query {
67
- EntityName(
68
- # conditions here
69
- ) {
70
- edges {
71
- node {
72
- # Direct fields — use @optional for FLS resilience
73
- FieldName @optional { value }
74
-
75
- # Non-polymorphic reference (single type)
76
- RelationshipName @optional {
77
- Id
78
- Name { value }
79
- }
80
-
81
- # Polymorphic reference (multiple types)
82
- PolymorphicRelationshipName @optional {
83
- ...TypeAInfo
84
- ...TypeBInfo
85
- }
86
-
87
- # Child relationship (subquery)
88
- RelationshipName @optional (
89
- # conditions here
90
- ) {
91
- edges {
92
- node {
93
- # fields
94
- }
95
- }
96
- }
97
- }
98
- }
99
- }
100
- }
101
- }
102
- }
103
-
104
- fragment TypeAInfo on TypeA {
105
- Id
106
- SpecificFieldA @optional { value }
107
- }
108
-
109
- fragment TypeBInfo on TypeB {
110
- Id
111
- SpecificFieldB @optional { value }
112
- }
113
- ```
114
-
115
- ## Semi-Join and Anti-Join Condition Template
116
-
117
- Semi-joins (resp. anti-joins) condition leverage parent-child relationships and allow filtering the parent entity using a condition on child entities.
118
- This is a standard `where` condition, on the parent entity's `Id`, expressed using the `inq` (resp. `ninq`, i.e. not `inq`) operator. This operator accepts two attributes:
119
-
120
- - The child entity camelcase name to apply the condition on, with a value expressing the condition
121
- - The field name on the child entity containing the parent entity `Id`, which is the `fieldName` from the `childRelationships` information for the child entity
122
- - If the only condition is related child entity existence, you can use an `Id: { ne: null }` condition
123
-
124
- ### Semi-Join Example - ParentEntity with at least one Matching ChildEntity
125
-
126
- ```graphql
127
- query testSemiJoin {
128
- uiapi {
129
- query {
130
- ParentEntity(
131
- where: {
132
- Id: {
133
- inq: {
134
- ChildEntity: {
135
- # standard conditions here
136
- Name: { like: "test%" }
137
- Type: { eq: "some value" }
138
- }
139
- ApiName: "parentIdFieldInChild"
140
- }
141
- }
142
- }
143
- ) {
144
- edges {
145
- node {
146
- Id
147
- Name @optional {
148
- value
149
- }
150
- }
151
- }
152
- }
153
- }
154
- }
155
- }
156
- ```
157
-
158
- ### Anti-Join Example - ParentEntity with no Matching ChildEntity
159
-
160
- Same example as the [Semi-Join Example](#semi-join-example---parententity-with-at-least-one-matching-childentity), but replacing the `inq` operator by the `ninq` one.
161
-
162
- ## Read Standalone (Default) Output Format - CLEAN CODE ONLY
163
-
164
- ```javascript
165
- const QUERY_NAME = `
166
- query GetData {
167
- # query here
168
- }
169
- `;
170
-
171
- const QUERY_VARIABLES = {
172
- // variables here
173
- };
174
- ```
175
-
176
- **❌ FORBIDDEN — Do NOT include any of the following:**
177
-
178
- - Explanatory comments about the query (inline or surrounding)
179
- - Field descriptions or annotations
180
- - Additional text about what the query does
181
- - Workflow step descriptions or summaries
182
- - Comments like `// fetches...`, `// returns...`, `/* ... */`
183
-
184
- **✅ ONLY output:**
185
-
186
- - The raw query string constant
187
- - The variables object constant
188
- - Nothing else — no imports, no exports, no wrapper functions
189
-
190
- ## Lint Validation
191
-
192
- After writing the generated query into a source file, validate it against the schema using the project's GraphQL ESLint setup:
193
-
194
- ```bash
195
- # Run from webapp dir (force-app/main/default/webapplications/<app-name>/)
196
- npx eslint <path-to-file-containing-query>
197
- ```
198
-
199
- **How it works:** The ESLint config uses `@graphql-eslint/eslint-plugin` with its `processor`, which extracts GraphQL operations from `gql` template literals in `.ts`/`.tsx` files and validates the extracted `.graphql` virtual files against `schema.graphql`.
200
-
201
- **Rules enforced:** `no-anonymous-operations`, `no-duplicate-fields`, `known-fragment-names`, `no-undefined-variables`, `no-unused-variables`
202
-
203
- **On failure:** Fix the reported issues, re-run `npx eslint <file>` until clean, then proceed to testing.
204
-
205
- > ⚠️ **Prerequisites**: The `schema.graphql` file must exist (invoke `exploring-graphql-schema` first) and project dependencies must be installed (`npm install`).
206
-
207
- ## Generated Read Query Testing
208
-
209
- **Triggering conditions** — **ALL conditions must be true:**
210
-
211
- 1. The [Read Query Generation Workflow](#read-query-generation-workflow) completed with status `SUCCESS` and you have a generated query
212
- 2. The query is a read query
213
- 3. A non-manual method was used during schema exploration to retrieve introspection data
214
-
215
- **Workflow**
216
-
217
- 1. **Report Step** - State the exact method you will use to test (e.g., `sf api request graphql` from the **project root**, Connect API, etc.) — this **MUST** match the method used during schema exploration
218
- 2. **Interactive Step** - Ask the user whether they want you to test the query using the proposed method
219
- 1. **STOP and WAIT** for the user's answer. Do NOT proceed until the user responds. Do NOT assume consent.
220
- 3. **Test Query** - Only if the user explicitly agrees:
221
- 1. Use `sf api request rest` to POST the query to the GraphQL endpoint:
222
- ```bash
223
- sf api request rest /services/data/v65.0/graphql \
224
- --method POST \
225
- --body '{"query":"query GetData { uiapi { query { EntityName { edges { node { Id } } } } } }"}'
226
- ```
227
- 2. Replace `v65.0` with the API version of the target org
228
- 3. Replace the `query` value with the generated read query string
229
- 4. If the query uses variables, include them in the JSON body as a `variables` key
230
- 5. Report the result as `SUCCESS` if the query executed without error, or `FAILED` if errors were returned
231
- 6. An empty result set with no errors is `SUCCESS` — the query is valid, the org simply has no matching data
232
- 4. **Remediation Step** - If status is `FAILED`, use the [`FAILED` status handling workflows](#failed-status-handling-workflow)
233
-
234
- ### `FAILED` Status Handling Workflow
235
-
236
- The query is invalid:
237
-
238
- 1. **Error Analysis** - Parse and categorize the specific error messages
239
- 2. **Root Cause Identification** - Use error message to identify the root cause:
240
- - **Syntax** - Error contains `invalid syntax`
241
- - **Validation** - Error contains `validation error`
242
- - **Type** - Error contains `VariableTypeMismatch` or `UnknownType`
243
- 3. **Targeted Resolution** - Depending on the root cause categorization
244
- - **Syntax** - Update the query using the error message information to fix the syntax errors
245
- - **Validation** - The field name is most probably invalid. Re-run the relevant grep command from the `exploring-graphql-schema` skill to verify the correct field name. If still unclear, ask the user for clarification and **STOP and WAIT** for their answer
246
- - **Type** - Use the error details and re-verify the type via grep lookup in the schema. Correct the argument type and adjust variables accordingly
247
- 4. **Test Again** - Resume the [query testing workflow](#generated-read-query-testing) with the updated query (increment and track attempt counter)
248
- 5. **Escalation Path** - If targeted resolution fails after 2 attempts, ask for additional details and restart the entire GraphQL workflow from the `exploring-graphql-schema` skill
249
-
250
- ## Related Skills
251
-
252
- - Schema exploration: `exploring-graphql-schema` (must complete first)
253
- - Mutation generation: `generating-graphql-mutation-query`
@@ -1,324 +0,0 @@
1
- ---
2
- name: using-graphql
3
- description: Salesforce GraphQL data access. Use when the user asks to fetch, query, or mutate Salesforce data, or add a GraphQL operation for an object like Account, Contact, or Opportunity.
4
- paths:
5
- - "**/*.ts"
6
- - "**/*.tsx"
7
- - "**/*.graphql"
8
- ---
9
-
10
- # Salesforce GraphQL
11
-
12
- Guidance for querying and mutating Salesforce data via the Salesforce GraphQL API. Use `createDataSDK()` + `sdk.graphql?.()` and codegen tooling.
13
-
14
- ## When to Use
15
-
16
- - User asks to "fetch data from Salesforce"
17
- - User asks to "query" or "mutate" Salesforce records
18
- - User wants to add a new GraphQL operation (query or mutation)
19
- - User asks to add data access for a Salesforce object (Account, Contact, Opportunity, etc.)
20
-
21
- ## Schema Access Policy (GREP ONLY)
22
-
23
- > **GREP ONLY** — The `schema.graphql` file is very large (~265,000+ lines). All schema lookups **MUST** use the grep-only commands defined in the `exploring-graphql-schema` skill. Do NOT open, read, stream, or parse `./schema.graphql` with any tool other than grep.
24
-
25
- ## Directory Context
26
-
27
- The generated app has a two-level directory structure. Commands must run from the correct directory.
28
-
29
- ```
30
- <project-root>/ ← SFDX project root
31
- ├── schema.graphql ← grep target
32
- ├── sfdx-project.json
33
- └── force-app/main/default/webapplications/<app-name>/ ← webapp dir
34
- ├── package.json (npm scripts: graphql:schema, graphql:codegen, lint)
35
- ├── eslint.config.js (schema ref: ../../../../../schema.graphql)
36
- ├── codegen.yml (schema ref: ../../../../../schema.graphql)
37
- └── src/ (source code, .graphql query files)
38
- ```
39
-
40
- | Command | Run from | Why |
41
- | ------------------------- | ---------------- | -------------------------------------- |
42
- | `npm run graphql:schema` | **webapp dir** | Script is in webapp's `package.json` |
43
- | `npm run graphql:codegen` | **webapp dir** | Reads `codegen.yml` in webapp dir |
44
- | `npx eslint <file>` | **webapp dir** | Reads `eslint.config.js` in webapp dir |
45
- | `grep ... schema.graphql` | **project root** | `schema.graphql` lives at project root |
46
- | `sf api request graphql` | **project root** | Needs `sfdx-project.json` |
47
-
48
- > **Wrong directory = silent failures.** `npm run graphql:schema` from the project root will fail with "missing script." `grep ./schema.graphql` from the webapp dir will fail with "no such file."
49
-
50
- ## Prerequisites
51
-
52
- The base React app (`base-react-app`) ships with all GraphQL dependencies and tooling pre-configured:
53
-
54
- - `@salesforce/sdk-data` — runtime SDK for `createDataSDK` and `gql`
55
- - `@graphql-codegen/cli` + plugins — type generation from `.graphql` files and inline `gql` queries
56
- - `@graphql-eslint/eslint-plugin` — validates `.graphql` files and `gql` template literals against `schema.graphql` (used as a query validation gate — see Step 6)
57
- - `graphql` — shared by codegen, ESLint, and schema introspection
58
-
59
- Before using this skill, ensure:
60
-
61
- 1. The `@salesforce/sdk-data` package is available (provides `createDataSDK`, `gql`, `NodeOfConnection`)
62
- 2. **Deployment order**: Metadata must be deployed before schema fetch; schema must be refetched after any metadata deployment. Invoke the `deploying-to-salesforce` skill when deploying or syncing with the org.
63
- 3. A `schema.graphql` file exists at the project root. If missing, generate it:
64
- ```bash
65
- # Run from webapp dir (force-app/main/default/webapplications/<app-name>/)
66
- npm run graphql:schema
67
- ```
68
-
69
- ## npm Scripts
70
-
71
- - **`npm run graphql:schema`** — _(run from webapp dir)_ Downloads the full GraphQL schema from a connected Salesforce org via introspection. Outputs `schema.graphql` to the project root.
72
- - **`npm run graphql:codegen`** — _(run from webapp dir)_ Generates TypeScript types from `.graphql` files and inline `gql` queries. Outputs to `src/api/graphql-operations-types.ts`.
73
-
74
- ## Workflow
75
-
76
- ### Step 1: Download Schema
77
-
78
- Ensure `schema.graphql` exists at the project root. If missing, run `npm run graphql:schema` from the webapp dir.
79
-
80
- ### Step 2: Explore the Schema (grep-only)
81
-
82
- Before writing any query, verify the target object and its fields exist in the schema.
83
-
84
- **Invoke the `exploring-graphql-schema` skill** for the full exploration workflow and **mandatory grep-only access policy**.
85
-
86
- > **GREP ONLY** — All schema lookups MUST use the grep commands defined in the `exploring-graphql-schema` skill. Do NOT open, read, stream, or parse `./schema.graphql` with any tool other than grep.
87
-
88
- Key actions (all via grep):
89
-
90
- - `type <ObjectName> implements Record` — find available fields
91
- - `input <ObjectName>_Filter` — find filter options
92
- - `input <ObjectName>_OrderBy` — find sorting options
93
- - `input <ObjectName>CreateInput` / `<ObjectName>UpdateInput` — find mutation input types
94
-
95
- ### Step 3: Choose the Query Pattern
96
-
97
- **Pattern 1 — External `.graphql` file** (recommended for complex queries):
98
-
99
- - Queries with variables, fragments, or shared across files
100
- - Full codegen support, syntax highlighting, shareable
101
- - Requires codegen step after changes
102
- - See example: `api/utils/accounts.ts` + `api/utils/query/highRevenueAccountsQuery.graphql`
103
-
104
- **Pattern 2 — Inline `gql` tag** (recommended for simple queries):
105
-
106
- - Simple queries without variables; colocated with usage code
107
- - Supports dynamic queries (field set varies at runtime)
108
- - **MUST use `gql` tag** — plain template strings bypass `@graphql-eslint` validation
109
- - See example: `api/utils/user.ts`
110
-
111
- ### Step 4: Write the Query
112
-
113
- For **Pattern 1**:
114
-
115
- 1. Create a `.graphql` file under `src/api/utils/query/`
116
- 2. Follow UIAPI structure: `query { uiapi { query { ObjectName(...) { edges { node { ... } } } } } }`
117
- 3. For mutations, invoke the `generating-graphql-mutation-query` skill
118
- 4. For read queries, invoke the `generating-graphql-read-query` skill
119
-
120
- For **Pattern 2**:
121
-
122
- 1. Define query inline using the `gql` template tag
123
- 2. Ensure the query name matches what codegen expects
124
-
125
- ### Step 5: Test Queries Against Live Org
126
-
127
- Use the testing workflows in the `generating-graphql-read-query` and `generating-graphql-mutation-query` skills to validate queries against the connected org before integrating into the app.
128
-
129
- ### Step 6: Generate Types
130
-
131
- ```bash
132
- # Run from webapp dir (force-app/main/default/webapplications/<app-name>/)
133
- npm run graphql:codegen
134
- ```
135
-
136
- This updates `src/api/graphql-operations-types.ts` with `<OperationName>Query`/`<OperationName>Mutation` and `<OperationName>QueryVariables`/`<OperationName>MutationVariables`.
137
-
138
- ### Step 7: Lint Validate
139
-
140
- Run ESLint on the file containing the query to validate it against the schema **before** any live testing:
141
-
142
- ```bash
143
- # Run from webapp dir
144
- npx eslint <path-to-file>
145
- ```
146
-
147
- The `@graphql-eslint/eslint-plugin` processor extracts GraphQL from `gql` template literals and validates them against `schema.graphql`. Fix all ESLint errors before proceeding.
148
-
149
- ### Step 8: Implement and Verify
150
-
151
- Implement the data access function using the pattern below. Use the Quality Checklist before completing.
152
-
153
- ---
154
-
155
- ## Core Types & Function Signatures
156
-
157
- ### createDataSDK and graphql
158
-
159
- ```typescript
160
- import { createDataSDK } from "@salesforce/sdk-data";
161
-
162
- const sdk = await createDataSDK();
163
- const response = await sdk.graphql?.<ResponseType, VariablesType>(query, variables);
164
- ```
165
-
166
- `createDataSDK()` returns a `DataSDK` instance. The `graphql` method uses optional chaining (`?.`) because not all surfaces support GraphQL.
167
-
168
- ### gql Template Tag
169
-
170
- ```typescript
171
- import { gql } from "@salesforce/sdk-data";
172
-
173
- const MY_QUERY = gql`
174
- query MyQuery {
175
- uiapi { ... }
176
- }
177
- `;
178
- ```
179
-
180
- The `gql` tag enables ESLint validation against the schema. Plain template strings bypass validation.
181
-
182
- ### Error Handling
183
-
184
- Default: treat any errors as failure (Strategy A). For partial data tolerance, log errors but use data. For mutations where some return fields are inaccessible, use Strategy C (fail only when no data).
185
-
186
- ```typescript
187
- // Default: strict
188
- if (response?.errors?.length) {
189
- throw new Error(response.errors.map((e) => e.message).join("; "));
190
- }
191
- const result = response?.data;
192
- ```
193
-
194
- Responses follow `uiapi.query.ObjectName.edges[].node`; fields use `{ value }`.
195
-
196
- ### NodeOfConnection
197
-
198
- ```typescript
199
- import { type NodeOfConnection } from "@salesforce/sdk-data";
200
-
201
- type AccountNode = NodeOfConnection<GetHighRevenueAccountsQuery["uiapi"]["query"]["Account"]>;
202
- ```
203
-
204
- ---
205
-
206
- ## Pattern 1: External .graphql File
207
-
208
- Create a `.graphql` file, run `npm run graphql:codegen`, import with `?raw` suffix, and use generated types.
209
-
210
- **Required imports:**
211
-
212
- ```typescript
213
- import { createDataSDK, type NodeOfConnection } from "@salesforce/sdk-data";
214
- import MY_QUERY from "./query/myQuery.graphql?raw"; // ← ?raw suffix required
215
- import type { GetMyDataQuery, GetMyDataQueryVariables } from "../graphql-operations-types";
216
- ```
217
-
218
- **When to use:** Complex queries with variables, fragments, or shared across files. Does NOT support dynamic queries (field set varies at runtime).
219
-
220
- ---
221
-
222
- ## Pattern 2: Inline gql Tag
223
-
224
- **Required imports:**
225
-
226
- ```typescript
227
- import { createDataSDK, gql } from "@salesforce/sdk-data";
228
- import { type CurrentUserQuery } from "../graphql-operations-types";
229
-
230
- const MY_QUERY = gql`
231
- query CurrentUser {
232
- uiapi { ... }
233
- }
234
- `;
235
- ```
236
-
237
- > **MUST use `gql` tag** — plain template strings bypass the `@graphql-eslint` processor entirely, meaning no lint validation against the schema.
238
-
239
- **When to use:** Simple, colocated queries. Supports dynamic queries (field set varies at runtime).
240
-
241
- ---
242
-
243
- ## Conditional Field Selection
244
-
245
- For dynamic fieldsets with **known** fields, use `@include(if: $condition)` and `@skip(if: $condition)` in `.graphql` files. See GraphQL spec for details.
246
-
247
- ---
248
-
249
- ## Anti-Patterns (Not Recommended)
250
-
251
- ### Direct API Calls
252
-
253
- ```typescript
254
- // NOT RECOMMENDED: Direct axios/fetch calls for GraphQL
255
- // PREFERRED: Use the Data SDK
256
- const sdk = await createDataSDK();
257
- const response = await sdk.graphql?.<ResponseType>(query, variables);
258
- ```
259
-
260
- ### Missing Type Definitions
261
-
262
- ```typescript
263
- // NOT RECOMMENDED: Untyped GraphQL calls
264
- // PREFERRED: Provide response type
265
- const response = await sdk.graphql?.<GetMyDataQuery>(query);
266
- ```
267
-
268
- ### Plain String Queries (Without gql Tag)
269
-
270
- ```typescript
271
- // NOT RECOMMENDED: Plain strings bypass ESLint validation
272
- const query = `query { ... }`;
273
-
274
- // PREFERRED: Use gql tag for inline queries
275
- const QUERY = gql`query { ... }`;
276
- ```
277
-
278
- ---
279
-
280
- ## Quality Checklist
281
-
282
- > If you have not completed the workflow above, **stop and complete it first**. Invoke the skill workflow before using this checklist.
283
-
284
- Before completing GraphQL data access code:
285
-
286
- ### For Pattern 1 (.graphql files):
287
-
288
- 1. [ ] All field names verified via grep against `schema.graphql` (invoke `exploring-graphql-schema`)
289
- 2. [ ] Create `.graphql` file for the query/mutation
290
- 3. [ ] Run `npm run graphql:codegen` to generate types
291
- 4. [ ] Import query with `?raw` suffix
292
- 5. [ ] Import generated types from `graphql-operations-types.ts`
293
- 6. [ ] Use `sdk.graphql?.<ResponseType>()` with proper generic
294
- 7. [ ] Handle `response.errors` and destructure `response.data`
295
- 8. [ ] Use `NodeOfConnection` for cleaner node types when needed
296
- 9. [ ] Run `npx eslint <file>` from webapp dir — fix all GraphQL errors
297
-
298
- ### For Pattern 2 (inline with gql):
299
-
300
- 1. [ ] All field names verified via grep against `schema.graphql`
301
- 2. [ ] Define query using `gql` template tag (NOT a plain string)
302
- 3. [ ] Ensure query name matches generated types in `graphql-operations-types.ts`
303
- 4. [ ] Import generated types for the query
304
- 5. [ ] Use `sdk.graphql?.<ResponseType>()` with proper generic
305
- 6. [ ] Handle `response.errors` and destructure `response.data`
306
- 7. [ ] Run `npx eslint <file>` from webapp dir — fix all GraphQL errors
307
-
308
- ### General:
309
-
310
- - [ ] Lint validation passes (`npx eslint <file>` reports no GraphQL errors)
311
- - [ ] Query field names match the schema exactly (case-sensitive, confirmed via grep)
312
- - [ ] Response type generic is provided to `sdk.graphql?.<T>()`
313
- - [ ] Optional chaining is used for nested response data
314
-
315
- ---
316
-
317
- ## Reference
318
-
319
- - Schema exploration: invoke the `exploring-graphql-schema` skill
320
- - Read query generation: invoke the `generating-graphql-read-query` skill
321
- - Mutation query generation: invoke the `generating-graphql-mutation-query` skill
322
- - Shared GraphQL schema types: `shared-schema.graphqls` (in this skill directory)
323
- - Schema download: `npm run graphql:schema` (run from webapp dir)
324
- - Type generation: `npm run graphql:codegen` (run from webapp dir)