v0.18: Scalar, descargas de archivos tipadas, Collections conscientes de filtros
v0.18 se centra en un modelado de datos más rico para valores que varían según el contexto de la petición, descargas tipadas más simples y una coincidencia de collections que refleja mejor los filtros reales de las APIs.
Nuevas funcionalidades:
- Schema Scalar - Campos de entidad dependientes de un lens (p. ej. valores específicos de un portafolio) sin mutar jamás la entidad subyacente
- Propiedad
contentde RestEndpoint - Descargas de archivos tipadas, respuestas de texto y streaming con una sola propiedad nonFilterArgumentKeysen resource() - Los argumentos de ordenamiento/paginación no fragmentan tus Collections
Otras mejoras:
- Detección automática de Content-Type binarios - Las imágenes, PDFs y otras respuestas binarias se manejan automáticamente sin configuración (#3868)
- Los tipos de body de los extenders de Collection coinciden con la semántica del método HTTP - Los extenders PATCH (
.move,.remove) aceptan bodies parciales; un RestEndpoint independiente deriva un body tipado a partir del schema de entidad de la Collection (#3910) - Se exporta
CollectionOptionsdesde@data-client/endpointy@data-client/restpara construir Collections con tipado (#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: string }) => ({ portfolio }), }), });
El ejemplo muestra las mismas entidades Company renderizadas a través de distintos lenses de portafolio. Los campos estables de la Entity se reutilizan, mientras que los valores dependientes del lens se seleccionan de celdas Scalar separadas.
- Schema.denormalize() recibe un delegate -
denormalize(input, args, unvisit)→denormalize(input, delegate). Afecta solo a implementaciones personalizadas de Schema. - Schema.normalize() recibe un delegate -
normalize(input, parent, key, args, visit, delegate)→normalize(input, parent, key, delegate). Afecta solo a implementaciones personalizadas de Schema.
¿Usas un agente de IA? Instala la skill de migración: ejecuta el codemod, registra
argsKey para los schemas que dependen de los argumentos y se encarga de los casos que el codemod
no puede resolver (campos de clase, asignación dinámica de métodos, bloques <script> de SFC, helpers personalizados):
- Skills
- OpenSkills
- Claude Code
npx skills add reactive/data-client --skill data-client-v0.18-migration
npx openskills install reactive/data-client/.agents/skills/data-client-v0.18-migration
claude plugin marketplace add reactive/data-client
claude plugin install migrations@data-client
De lo contrario, ejecuta el codemod directamente; cubre los casos comunes:
npx jscodeshift -t https://dataclient.io/codemods/v0.18.js --extensions=ts,tsx,js,jsx src/
