.cursor/skills/data-client-schema/SKILL.md
Define data schemas - Entity, Collection, Union, Query, pk/primary key, normalize/denormalize, relational/nested data, polymorphic types, Invalidate, Values
npx skillsauth add reactive/data-client data-client-schemaInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Define schemas to represent the JSON returned by an endpoint. Compose these to represent the data expected.
{[key:string]: Schema} - immutable objects[Schema] - immutable listsnew Collection(Values(Schema)) - mutable/growable mapsnew Query(Queryable) - memoized programmatic selectors
const queryRemainingTodos = new Query(
TodoResource.getList.schema,
entries => entries.filter(todo => !todo.completed).length,
);
const groupTodoByUser = new Query(
TodoResource.getList.schema,
todos => Object.groupBy(todos, todo => todo.userId),
);
Entity subclass defines defaults for all non-optional serialised fields.pk() only when the primary key ≠ id.pk() return type is number | string | undefinedEntity.process(value, parent, key, args) to insert fields based on args/urlstatic schema (optional) for nested schemas or deserialization functions
process() → validate() → pk() → if existing: mergeWithStore() which calls shouldUpdate() and maybe shouldReorder() + merge(); metadata via mergeMetaWithStore().createIfValid() → validate() → fromJS().To define polymorphic resources (e.g., events), use Union and a discriminator field.
import { Union } from '@data-client/rest'; // also available from @data-client/endpoint
export abstract class Event extends Entity {
type: EventType = 'Issue'; // discriminator field is shared
/* ... */
}
export class PullRequestEvent extends Event { /* ... */ }
export class IssuesEvent extends Event { /* ... */ }
export const EventResource = resource({
path: '/users/:login/events/public/:id',
schema: new Union(
{
PullRequestEvent,
IssuesEvent,
// ...other event types...
},
'type', // discriminator field
),
});
When an endpoint returns partial or differently-shaped data for an entity already in cache (e.g., a metadata endpoint, a stats endpoint, a lazy-load expansion endpoint), use the same Entity as the schema — don't create a wrapper entity.
See partial-entities for patterns and examples.
schema on every resource/entity/collection for normalizationEntity.schema for client-side joinsDenormalize<> type from rest/endpoint/graphql instead of InstanceType<>. This will handle all schemas like Unions, not just Entity.fromJS() or assign default properties for class fieldsEntity.schema for client-side joinsFor detailed API documentation, see the references directory:
tools
Create a GitHub pull request from current working changes. Handles all git states - uncommitted changes, no branch, unpushed commits, etc. Analyzes diffs and changesets to generate a PR with filled-in template. Opens the PR in the browser when done. Use when the user asks to create a PR, open a PR, submit changes, or push for review.
tools
Migrate @data-client/rest path strings from path-to-regexp v6 to v8 syntax. Use when upgrading path-to-regexp, updating RestEndpoint.path or resource path strings, or when seeing errors about unexpected ?, +, (, or ) in paths.
development
Write, update, and format docs for public APIs - API reference, README, docstrings, usage examples, migration guides, deprecation notices
tools
Setup, install, and onboard new developers to Reactive Data Client monorepo - nvm, yarn, build, test, getting started guide