experience-ui-bundle-salesforce-data-access

MUST activate whenever a uiBundles/*/src/ project reads, writes, or displays Salesforce data — INCLUDING building a page, list, table, card grid, dashboard, or form that shows, filters, counts, or edits records of any object (e.g. Property__c, Account, Case), even when the prompt names only the UI o

By forcedotcom · 4,905 installs

npx skills add forcedotcom/sf-skills --skill experience-ui-bundle-salesforce-data-access

Source repository · Upstream listing

Salesforce Data Access (UI bundles) All Salesforce data access in a UI bundle goes through the @salesforce/platform sdk data SDK. The SDK handles auth, CSRF, and base URL resolution, and — on the WebApp surface — caches every GraphQL query by default. This file is the workflow + guardrail spine . Depth lives in linked docs: [references/graphiti cli.md](references/graphiti cli.md) — the graphiti CLI ( sf gql commands) that compiles a small JSON spec into a schema correct, guardrail applied query + variables + types. The preferred way to author the GraphQL in steps below; falls back to the schema grep script when unavailable. [references/sdk api.md](references/sdk api.md) — query / mutate call surface + generated type placement; the behavior nuance (surfaces, error stances, QueryResult ) grounds on tier 2b . [references/caching.md](references/caching.md) — the on by default cache + two refresh modes; behavior grounds on tier 2b docs/data/ when installed, with the full version stamped fallback here. [references/graphql hand authoring.md](references/graphql hand authoring.md) — schema lookup, read / mutation templates, every platform guardrail ( @optional , pagination, limits, semi join, wrappers, error table…). [references/rest and integration.md](references/rest and integration.md) — sdk.fetch , the supported API allowlist, and the reactive/lifecycle integration patterns. [references/migration.md](references/migration.md) — old @salesforce/sdk data callable code → new namespace. The only place the dead API appears as usable code. The one paragraph mental model const sdk = await createDataSDK() . Then sdk.graphql is a namespace , not a function: sdk.graphql!.query({...}) for reads, sdk.graphql!.mutate({...}) for writes. On WebApp, every query() is cached by default (300s). HTTP 200 never means success — always check result.errors . Verify every entity and field against the schema before you query it: one unverified field fails the whole query at runtime, and schema.graphql is too large to eyeball — look it up. Typed call params ( query<GetAccountsQuery, GetAccountsQueryVariables ), the CacheControl type, and NodeOfConnection<T (extracts a node type from a Connection for clean typing) all live in [references/sdk api.md](references/sdk api.md). This changed (breaking — PR 502). The previous callable sdk.graphql(...) form and the previous package name are dead — the code above is the only correct form. If you encounter the old API in existing code (or a stale dist/ artifact), don't copy it; convert it per [Working on existing code]( working on existing code migration). sdk.graphql! is WebApp only. The non null assertion above is correct only if the bundle runs solely on WebApp. On other surfaces it can crash — decide before you write it. See [Surfaces — ! vs guard]( surfaces sdkgraphql vs guard) below. Ground the SDK contract on the installed types (tier 2a) @salesforce/platform sdk force publishes on a shared version line and moves fast. This SKILL's prose is a point in time snapshot of the call contract; the installed declarations are authoritative for the version you actually have . Before writing any query / mutate , read the installed types and let them win: node modules/@salesforce/platform sdk/dist/core/data.d.ts — query / mutate signatures, QueryResult (has subscribe / refresh ) vs MutationResult (has neither, by design), the CacheControl union, the default TTL. node modules/@salesforce/platform sdk/dist/data/index.d.ts — createDataSDK , gql , NodeOfConnection . Precedence — installed .d.ts beats this SKILL's prose. If a signature, type, or default here disagrees with the installed declaration, follow the declaration and note the drift; do not "correct" the types to match the prose. Grounding ladder (one model, two axes): Tier Grounds Answers Via tier 1 GraphQL schema what data exists graphiti / graphql search.sh (Precondition 2) tier 2a SDK contract how you call it the installed .d.ts above tier 2b SDK behavior how it behaves the installed docs/data/ folder (below) spine this SKILL.md workflow + guardrails that orchestrate all three; the fallback when a tier can't ground Fallback when the .d.ts is absent — the package is installed but ships no declarations (a stale or types stripped build artifact). Then use this SKILL's prose as best effort. This fallback does not cover a missing package: if @salesforce/platform sdk isn't installed, stop and install it (Precondition 1) — do not author calls from prose against a dependency you don't have. Ground the SDK behavior on the installed docs (tier 2b) The same package ships an authored behavior guide beside its types: node modules/@salesforce/platform sdk/docs/data/ (numbered files, read them in order). Tier 2a's .d.ts fixes the call contract ; this folder is authoritative for the behavior the contract doesn't spell out — the caching model, the surface ! vs guard decision, error handling stances, the migration mindset. Read it before choosing a caching policy, a surface assertion, or an error stance, and let it win — same precedence as tier 2a (the installed source beats this prose; when present it's the fuller, version current copy). Fallback when the folder is absent (older SDK, or a types only build): this SKILL keeps a thin per behavior fallback — below and in each section — sized only to keep you moving; act on it. As with tier 2a, a missing package is different: if @salesforce/platform sdk isn't installed, stop and install it (Precondition 1). Surfaces — sdk.graphql! vs guard sdk.graphql / sdk.fetch are genuinely optional (typed graphql?: … ), and whether you may assert them with ! is a runtime crash decision — make it before writing any query / mutate . Fallback rule: WebApp only bundle → sdk.graphql! is safe; any bundle that might run off WebApp (Mosaic / OpenAI / MCPApps) → guard first ( if (!sdk.graphql) return … ), then call. If you cannot prove WebApp only, guard — a bare ! that later ships elsewhere throws Cannot read properties of undefined and TypeScript won't catch it (same for sdk.fetch! ). The surface matrix, the portable guard snippet, and the full reasoning ground on tier 2b docs/data/ (fallback above); the guard snippet is also in [references/sdk api.md](references/sdk api.md sdkgraphql vs guard). Step 0 — Route the task The task is… Go to Read records [Read workflow]( read workflow) below Create / update / delete records [Write workflow]( write workflow) below Object/field metadata, picklist values, related list metadata, aggregations [Beyond record CRUD]( beyond record crud) below Data is stale / "add a refresh button" / "cache it longer" [Freshness & caching]( freshness caching) below Something GraphQL can't express (Apex REST, file upload, Einstein) [references/rest and integration.md](references/rest and integration.md) Migrating old sdk.graphql?.(query, vars) code [Working on existing code]( working on existing code migration) below GraphQL covers far more than record reads and writes — prefer it for anything the uiapi namespace exposes (see [Beyond record CRUD]( beyond record crud)). Reach for REST only when the data genuinely lives outside uiapi (Apex REST, file upload, Einstein) — see [references/rest and integration.md](references/rest and integration.md). Preconditions — verify before writing any query <skill dir below is wherever this skill is installed (the directory this SKILL.md loaded from). The schema lookup script ships inside it. The script does not hunt for schema.graphql by walking up the tree — an ancestor schema can belong to a different org and would validate fields against the wrong one. Resolve the schema explicitly: run from the SFDX project root (where schema.graphql lives), or pass schema <path / set GRAPHQL SCHEMA=<path . The script echoes the schema it resolved ( [graphql search] using schema: … on stderr) — glance at it to confirm you grounded against the right file. Requirement Verify If missing 1 @salesforce/platform sdk installed and its contract + behavior docs read package.json in the UI bundle dir lists it; then read dist/core/data.d.ts + dist/data/index.d.ts ([tier 2a]( ground the sdk contract on the installed types tier 2a)) and the docs/data/ folder ([tier 2b]( ground the sdk behavior on the installed docs tier 2b)), and let them win over this SKILL's prose Not installed → tell user to install it; cannot proceed. Installed but .d.ts / docs/ absent (stale or types only artifact) → use prose fallback 2 A grounding tool resolves Preferred: npx graphiti sf gql discover '{"org":"<alias ","mode":"list objects"}' from the UI bundle dir returns objects. Fallback: bash <skill dir /scripts/graphql search.sh <Entity from the project root prints a lookup, not "schema.graphql not found" No graphiti dep / org won't prime → use the script. Script can't find schema.graphql → pass schema <path , or npm run graphql:schema from the UI bundle dir. ([references/graphiti cli.md](references/graphiti cli.md) covers CLI setup) 3 Target objects/fields deployed The object appears in sf gql discover (or graphql search.sh <Entity returns output) Entity absent usually means it isn't deployed (or the cache/schema is stale). Refresh: npx graphiti sf gql connect '{"org":"<alias ","forceRefresh":true}' (CLI) or npm run graphql:schema (script). If still absent, deploy the metadata (the platform metadata deploy skill handles this) and assign the permission sets, then re check If preconditions aren't met you may still scaffold components, routes, and layout — but use empty arrays / null for data, mark query sites with // TODO: add query after schema verification , and add a plan item to return. Do not write GraphQL strings until the schema workflow is complete. Read workflow 1. Look up the schema first — never guess a name. Preferred (graphiti): when the exact API name is at all uncertain, list before you describe — npx graphiti sf gql discover '{"org":"<alias ","mode":"list objects","search":"<intent "}' to find the real name, then npx graphiti sf gql discover '{"org":"<alias ","mode":"describe object","object":"<Entity "}' for exact field/type names, picklist values, filterable/sortable. An empty list or missing object is a fact about the org (wrong name or not deployed), not a tool failure — re list or forceRefresh ; do not fall back to the script for this (see guardrail 2). Fallback is only for a CLI that genuinely can't run (no graphiti dep / org won't prime): bash <skill dir /scripts/graphql search.sh <Entity from the SFDX project root. (Full rules: [references/graphql hand authoring.md](references/graphql hand authoring.md).) 2. Write the query. Preferred — compile it with graphiti: npx graphiti sf gql list '{"org":"<alias ","object":"<Entity ","fields":[…],"first":N}' returns a { query, variables, types, warnings } envelope with @optional , value / displayValue , edges/node , and first: / pageInfo already applied . Confirm warnings: [] (a non empty array means the object wasn't in the primed schema — the query is degraded; don't ship it), then paste the query verbatim into inline gql (simple) or an external .graphql file (one operation per file, imported with the bundler's ?raw suffix — import Q from "./q.graphql?raw" brings the file in as a plain string). Fallback — hand author: apply @optional to every selectable FLS gated field — scalar leaf fields ( Name @optional { value } ) and par