v0.18: Scalar, Typed File Downloads, Filter-aware Collections
v0.18 focuses on richer data modeling for values that vary by request context, simpler typed downloads, and collection matching that better reflects real API filters.
New Features:
- Scalar schema - Lens-dependent entity fields (e.g. portfolio-specific values) without ever mutating the underlying entity
- RestEndpoint
contentproperty - Typed file downloads, text responses, and streaming with a single property - resource()
nonFilterArgumentKeys- Sort/pagination args don't fragment your Collections
Other Improvements:
- Binary Content-Type auto-detection - Images, PDFs, and other binary responses are handled automatically with no configuration (#3868)
- Collection extender body types match HTTP method semantics - PATCH extenders (
.move,.remove) accept partial bodies; standalone RestEndpoint derives a typed body from the Collection's entity schema (#3910) - Export
CollectionOptionsfrom@data-client/endpointand@data-client/restfor typed Collection construction (#3904)
import { Collection, Entity, RestEndpoint, Scalar } from '@data-client/rest'; export class Company extends Entity { id = ''; name = ''; price = 0; pct_equity = 0; shares = 0; } const PortfolioScalar = new Scalar({ lens: args => args[0]?.portfolio, key: 'portfolio', entity: Company, }); Company.schema = { pct_equity: PortfolioScalar, shares: PortfolioScalar, }; export const getCompanies = new RestEndpoint({ path: '/companies', searchParams: {} as { portfolio: string }, // `portfolio` is a lens, not a filter — the returned Company list is the same // regardless of lens. Dropping it from `argsKey` collapses every portfolio to // one Collection pk, so `Collection.queryKey()` finds the list on every // switch and `useSuspense` reuses it without refetching. schema: new Collection([Company], { argsKey: () => ({}) }), }); export const getPortfolioColumns = new RestEndpoint({ path: '/companies/columns', searchParams: {} as { portfolio: string }, schema: new Collection([PortfolioScalar], { argsKey: ({ portfolio }) => ({ portfolio }), }), });
The example shows the same Company entities rendered through different portfolio lenses. Stable Entity fields are reused, while lens-dependent values are selected from separate Scalar cells.
- Schema.denormalize() takes a delegate -
denormalize(input, args, unvisit)→denormalize(input, delegate). Affects custom Schema implementations only. - Schema.normalize() takes a delegate -
normalize(input, parent, key, args, visit, delegate)→normalize(input, parent, key, delegate). Affects custom Schema implementations only.
Upgrade with the automated codemod:
npx jscodeshift -t https://dataclient.io/codemods/v0.18.js --extensions=ts,tsx,js,jsx src/
