@salesforce/platform-sdk 11.69.2 → 11.70.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.
@@ -105,6 +105,8 @@ export type QuerySubscriber<T> = (snapshot: QuerySnapshot<T>) => void;
105
105
  * @remarks
106
106
  * On uncached surfaces (Mosaic, OpenAI), `subscribe` only emits in response
107
107
  * to `refresh()` — there is no cache to push background updates.
108
+ *
109
+ * @see docs/data/03-reactive-handle-lifecycle.md
108
110
  */
109
111
  export interface QueryResult<T> extends QuerySnapshot<T> {
110
112
  subscribe(cb: QuerySubscriber<T>): Unsubscribe;
@@ -127,6 +129,8 @@ export interface QueryResult<T> extends QuerySnapshot<T> {
127
129
  * `subscribe` / `refresh` (mutating a side effect on subscription is incoherent;
128
130
  * re-running it on refresh is dangerous). Stale-after-mutation is handled by
129
131
  * the caller holding query result references and calling `result.refresh()`.
132
+ *
133
+ * @see docs/data/03-reactive-handle-lifecycle.md
130
134
  */
131
135
  export interface MutationResult<T> {
132
136
  data: T | undefined;
@@ -140,6 +144,8 @@ export interface MutationResult<T> {
140
144
  * Follows HTTP RFC 7234 `no-cache` semantics.
141
145
  * - `"only-if-cached"` — return the cached entry without a network call.
142
146
  * Returns an error if no entry exists for this query + variables.
147
+ *
148
+ * @see docs/data/02-caching-and-freshness.md
143
149
  */
144
150
  export type CacheControlShorthand = "no-cache" | "only-if-cached";
145
151
  /**
@@ -149,6 +155,8 @@ export type CacheControlShorthand = "no-cache" | "only-if-cached";
149
155
  * - `maxAge: 0` — entry is written but immediately considered stale
150
156
  * (always re-fetches, similar to `"no-cache"` but writes a 0s TTL).
151
157
  * - Invalid values (NaN, Infinity, negative) fall back to the 300s default.
158
+ *
159
+ * @see docs/data/02-caching-and-freshness.md
152
160
  */
153
161
  export interface CacheControlMaxAge {
154
162
  type: "max-age";
@@ -169,10 +177,14 @@ export interface CacheControlMaxAge {
169
177
  *
170
178
  * When omitted, the default `max-age` strategy with a 300-second TTL applies.
171
179
  * After the TTL expires, the next call fetches fresh data from the network.
180
+ *
181
+ * @see docs/data/02-caching-and-freshness.md
172
182
  */
173
183
  export type CacheControl = CacheControlShorthand | CacheControlMaxAge;
174
184
  /**
175
185
  * Options bag for {@link DataSDKGraphQL.query}.
186
+ *
187
+ * @see docs/data/02-caching-and-freshness.md
176
188
  */
177
189
  export interface QueryOptions<V = Record<string, unknown>> {
178
190
  query: GraphQLRawDocument;
@@ -197,6 +209,8 @@ export interface QueryOptions<V = Record<string, unknown>> {
197
209
  }
198
210
  /**
199
211
  * Options bag for {@link DataSDKGraphQL.mutate}.
212
+ *
213
+ * @see docs/data/02-caching-and-freshness.md
200
214
  */
201
215
  export interface MutateOptions<V = Record<string, unknown>> {
202
216
  mutation: GraphQLRawDocument;
@@ -214,6 +228,8 @@ export interface MutateOptions<V = Record<string, unknown>> {
214
228
  * Queries are reactive (cached on surfaces that cache, subscribable on every
215
229
  * surface); mutations are request/response. Each method's return shape
216
230
  * matches its semantics — no fakes, no noops.
231
+ *
232
+ * @see docs/data/04-surfaces-and-guards.md
217
233
  */
218
234
  export interface DataSDKGraphQL {
219
235
  /**
@@ -302,6 +318,8 @@ export interface DataSDKGraphQL {
302
318
  *
303
319
  * May be a bare `{}` on unsupported surfaces — feature-detect `graphql` or
304
320
  * `fetch` before use to avoid runtime errors.
321
+ *
322
+ * @see docs/data/04-surfaces-and-guards.md
305
323
  */
306
324
  export interface DataSDK {
307
325
  /** GraphQL namespace. Present when the surface supports data operations. */
@@ -1 +1 @@
1
- {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/core/data.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/core/data.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,8 @@
18
18
  *
19
19
  * const query = gql`query { account { name } }`;
20
20
  * ```
21
+ *
22
+ * @see docs/data/01-grounding-and-precedence.md
21
23
  */
22
24
  export declare function gql(strings: TemplateStringsArray, ...values: unknown[]): string;
23
25
  //# sourceMappingURL=gql.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gql.d.ts","sourceRoot":"","sources":["../../src/data/gql.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,GAAG,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAM/E"}
1
+ {"version":3,"file":"gql.d.ts","sourceRoot":"","sources":["../../src/data/gql.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,GAAG,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAM/E"}
@@ -3,10 +3,15 @@ import { MosaicDataSDKOptions } from './mosaic';
3
3
  /**
4
4
  * A callback the host invokes for a given HTTP status (see {@link WebAppDataSDKOptions.onStatus}).
5
5
  * May be sync or async.
6
+ *
7
+ * @see docs/data/04-surfaces-and-guards.md
6
8
  */
7
9
  export type StatusCallback = () => Promise<unknown> | void;
8
10
  /**
9
- * Options for creating a WebAppDataSDK
11
+ * Options for the WebApp surface — the browser-hosted, cached surface. Passed
12
+ * as `DataSDKOptions.webapp`.
13
+ *
14
+ * @see docs/data/04-surfaces-and-guards.md
10
15
  */
11
16
  export interface WebAppDataSDKOptions {
12
17
  /**
@@ -52,7 +57,10 @@ export declare const defineDataExtension: <const Name extends string, Api>(exten
52
57
  */
53
58
  export type DataSDKWithExtensions<Extensions extends ExtensionsFor<DataSDK>> = ExtendedSDK<DataSDK, Extensions>;
54
59
  /**
55
- * Options for creating a DataSDK instance.
60
+ * Options for creating a DataSDK instance — surface selection plus the
61
+ * per-surface option bags (`webapp`, `mosaic`) and any `plugins`.
62
+ *
63
+ * @see docs/data/04-surfaces-and-guards.md
56
64
  */
57
65
  export interface DataSDKOptions extends SDKOptions {
58
66
  /**
@@ -116,6 +124,8 @@ export interface DataSDKOptions extends SDKOptions {
116
124
  * console.log(result.data);
117
125
  * }
118
126
  * ```
127
+ *
128
+ * @see docs/data/01-grounding-and-precedence.md
119
129
  */
120
130
  export declare function createDataSDK<const Extensions extends ExtensionsFor<DataSDK> = []>(options?: Omit<DataSDKOptions, "extensions"> & {
121
131
  extensions?: Extensions;
@@ -127,6 +137,8 @@ export type { CacheControl, DataSDK, DataSDKGraphQL, GraphQLError, GraphQLRawDoc
127
137
  * `{ edges: [{ node }] }` connection. Resolves to `never` when `T` is not such a connection.
128
138
  *
129
139
  * @typeParam T - The connection type to unwrap.
140
+ *
141
+ * @see docs/data/04-surfaces-and-guards.md
130
142
  */
131
143
  export type NodeOfConnection<T> = T extends {
132
144
  edges?: (infer E)[] | null;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/data/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACX,OAAO,EACP,WAAW,EACX,SAAS,EACT,aAAa,EACb,UAAU,EACV,oBAAoB,EACpB,eAAe,EACf,MAAM,SAAS,CAAC;AACjB,OAAO,EAAiB,KAAK,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAKpE;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;IACnD;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,YAAY,EAAE,oBAAoB,EAAE,CAAC;AAErC;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,OAAO,IAAI,SAAS,CACpF,OAAO,EACP,IAAI,EACJ,GAAG,CACH,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,+IAAoC,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,CAAC,UAAU,SAAS,aAAa,CAAC,OAAO,CAAC,IAAI,WAAW,CACzF,OAAO,EACP,UAAU,CACV,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,UAAU;IACjD;;;OAGG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CACpC;AAqCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAiBH,wBAAgB,aAAa,CAAC,KAAK,CAAC,UAAU,SAAS,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,EACjF,OAAO,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,GAAG;IAC9C,UAAU,CAAC,EAAE,UAAU,CAAC;CACxB,GAAG,oBAAoB,CAAC,UAAU,CAAC,GACnC,eAAe,CAAC,UAAU,CAAC,GAC1B,OAAO,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC,CAAC;AAe9C,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,YAAY,EACX,YAAY,EACZ,OAAO,EACP,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,aAAa,EACb,cAAc,EACd,YAAY,EACZ,WAAW,EACX,eAAe,EACf,UAAU,EACV,WAAW,GACX,MAAM,SAAS,CAAC;AAEjB;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS;IAC3C,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC;CAC3B,GAAG,IAAI,GACL,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,IAAI,GAClC,CAAC,GACD,KAAK,GACN,KAAK,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/data/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACX,OAAO,EACP,WAAW,EACX,SAAS,EACT,aAAa,EACb,UAAU,EACV,oBAAoB,EACpB,eAAe,EACf,MAAM,SAAS,CAAC;AACjB,OAAO,EAAiB,KAAK,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAKpE;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACpC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;IACnD;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,YAAY,EAAE,oBAAoB,EAAE,CAAC;AAErC;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,OAAO,IAAI,SAAS,CACpF,OAAO,EACP,IAAI,EACJ,GAAG,CACH,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,+IAAoC,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,CAAC,UAAU,SAAS,aAAa,CAAC,OAAO,CAAC,IAAI,WAAW,CACzF,OAAO,EACP,UAAU,CACV,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,cAAe,SAAQ,UAAU;IACjD;;;OAGG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CACpC;AAqCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAiBH,wBAAgB,aAAa,CAAC,KAAK,CAAC,UAAU,SAAS,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,EACjF,OAAO,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,GAAG;IAC9C,UAAU,CAAC,EAAE,UAAU,CAAC;CACxB,GAAG,oBAAoB,CAAC,UAAU,CAAC,GACnC,eAAe,CAAC,UAAU,CAAC,GAC1B,OAAO,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC,CAAC;AAe9C,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,YAAY,EACX,YAAY,EACZ,OAAO,EACP,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,aAAa,EACb,cAAc,EACd,YAAY,EACZ,WAAW,EACX,eAAe,EACf,UAAU,EACV,WAAW,GACX,MAAM,SAAS,CAAC;AAEjB;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS;IAC3C,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC;CAC3B,GAAG,IAAI,GACL,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,IAAI,GAClC,CAAC,GACD,KAAK,GACN,KAAK,CAAC"}
@@ -279,7 +279,7 @@ const v = "Accept-Language", we = (t) => {
279
279
  return l(t);
280
280
  const [r, n] = t;
281
281
  return (r instanceof Request && !n?.headers ? r.headers.has(v) : new Headers(n?.headers).has(v)) ? l(t) : l(b(v, e, t));
282
- }, Se = "X-SFDC-Client-Name", ge = "X-SFDC-Client-Version", ve = "@salesforce/platform-sdk", Ee = "11.69.2", Ce = (t) => {
282
+ }, Se = "X-SFDC-Client-Name", ge = "X-SFDC-Client-Version", ve = "@salesforce/platform-sdk", Ee = "11.70.0", Ce = (t) => {
283
283
  let e = b(Se, ve, t);
284
284
  return e = b(ge, Ee, e), l(e);
285
285
  }, De = "X-CSRF-Token";
@@ -1,6 +1,9 @@
1
1
  import { DataSDK, DataSDKGraphQL } from '../../core';
2
2
  /**
3
- * Options for creating a MosaicDataSDK
3
+ * Options for the Mosaic surface — the server-side (Node.js) surface. Auth is
4
+ * via access token and there is no cache. Passed as `DataSDKOptions.mosaic`.
5
+ *
6
+ * @see docs/data/04-surfaces-and-guards.md
4
7
  */
5
8
  export interface MosaicDataSDKOptions {
6
9
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/data/mosaic/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAmC,MAAM,YAAY,CAAC;AAe3F;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,qBAAa,aAAc,YAAW,OAAO;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAe;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;gBAErB,OAAO,CAAC,EAAE,oBAAoB;YAa5B,iBAAiB;CAe/B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/data/mosaic/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAmC,MAAM,YAAY,CAAC;AAe3F;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACpC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,qBAAa,aAAc,YAAW,OAAO;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAe;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;gBAErB,OAAO,CAAC,EAAE,oBAAoB;YAa5B,iBAAiB;CAe/B"}
@@ -0,0 +1,84 @@
1
+ <!-- sdk-symbols
2
+ createDataSDK: dist/data/index.d.ts
3
+ gql: dist/data/gql.d.ts
4
+ DataSDK: dist/core/data.d.ts
5
+ -->
6
+
7
+ # Data access — grounding & precedence
8
+
9
+ This folder is the **authored** half of the `@salesforce/platform-sdk` data-access contract. It
10
+ ships **inside the installed package**, so it version-travels with the `.d.ts` you have on disk:
11
+ the guidance you read here always matches the SDK version you installed, never a newer or older
12
+ copy kept somewhere else.
13
+
14
+ It is deliberately **thin**. The installed declarations own the call contract; these pages carry
15
+ only the residue the types cannot express — strategy, negatives, lifecycle, and the migration
16
+ story.
17
+
18
+ ## Two ways in — `.graphql` and `.fetch`
19
+
20
+ `createDataSDK()` returns two data-access members, both surface-optional (feature-detect before use
21
+ — see [04-surfaces-and-guards.md](./04-surfaces-and-guards.md)):
22
+
23
+ - **`.graphql` — the primary route.** UIAPI-backed reads and mutations, cached and reactive on the
24
+ WebApp surface. Steer here first: anything the GraphQL schema can express should go through
25
+ `.graphql`. Pages [02](./02-caching-and-freshness.md)–[03](./03-reactive-handle-lifecycle.md)
26
+ are entirely about this route.
27
+ - **`.fetch` — the escape hatch.** SDK-enriched authenticated HTTP (`typeof fetch`) for the
28
+ endpoints the GraphQL schema does not expose — REST (`/services/data/…`), Apex REST
29
+ (`/services/apexrest/…`), Connect, blob/file downloads. It carries the surface's auth, CSRF, and
30
+ header handling, and is **not** cached. On WebApp, `.graphql` is itself built on top of `.fetch`
31
+ — it is the primitive, not an afterthought.
32
+
33
+ **Which door:** default to `.graphql`; reach for `.fetch` only when there is no GraphQL
34
+ representation for what you need. These pages document the _mechanics_ of each — the `.fetch`
35
+ contract, per-surface behaviour, and examples live in
36
+ [04-surfaces-and-guards.md](./04-surfaces-and-guards.md). The authoritative
37
+ `.graphql`-vs-`.fetch` **routing** decision (which endpoints belong on which door) stays with the
38
+ `experience-ui-bundle-salesforce-data-access` skill, not here.
39
+
40
+ ## Precedence — read in this order, and let the earlier rung win
41
+
42
+ 1. **Tier-1 — the live GraphQL schema.** What fields/types actually exist for a `.graphql` query.
43
+ Not in this package. This rung grounds the `.graphql` door only — the `.fetch` door is grounded
44
+ by the contract of whatever REST/Apex endpoint you call, which this SDK does not own.
45
+ 2. **Tier-2a — the installed `.d.ts`.** The authoritative call contract: exports, `query`/`mutate`
46
+ signatures, options bags, result shapes, `CacheControl`, `NodeOfConnection`. Start here:
47
+ - `dist/core/data.d.ts` — the contract types (`DataSDK`, `DataSDKGraphQL`, `QueryResult`,
48
+ `CacheControl`, …).
49
+ - `dist/data/index.d.ts` — the entry points (`createDataSDK`, `gql`) and the surface options.
50
+ 3. **Tier-2b — these pages.** Only what the types can't carry. **If a page and the `.d.ts`
51
+ disagree, the `.d.ts` wins** — assume the prose has drifted and trust the declaration.
52
+ 4. **Skill spine — fallback.** The `experience-ui-bundle-salesforce-data-access` skill covers
53
+ routing, guardrails, and the tier-1 gate. It points _here_ for the SDK-usage detail rather
54
+ than restating it.
55
+
56
+ ## What lives where
57
+
58
+ | The installed `.d.ts` owns | These pages own |
59
+ | -------------------------------------------------------------- | --------------------------------------------------------------- |
60
+ | Signatures, options bags, result shapes, enums, default values | Strategy/decision tables, "do NOT reinvent it" negatives |
61
+ | `CacheControl` values & the default TTL | _When_ to reach for each cache policy, offline-first stance |
62
+ | The `QueryResult` shape | Living with the reactive handle in a framework lifecycle |
63
+ | `DataSDK.fetch` (`typeof fetch`) — the raw call shape | _When_ to reach for `.fetch` vs `.graphql`, and what it carries |
64
+ | The current call contract | The dead `@salesforce/sdk-data` → new-API migration story |
65
+
66
+ ## Reading order
67
+
68
+ - [02-caching-and-freshness.md](./02-caching-and-freshness.md) — the WebApp cache, the two refresh
69
+ tools, offline-first.
70
+ - [03-reactive-handle-lifecycle.md](./03-reactive-handle-lifecycle.md) — living with
71
+ `QueryResult.subscribe`/`refresh`.
72
+ - [04-surfaces-and-guards.md](./04-surfaces-and-guards.md) — the two data-access members,
73
+ `sdk.graphql!` vs guard, reading `errors`, the `.fetch` escape hatch, per-surface options.
74
+ - [05-migration-from-sdk-data.md](./05-migration-from-sdk-data.md) — old callable API → new
75
+ namespace API.
76
+
77
+ ## Deep-path `.d.ts` are for reading, not importing
78
+
79
+ A few pages cite declarations that live deep in the tree — e.g.
80
+ `dist/data/shared/graphql/cache/command.d.ts`. Those are **raw file paths you may open to read**,
81
+ **not import subpaths**. The only importable entries are the ones declared in the package's
82
+ `exports` (`@salesforce/platform-sdk`, `@salesforce/platform-sdk/core`,
83
+ `@salesforce/platform-sdk/data`, …). Never write
84
+ `import … from "@salesforce/platform-sdk/data/shared/graphql/cache/command"` — it will not resolve.
@@ -0,0 +1,183 @@
1
+ <!-- sdk-symbols
2
+ CacheControl: dist/core/data.d.ts
3
+ CacheControlMaxAge: dist/core/data.d.ts
4
+ CacheControlShorthand: dist/core/data.d.ts
5
+ QueryOptions: dist/core/data.d.ts
6
+ MutateOptions: dist/core/data.d.ts
7
+ DataSDKGraphQL: dist/core/data.d.ts
8
+ HttpGraphQLResourceCacheControlCommand: dist/data/shared/graphql/cache/command.d.ts
9
+ cacheBundleRegistry: dist/data/shared/graphql/cache/services.d.ts
10
+ buildCacheServices: dist/data/shared/graphql/cache/services.d.ts
11
+ -->
12
+
13
+ # Caching & freshness
14
+
15
+ > **Surface caveat up front:** everything about _caching_ here is the **WebApp surface**. On the
16
+ > uncached surfaces (Mosaic, OpenAI) there is no cache — see
17
+ > [Uncached surfaces](#uncached-surfaces-mosaic-openai) below and
18
+ > [04-surfaces-and-guards.md](./04-surfaces-and-guards.md). The `query`/`mutate` shape is identical
19
+ > on every surface, so call sites stay portable.
20
+
21
+ The `CacheControl`, `CacheControlMaxAge`, and `DataSDKGraphQL` declarations in `dist/core/data.d.ts`
22
+ own the supported values, the default TTL, and the hit/miss behaviour. Read them first; this page is
23
+ strategy and negatives only.
24
+
25
+ ## Caching is ON by default (WebApp) — do NOT reinvent it
26
+
27
+ Every `sdk.graphql!.query()` on WebApp is cached automatically. There is **no opt-in flag, no
28
+ `createCachedClient` factory, and no `/cache` import subpath** — those do not exist in
29
+ `@salesforce/platform-sdk`. There is also **no need for React Query, SWR, `localStorage`, or any
30
+ hand-rolled memoization**. If you find yourself writing a cache, **stop** — it already exists.
31
+
32
+ The default TTL and the max-age override are defined on `CacheControl` / `CacheControlMaxAge` in the
33
+ `.d.ts`. Read the value there rather than hard-coding a number here — the declaration is the source
34
+ of truth for the default.
35
+
36
+ ## What gets cached
37
+
38
+ Only **successful responses with a non-empty `data` object** are written:
39
+
40
+ - `data` is `null`, missing, or `{}` → **NOT cached**. An empty `data` usually means a transient
41
+ server condition; caching it would poison the entry for the full TTL.
42
+ - Response carries a non-empty `errors` array → surfaced as an error and **NOT cached**.
43
+
44
+ ## Cache key
45
+
46
+ The key is `stableJSONStringify({ query, variables, operationName })`, plus a `headers` field when
47
+ the call passes per-request headers (see the `headers` bullet below). The derivation lives in
48
+ `HttpGraphQLResourceCacheControlCommand` (`dist/data/shared/graphql/cache/command.d.ts` — a raw path
49
+ to read, not an import). What matters at a call site:
50
+
51
+ - **`cacheControl` does NOT affect the key.** The same query + variables share **one** entry no
52
+ matter what policy each call passes. A `"no-cache"` call and a default call read/write the _same_
53
+ slot.
54
+ - The query is keyed by its **normalized, printed GraphQL document** — the WebApp path parses the
55
+ authored query into an AST and re-serializes it with `print()` before it reaches the cache key, so
56
+ whitespace-only differences between two calls do **not** produce separate entries. Two calls only
57
+ land in different entries if their parsed documents actually differ (selections, arguments,
58
+ fragments). Reuse the same `gql`-tagged constant anyway — it stays the single source of truth for
59
+ the operation, independent of cache-key mechanics.
60
+ - Variables are deep-cloned at call time, so mutating your variables object afterward does not
61
+ desync the key from the request body. Variables must be JSON-serializable (circular refs / BigInt
62
+ throw a typed error).
63
+ - **`headers` are part of the key** (see `QueryOptions.headers` in the `.d.ts`): two calls that
64
+ differ only in `headers` resolve to different entries, so a response scoped by an `Authorization`
65
+ header is never served to a caller that passed a different value.
66
+
67
+ ## Shared across SDK instances by host + API version
68
+
69
+ Cache bundles are deduped in a module-level registry keyed by the resolved `baseUrl` **plus the
70
+ API-version path** (`cacheBundleRegistry` / `buildCacheServices` in
71
+ `dist/data/shared/graphql/cache/services.d.ts` — raw paths). **A query run through one
72
+ `createDataSDK()` instance is a cache hit on another instance only if both the host and the
73
+ `apiVersion` match.** Two instances targeting the same host but different `apiVersion` get fully
74
+ isolated cache bundles — version isolation matters because the per-entry cache key does not carry
75
+ the request URL, so sharing across versions would let one version read another's cached response.
76
+ The per-instance fetch pipeline (CSRF, `onStatus`) stays **isolated** — a cache _miss_ routes through
77
+ the calling SDK's own fetch. The registry is a plain module-level `Map`, so sharing only happens
78
+ **within the current JavaScript realm** — it does not persist across page reloads and is not shared
79
+ across browser tabs.
80
+
81
+ **Practical implication:** you do **not** need to hoist `createDataSDK()` into a singleton purely to
82
+ share cache. Calling it per-feature is fine as long as every instance resolves the same `baseUrl` +
83
+ `apiVersion`; the cache is shared underneath. (A singleton is still reasonable for other reasons.)
84
+
85
+ ## The two refresh tools (keep them distinct)
86
+
87
+ There are **two unrelated mechanisms** for getting fresh data. Do not conflate `result.refresh()` (a
88
+ method on a live handle) with `cacheControl: "no-cache"` (a per-call option).
89
+
90
+ | | **Reactive refresh** | **Call-site cache control** |
91
+ | ------------------- | ---------------------------------------------------- | ----------------------------------------------------- |
92
+ | **API** | `result.subscribe(cb)` + `result.refresh()` | `cacheControl` on the query options bag |
93
+ | **Lifetime** | Long-lived handle; persists until you unsubscribe | One-shot, per call |
94
+ | **Pushes updates?** | Yes — `subscribe` fires on every subsequent snapshot | No — you read the returned value once |
95
+ | **PR** | #502 | #537 (W-22514759) |
96
+ | **Use when** | A mounted consumer should react / re-fetch on demand | "This specific read must bypass / only-use the cache" |
97
+
98
+ The reactive handle's lifecycle (subscribe/unsubscribe, framework teardown) is
99
+ [03-reactive-handle-lifecycle.md](./03-reactive-handle-lifecycle.md). This page covers `cacheControl`.
100
+
101
+ ### `cacheControl` — the per-call policy
102
+
103
+ Values and mechanics are defined on `CacheControl` / `CacheControlShorthand` / `CacheControlMaxAge`
104
+ in the `.d.ts`. Two behaviours worth stating that the declaration does not:
105
+
106
+ - An **`only-if-cached` miss is not an exception.** The Promise resolves and the miss surfaces on
107
+ `result.errors`. This is offline-first: a miss is **expected, not an error** — when it genuinely is
108
+ a miss, render an empty state and **do not fall back to a network read** (a fallback defeats the
109
+ point of `only-if-cached`).
110
+
111
+ **A cache miss is discriminable; other failures are message-only.** `result.errors` is a flat
112
+ `GraphQLError[]` (`message`/`locations`/`path`/`extensions` — see `dist/core/data.d.ts`). A cache
113
+ miss on `only-if-cached` carries a typed discriminator — `extensions.code === "CACHE_MISS"` — so
114
+ you can identify it positively; every other SDK-synthesized failure sets no `code` and is told
115
+ apart by `message` text alone. Verified by executing every path (not just reading it — see
116
+ `error-shape-discriminators.spec.ts`):
117
+
118
+ | Failure | `result.errors?.[0]` |
119
+ | ----------------------------------------- | -------------------------------------------------------------------------------- |
120
+ | Cache miss (`only-if-cached`, cold cache) | `{ message: "No cached entry found …", extensions: { code: "CACHE_MISS" } }` |
121
+ | Wrong operation kind | `{ message: "…requires a GraphQL query, received <kind>." }` |
122
+ | Malformed GraphQL syntax | `{ message: "Syntax Error: …" }` (parser-generated) |
123
+ | Non-serializable variables | `{ message: "…must be JSON-serializable. …" }` |
124
+ | Network failure | `{ message: <the rejected fetch's Error.message, verbatim> }` |
125
+ | Server-returned GraphQL error | Whatever the server sent (`message`, optionally `path`/`locations`/`extensions`) |
126
+
127
+ `only-if-cached` never touches the network, so an errored result with no data is by construction a
128
+ cache miss — platform-sdk synthesizes the typed `CACHE_MISS` error (see `invokeResourceGraphQL`)
129
+ rather than leaking the underlying transport's opaque empty-message 504. Because the miss is
130
+ discriminable, you can branch on it positively even at a call site that can also fail for other
131
+ reasons: check `extensions.code === "CACHE_MISS"` first, then route anything else through your
132
+ normal application error path. It's pinned by `error-shape-discriminators.spec.ts` — if that test
133
+ ever fails, this table is stale.
134
+
135
+ ```typescript
136
+ const result = await sdk.graphql!.query({
137
+ query: GET_ACCOUNTS,
138
+ variables,
139
+ cacheControl: "only-if-cached",
140
+ });
141
+ if (result.errors?.[0]?.extensions?.code === "CACHE_MISS") {
142
+ // Cold cache. Do NOT fall back to the network; that defeats offline-first.
143
+ return renderEmptyState();
144
+ }
145
+ if (result.errors?.length) {
146
+ // Any other failure (syntax, variables, network, server) — not a cache miss.
147
+ return handleQueryError(result.errors);
148
+ }
149
+ ```
150
+
151
+ - `cacheControl` does **not** affect the cache key (see above) — it only chooses the read/write
152
+ policy for that one call.
153
+
154
+ Mutations never touch the cache — `MutateOptions` has no `cacheControl`. To reflect a write, refresh
155
+ a held query (see [Refresh after a mutation](./03-reactive-handle-lifecycle.md#refresh-after-a-mutation)).
156
+
157
+ ## Choosing a strategy
158
+
159
+ | Goal | Reach for |
160
+ | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
161
+ | Default reads, freshness within the default TTL is fine | Nothing — the default cache |
162
+ | Mounted consumer should reflect cache updates / re-fetch on demand | `subscribe` + `refresh` ([reactive handle lifecycle](./03-reactive-handle-lifecycle.md)) |
163
+ | Re-fetch a held query after a mutation | `result.refresh()` ([reactive handle lifecycle](./03-reactive-handle-lifecycle.md)) |
164
+ | One-off "this read must be fresh" (button, post-mutation one-shot) | `cacheControl: "no-cache"` |
165
+ | Offline-first — render only cached data, tolerate a miss as an empty state | `cacheControl: "only-if-cached"` |
166
+ | Data changes faster than the default TTL | `cacheControl: { type: "max-age", maxAge: N }` |
167
+
168
+ `no-cache` and `refresh()` both bypass the cache and write back; the difference is **`refresh()`
169
+ pushes to existing subscribers** and is a method on a live handle, while `no-cache` is a fresh
170
+ one-shot call with no subscribers.
171
+
172
+ ## Uncached surfaces (Mosaic, OpenAI)
173
+
174
+ - **No cache exists.** Every `query()` is a network request.
175
+ - **`cacheControl` is silently ignored** — `"no-cache"`, `"only-if-cached"`, and `max-age` have no
176
+ effect. Notably `only-if-cached` will **not** raise `DataNotFoundError`, because there is no cache
177
+ layer to miss.
178
+ - **`subscribe` is real but only emits in response to `refresh()`** — there is no background cache to
179
+ push updates, so `refresh()` is the sole source of new snapshots and each one costs a network
180
+ request. See [03-reactive-handle-lifecycle.md](./03-reactive-handle-lifecycle.md).
181
+ - PR #502 flags the uncached `subscribe`/`refresh` edge semantics (re-emit-to-all, error fan-out,
182
+ ordering vs concurrent refresh) as a **known soft spot / follow-up**. Document conservatively; do
183
+ not over-promise behaviour there.
@@ -0,0 +1,84 @@
1
+ <!-- sdk-symbols
2
+ QueryResult: dist/core/data.d.ts
3
+ QuerySnapshot: dist/core/data.d.ts
4
+ QuerySubscriber: dist/core/data.d.ts
5
+ Unsubscribe: dist/core/data.d.ts
6
+ MutationResult: dist/core/data.d.ts
7
+ -->
8
+
9
+ # Living with the reactive query handle
10
+
11
+ `sdk.graphql!.query()` resolves to a `QueryResult<T>` — a reactive handle, not a plain response.
12
+ Its shape and core behaviour are owned by `QueryResult` / `QuerySnapshot` / `QuerySubscriber` in
13
+ `dist/core/data.d.ts`. This page is the residue: the subscription behaviours the declaration doesn't
14
+ spell out, and how to live with the handle inside a UI framework's lifecycle.
15
+
16
+ ## Two subscription behaviours to know
17
+
18
+ - Each `subscribe` is **independent** — unsubscribing one leaves the others live.
19
+ - `subscribe` does **not** fire on registration; it only pushes **later** snapshots. Set initial
20
+ state from the **awaited** snapshot (`result.data` / `result.errors`), not from the subscriber
21
+ callback.
22
+ - `result.refresh()` broadcasts the new snapshot to **all** current subscribers, not just the caller.
23
+
24
+ ## The lifecycle
25
+
26
+ Read the initial snapshot, register a subscriber for later snapshots, and **always unsubscribe when
27
+ the consumer goes away** (component unmount, effect re-run, view teardown) so the subscription
28
+ doesn't leak:
29
+
30
+ ```typescript
31
+ const result = await sdk.graphql!.query<GetAccountsQuery>({ query: GET_ACCOUNTS, variables });
32
+ render(result.data, result.errors); // initial snapshot (subscribe won't re-deliver this)
33
+
34
+ const unsub = result.subscribe(({ data, errors }) => render(data, errors)); // live updates
35
+ await result.refresh(); // force re-fetch → pushes to subscribers
36
+ // later, when the consumer tears down:
37
+ unsub();
38
+ ```
39
+
40
+ ## Managing the subscription in a framework
41
+
42
+ Whatever reactive/lifecycle primitive your UI layer uses — a React effect, a Vue/Svelte lifecycle
43
+ hook, a web-component `connected`/`disconnectedCallback`, a store teardown — the same three
44
+ obligations hold:
45
+
46
+ - Kick off `query()` on mount/setup and store the resolved `result`, so you can call `refresh()` on
47
+ it later (e.g. behind a "Refresh" button).
48
+ - Push each `subscribe` snapshot into your reactive state so the view re-renders.
49
+ - Run `unsub()` in the teardown path, and guard against a late-resolving `query()` writing state
50
+ **after** teardown — track a `cancelled` flag. (Because `subscribe` does not fire on registration,
51
+ the awaited snapshot is the only place your initial state comes from.)
52
+
53
+ ## Refresh after a mutation
54
+
55
+ Mutations resolve to a `MutationResult` — a one-shot `{ data, errors }` with **no**
56
+ `subscribe`/`refresh` (see `MutationResult` in the `.d.ts`; re-running a mutation on refresh would be
57
+ dangerous). A mutation **does not throw on a GraphQL-level failure** — exactly like a query, the
58
+ outcome surfaces on the resolved result (`result.errors`, with `result.data` left `undefined`). A
59
+ failed operation — or even a degenerate `{ data: undefined, errors: [] }` response from the server —
60
+ will **not** raise. So **guard on the result before treating the write as done**, and only refresh a
61
+ held query after a clean mutation:
62
+
63
+ ```typescript
64
+ const result = await sdk.graphql!.mutate({ mutation: CREATE_ACCOUNT, variables: { input } });
65
+ if (result.errors?.length || !result.data) {
66
+ // Mutation didn't succeed. Surface it through your normal error path — do NOT refresh a
67
+ // write that didn't happen. (`!result.data` also catches the empty-errors degenerate case.)
68
+ return handleMutationFailure(result.errors);
69
+ }
70
+ await accountsResult.refresh(); // re-fetches, bypasses cache, pushes to subscribers
71
+ ```
72
+
73
+ ## When to reach for this vs the default cache
74
+
75
+ _Whether_ to use `subscribe`/`refresh` at all — versus just relying on the default cache or a
76
+ one-shot `cacheControl` — is a strategy call. See the two-refresh-tools table and decision matrix in
77
+ [02-caching-and-freshness.md](./02-caching-and-freshness.md); this page is not duplicated there.
78
+
79
+ ## Uncached surfaces
80
+
81
+ On Mosaic / OpenAI the handle exists but `subscribe` only emits in response to `refresh()` — there
82
+ is no background cache to push updates, and each `refresh()` costs a network request. See
83
+ [Uncached surfaces](./02-caching-and-freshness.md#uncached-surfaces-mosaic-openai) and
84
+ [04-surfaces-and-guards.md](./04-surfaces-and-guards.md).
@@ -0,0 +1,146 @@
1
+ <!-- sdk-symbols
2
+ DataSDK: dist/core/data.d.ts
3
+ DataSDKGraphQL: dist/core/data.d.ts
4
+ DataSDKOptions: dist/data/index.d.ts
5
+ WebAppDataSDKOptions: dist/data/index.d.ts
6
+ StatusCallback: dist/data/index.d.ts
7
+ MosaicDataSDKOptions: dist/data/mosaic/index.d.ts
8
+ NodeOfConnection: dist/data/index.d.ts
9
+ -->
10
+
11
+ # Surfaces & guards
12
+
13
+ `createDataSDK()` returns a `DataSDK` with two data-access members — `graphql` (the primary route)
14
+ and `fetch` (the escape hatch; see [01-grounding-and-precedence.md](./01-grounding-and-precedence.md)
15
+ for which door to pick). Both are **optional**: a surface that doesn't support data operations
16
+ resolves to a bare `{}` rather than throwing (see `DataSDK` in `dist/core/data.d.ts`). This page is
17
+ the residue: how to guard that optionality, what `.fetch` is and how it differs from `.graphql`, how
18
+ to read `errors`, and the per-surface options.
19
+
20
+ ## `sdk.graphql!` vs guard — a surface decision
21
+
22
+ Whether to assert `sdk.graphql` after `createDataSDK()` is a **surface** call, not a style call:
23
+
24
+ ```typescript
25
+ // `!` form — WebApp-exclusive bundles only.
26
+ const result = await sdk.graphql!.query<...>({ query, variables });
27
+
28
+ // Portable guard form — safe on every surface. Use when the bundle is not WebApp-exclusive.
29
+ if (!sdk.graphql) {
30
+ // No data SDK on this surface — degrade gracefully (render empty, throw, or feature-flag off).
31
+ return;
32
+ }
33
+ const result = await sdk.graphql.query<...>({ query, variables });
34
+ ```
35
+
36
+ Use `!` **only** if the bundle ships to WebApp exclusively. A bare `sdk.graphql!` that later ships to
37
+ another surface throws `Cannot read properties of undefined` at runtime, and TypeScript **cannot**
38
+ catch it because `!` silences exactly that check. The same `!`-vs-guard decision applies to
39
+ `sdk.fetch!`.
40
+
41
+ ## `.fetch` — the escape hatch
42
+
43
+ `sdk.fetch` is the SDK's authenticated HTTP primitive: the same call shape as the global `fetch`
44
+ (`typeof fetch` — a URL/`Request` plus optional `RequestInit`, resolving to a `Response`), enriched
45
+ per surface so you don't reassemble auth and transport concerns by hand. Reach for it when the
46
+ GraphQL schema doesn't expose what you need — REST (`/services/data/…`), Apex REST
47
+ (`/services/apexrest/…`), Connect, or blob/file downloads. Default to `.graphql`; `.fetch` is the
48
+ route for everything that has no GraphQL representation.
49
+
50
+ What it carries, per surface:
51
+
52
+ - **WebApp** — CSRF token handling with automatic retry on token rejection, the `Accept-Language`
53
+ and client-context headers the platform expects, and relative URLs resolved against the app's API
54
+ base path. Your `onStatus` callbacks fire on `.fetch` responses too, so a `401` handler
55
+ re-authenticates for `.fetch` and `.graphql` alike. On this surface `.graphql` is itself built on
56
+ top of `.fetch`.
57
+ - **Mosaic** — no `.fetch`. `MosaicDataSDK` only implements `graphql`; guard for `.fetch`'s absence
58
+ rather than assuming it.
59
+ - **OpenAI** — no `.fetch`. That surface exposes only `.graphql` via an MCP tool, so guard for
60
+ `.fetch`'s absence rather than assuming it.
61
+
62
+ Two things `.fetch` does **not** do, both by contrast with `.graphql`:
63
+
64
+ - **No cache.** `.fetch` responses are never cached by the SDK — caching is a `.graphql`-only
65
+ concern (see [02-caching-and-freshness.md](./02-caching-and-freshness.md)). Layer your own if you
66
+ need it.
67
+ - **No `errors` envelope.** `.fetch` resolves to a raw `Response`, so the HTTP status _is_ the
68
+ signal — check `response.ok` / `response.status` and parse the body yourself, exactly as with the
69
+ platform `fetch`. This is the inverse of the `.graphql` "HTTP 200 ≠ success" model below.
70
+
71
+ ```typescript
72
+ if (!sdk.fetch) {
73
+ // No fetch on this surface (e.g. OpenAI) — degrade gracefully.
74
+ return;
75
+ }
76
+
77
+ // REST read — the standard Response model: status is the signal.
78
+ const res = await sdk.fetch("/services/data/v64.0/sobjects/Account/001xx000003DGb0AAG");
79
+ if (!res.ok) {
80
+ throw new Error(`Account read failed: ${res.status}`);
81
+ }
82
+ const account = await res.json();
83
+
84
+ // Apex REST — POST to a custom endpoint.
85
+ const apexRes = await sdk.fetch("/services/apexrest/MyService", {
86
+ method: "POST",
87
+ headers: { "Content-Type": "application/json" },
88
+ body: JSON.stringify({ recordId: "001xx000003DGb0AAG" }),
89
+ });
90
+ ```
91
+
92
+ Guard `sdk.fetch` exactly as you guard `sdk.graphql` — the `!`-vs-guard decision above applies
93
+ identically.
94
+
95
+ ## HTTP 200 ≠ success — always read `.graphql` `errors`
96
+
97
+ `DataSDKGraphQL.query` / `.mutate` **always resolve**; they do not reject. Every failure (GraphQL
98
+ errors, parse errors, wrong operation kind, non-serializable variables, network errors) is funnelled
99
+ into the resolved `result.errors` array (see `DataSDKGraphQL` in the `.d.ts`). So a settled Promise
100
+ is **not** a successful result — you must inspect `result.errors`. (This is `.graphql`-specific:
101
+ `.fetch` reports failure through the `Response` status instead, per the section above.)
102
+
103
+ Choose the product-appropriate stance; all three inspect `result.errors`:
104
+
105
+ ```typescript
106
+ // Strict — any errors = failure
107
+ if (result.errors?.length) throw new Error(result.errors.map((e) => e.message).join("; "));
108
+
109
+ // Tolerant — log, use whatever data came back (partial success)
110
+ if (result.errors?.length) console.warn("GraphQL partial errors:", result.errors);
111
+
112
+ // Discriminated — fail only when NO data returned
113
+ if (!result.data && result.errors?.length) {
114
+ throw new Error(result.errors.map((e) => e.message).join("; "));
115
+ }
116
+ ```
117
+
118
+ ## Per-surface options
119
+
120
+ `createDataSDK(options)` takes a `DataSDKOptions` bag; the fields you set depend on the surface. The
121
+ declarations own the field lists — this is just the routing:
122
+
123
+ - **WebApp** — `WebAppDataSDKOptions` (`options.webapp`): `basePath`, and `onStatus` per-HTTP-status
124
+ callbacks (each a `StatusCallback`) for cases like re-authenticating on a `401`. This is the
125
+ cached surface — see [02-caching-and-freshness.md](./02-caching-and-freshness.md).
126
+ - **Mosaic** — `MosaicDataSDKOptions` (`options.mosaic`): server-side (Node) auth via `instanceUrl` /
127
+ `accessToken` / `apiVersion`. Uncached.
128
+ - **OpenAI** — no surface options bag; delegates to an MCP tool. Uncached, and it exposes no header
129
+ channel, so per-request `headers` are ignored there.
130
+
131
+ ## Uncached surfaces (Mosaic, OpenAI)
132
+
133
+ - No cache exists — every `query()` is a network request, and `cacheControl` is silently ignored.
134
+ - `subscribe` is real but only emits in response to `refresh()`.
135
+
136
+ The full uncached-surface behaviour and the caching model it contrasts with are in
137
+ [02-caching-and-freshness.md](./02-caching-and-freshness.md#uncached-surfaces-mosaic-openai) and
138
+ [03-reactive-handle-lifecycle.md](./03-reactive-handle-lifecycle.md). The `query`/`mutate` shape is
139
+ identical across surfaces, so the same call site runs everywhere — only caching differs.
140
+
141
+ ## `NodeOfConnection` — unwrapping a connection
142
+
143
+ Read queries that return a Relay-style `{ edges: [{ node }] }` connection can have the element type
144
+ unwrapped with `NodeOfConnection<T>` (see the declaration in `dist/data/index.d.ts`). It resolves to
145
+ `never` when `T` isn't such a connection, and it is **read-side only** — only `query` returns
146
+ connections, so it never applies to `mutate` results.
@@ -0,0 +1,126 @@
1
+ <!-- sdk-symbols
2
+ createDataSDK: dist/data/index.d.ts
3
+ gql: dist/data/gql.d.ts
4
+ NodeOfConnection: dist/data/index.d.ts
5
+ CacheControl: dist/core/data.d.ts
6
+ -->
7
+
8
+ # Migration — old Data SDK → `@salesforce/platform-sdk`
9
+
10
+ The Data SDK changed in two breaking ways (PR #502, shipped in `@salesforce/platform-sdk` v10.10.1):
11
+
12
+ 1. **Package renamed** — `@salesforce/sdk-data` → **`@salesforce/platform-sdk`**.
13
+ 2. **`sdk.graphql` reshaped** from a **callable method** into a **namespace** with `.query()` and
14
+ `.mutate()`, both taking an **options object**.
15
+
16
+ > Any remaining `@salesforce/sdk-data` **import in consumer source** is a leftover from before this
17
+ > migration — not canonical. Always import from `@salesforce/platform-sdk`. (This does not cover
18
+ > intentional historical/comparative references elsewhere in the repo — e.g. this package's own
19
+ > `PACKAGING-STRATEGY.md` or the migration-facing skill docs — which are expected to keep the old
20
+ > name.)
21
+
22
+ This is the **only** page where the dead callable API appears, for comparison. The **new-side**
23
+ snippets below are illustrative of the transition, **not** the source of truth for the current call
24
+ contract — for the authoritative new signatures read `dist/core/data.d.ts` and `dist/data/index.d.ts`
25
+ (tier-2a). If a new-side snippet here has drifted from the installed declaration, the declaration
26
+ wins.
27
+
28
+ ## 1. Import
29
+
30
+ ```diff
31
+ - import { createDataSDK, gql, type NodeOfConnection } from "@salesforce/sdk-data";
32
+ + import { createDataSDK, gql, type NodeOfConnection, type CacheControl } from "@salesforce/platform-sdk";
33
+ ```
34
+
35
+ `createDataSDK`, `gql`, `NodeOfConnection`, and `CacheControl` all export from
36
+ `@salesforce/platform-sdk`.
37
+
38
+ ## 2. Query call
39
+
40
+ ```diff
41
+ - // OLD — callable, positional args, returns a response object with .data / .errors
42
+ - const response = await sdk.graphql?.<GetAccountsQuery, GetAccountsQueryVariables>(GET_ACCOUNTS, variables);
43
+ - const accounts = response?.data?.uiapi?.query?.Account?.edges ?? [];
44
+ - if (response?.errors?.length) { /* ... */ }
45
+
46
+ + // NEW — namespace method, options bag, returns a reactive QueryResult
47
+ + const result = await sdk.graphql!.query<GetAccountsQuery, GetAccountsQueryVariables>({
48
+ + query: GET_ACCOUNTS,
49
+ + variables,
50
+ + });
51
+ + const accounts = result.data?.uiapi?.query?.Account?.edges ?? [];
52
+ + if (result.errors?.length) { /* ... */ }
53
+ ```
54
+
55
+ Passing the generated `<GetAccountsQuery>` type parameter makes `result.data` fully typed — no
56
+ `as any` cast needed.
57
+
58
+ | Old | New |
59
+ | ------------------------------------- | -------------------------------------------------------- |
60
+ | `sdk.graphql?.(QUERY, vars)` | `sdk.graphql!.query({ query: QUERY, variables: vars })` |
61
+ | positional `<T, V>(query, variables)` | type params on `query<T, V>(options)` |
62
+ | `response.data` / `response.errors` | `result.data` / `result.errors` (same fields) |
63
+ | (none) | `result.subscribe(cb)` / `result.refresh()` — new handle |
64
+ | (none) | `cacheControl` option — new per-call cache policy |
65
+
66
+ ## 3. Mutation call
67
+
68
+ The old callable form was used for mutations too. Mutations now have their own method, and the
69
+ operation key is **`mutation`**, not `query`:
70
+
71
+ ```diff
72
+ - const response = await sdk.graphql?.<CreateAccountMutation>(CREATE_ACCOUNT, { input });
73
+ + const { data, errors } = await sdk.graphql!.mutate<CreateAccountMutation, CreateAccountMutationVariables>({
74
+ + mutation: CREATE_ACCOUNT, // key is `mutation`, not `query`
75
+ + variables: { input },
76
+ + });
77
+ ```
78
+
79
+ `mutate()` returns `{ data, errors }` only — **no** `subscribe`/`refresh`, and it is **never cached**.
80
+ To refresh a list after a mutation, hold the query `result` and call `result.refresh()` (see
81
+ [03-reactive-handle-lifecycle.md](./03-reactive-handle-lifecycle.md)).
82
+
83
+ ## 4. Optional chaining → non-null assertion
84
+
85
+ The old guidance was "always use optional chaining" (`sdk.graphql?.()`). Real consumer code now uses
86
+ the **non-null assertion** after `createDataSDK()` — but whether `!` or a guard is correct is a
87
+ surface decision, covered in [04-surfaces-and-guards.md](./04-surfaces-and-guards.md):
88
+
89
+ ```diff
90
+ - const response = await sdk.graphql?.(QUERY, vars);
91
+ + const result = await sdk.graphql!.query({ query: QUERY, variables: vars });
92
+ ```
93
+
94
+ ## 5. Generated types — unchanged generation, new call placement
95
+
96
+ The generated operation type **names** (`<Op>Query` / `<Op>QueryVariables` / `<Op>Mutation` /
97
+ `<Op>MutationVariables`) are **unchanged**. Only **where** the type params attach moves — from the
98
+ callable to the namespace method:
99
+
100
+ ```diff
101
+ - await sdk.graphql?.<GetAccountsQuery, GetAccountsQueryVariables>(GET_ACCOUNTS, variables);
102
+ + await sdk.graphql!.query<GetAccountsQuery, GetAccountsQueryVariables>({ query: GET_ACCOUNTS, variables });
103
+ ```
104
+
105
+ `NodeOfConnection` (read-side) still unwraps a connection the same way. **Regenerating** the types is
106
+ a repo/skill command, not something this package owns — this page only covers where the generated
107
+ names now attach.
108
+
109
+ ## 6. New capabilities unlocked while migrating
110
+
111
+ The reshape also unlocked the freshness features (none required to get back to working). The one
112
+ migration-specific gotcha: **caching is now on by default** (WebApp) — if any code relied on every
113
+ call hitting the network, add `cacheControl: "no-cache"` to it. The reactive `subscribe`/`refresh`
114
+ handle and the rest of `CacheControl` are in
115
+ [02-caching-and-freshness.md](./02-caching-and-freshness.md) and
116
+ [03-reactive-handle-lifecycle.md](./03-reactive-handle-lifecycle.md).
117
+
118
+ ## 7. Migration checklist
119
+
120
+ - [ ] Replace every `@salesforce/sdk-data` import with `@salesforce/platform-sdk`.
121
+ - [ ] Convert every `sdk.graphql?.(q, v)` query to `sdk.graphql!.query({ query: q, variables: v })`.
122
+ - [ ] Convert every mutation call to `sdk.graphql!.mutate({ mutation: m, variables: v })` (key is `mutation`).
123
+ - [ ] Move generated type params onto `query<T,V>` / `mutate<T,V>`.
124
+ - [ ] Rename `response` → `result`; `response.data`/`.errors` → `result.data`/`.errors`.
125
+ - [ ] Add `cacheControl: "no-cache"` to any call that genuinely must always hit the network.
126
+ - [ ] Re-check the `!`-vs-guard decision per surface ([surfaces & guards](./04-surfaces-and-guards.md)).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/platform-sdk",
3
- "version": "11.69.2",
3
+ "version": "11.70.0",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -112,15 +112,20 @@
112
112
  },
113
113
  "./package.json": "./package.json"
114
114
  },
115
+ "directories": {
116
+ "doc": "docs"
117
+ },
115
118
  "files": [
116
- "dist"
119
+ "dist",
120
+ "docs/data"
117
121
  ],
118
122
  "scripts": {
119
123
  "build": "vite build",
120
124
  "clean": "rm -rf dist",
121
125
  "dev": "vite build --watch",
122
- "test": "vitest run --typecheck && npm run test:examples",
126
+ "test": "vitest run --typecheck && npm run test:examples && npm run test:docs",
123
127
  "test:examples": "tsx scripts/check-examples.mts",
128
+ "test:docs": "tsx scripts/check-docs-symbols.mts",
124
129
  "test:watch": "vitest",
125
130
  "test:coverage": "vitest run --coverage --typecheck"
126
131
  },
@@ -134,7 +139,7 @@
134
139
  "@conduit-client/service-pubsub": "3.19.6",
135
140
  "@conduit-client/service-retry": "3.19.6",
136
141
  "@conduit-client/utils": "3.19.6",
137
- "@salesforce/jsonrpc": "^11.69.2",
142
+ "@salesforce/jsonrpc": "^11.70.0",
138
143
  "@salesforce/sf-embedding-bridge": "2.2.5-rc.2"
139
144
  },
140
145
  "peerDependencies": {