UNPKG

@data-client/rest

Version:

Quickly define typed REST resources and endpoints

1,110 lines (797 loc) 82.2 kB
# @data-client/rest ## 0.18.1 ### Patch Changes - [`adb82f1`](https://github.com/reactive/data-client/commit/adb82f15c1959ecfc09565a519d2672a2d63178c) - RestEndpoint.remove.name is 'partialUpdate' since it uses 'PATCH' ## 0.18.0 ### Minor Changes - [#3931](https://github.com/reactive/data-client/pull/3931) [`959465a`](https://github.com/reactive/data-client/commit/959465a064db687176e483932987b083f19718eb) - Allow one `Collection` schema to be used both top-level and nested. Before: ```ts const getTodos = new Collection([Todo], { argsKey }); const userTodos = new Collection([Todo], { nestKey }); ``` After: ```ts const userTodos = new Collection([Todo], { argsKey, nestKey }); ``` - [#3887](https://github.com/reactive/data-client/pull/3887) [`84078d7`](https://github.com/reactive/data-client/commit/84078d7d36bf5cf0fd16a479ce16c48c5d804f32) - **BREAKING**: `Schema.denormalize()` is now `(input, delegate)` instead of the previous `(input, args, unvisit)` 3-parameter signature. ```ts // before denormalize(input, args, unvisit) { return unvisit(this.schema, input); } // after denormalize(input, delegate) { return delegate.unvisit(this.schema, input); } ``` The new [`IDenormalizeDelegate`](https://dataclient.io/rest/api/SchemaSimple) exposes `unvisit`, `args`, and a new `argsKey(fn)` helper that registers a memoization dimension when output varies with endpoint args. Reading `delegate.args` directly does _not_ contribute to cache invalidation — schemas that branch on args must call `argsKey`. The `fn` reference doubles as the cache path key, so it must be **referentially stable** — define it on the instance or at module scope, not inline per call: ```ts class LensSchema { constructor({ lens }) { this.lensSelector = lens; // stable reference across calls } denormalize(input, delegate) { const portfolio = delegate.argsKey(this.lensSelector); return this.lookup(input, portfolio); } } ``` All built-in schemas (`Array`, `Object`, `Values`, `Union`, `Query`, `Invalidate`, `Lazy`, `Collection`) have been updated. Custom schemas implementing `SchemaSimple` must update their `denormalize` signature. `Schema.normalize()` and the `visit()` callback also gain an optional trailing `parentEntity` argument tracking the nearest enclosing entity-like schema. This is additive — existing schemas don't need changes unless they want to use it. - [#3887](https://github.com/reactive/data-client/pull/3887) [`84078d7`](https://github.com/reactive/data-client/commit/84078d7d36bf5cf0fd16a479ce16c48c5d804f32) - Add [Scalar](https://dataclient.io/rest/api/Scalar) schema for lens-dependent entity fields. `Scalar` models entity fields whose values vary by a runtime "lens" (such as the selected portfolio, currency, or locale). Multiple components can render the same entity through different lenses simultaneously — each sees the correct values without the entity itself ever being mutated. Lens-dependent values are stored in a separate cell table and joined at denormalize time from endpoint args. New exports: `Scalar`, `schema.Scalar`. A single `Scalar` instance can serve both as an `Entity.schema` field (parent entity inferred from the visit) and standalone — inside `Values(Scalar)`, `[Scalar]`, or `Collection([Scalar])` — for cheap column-only refreshes (entity bound explicitly via `entity`). Cell pks are derived from the map key or via `Scalar.entityPk()`, which defaults to `Entity.pk()` so custom and composite primary keys work with no override: ```ts import { Collection, Entity, RestEndpoint, Scalar } from '@data-client/rest'; class Company extends Entity { id = ''; 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, }; // Full load — Company rows + scalar cells for the current portfolio export const getCompanies = new RestEndpoint({ path: '/companies', searchParams: {} as { portfolio: string }, schema: new Collection([Company], { argsKey: () => ({}) }), }); // Lens-only refresh — writes to the same Scalar(portfolio) cell table export const getPortfolioColumns = new RestEndpoint({ path: '/companies/columns', searchParams: {} as { portfolio: string }, schema: new Collection([PortfolioScalar], { argsKey: ({ portfolio }) => ({ portfolio }), }), }); ``` `useSuspense(getCompanies, { portfolio: 'A' })` and `useSuspense(getCompanies, { portfolio: 'B' })` resolve to different `pct_equity` / `shares` while sharing the same `Company` row. `Scalar.queryKey` enumerates cells in its table for the current lens, so endpoints that use `Scalar` directly as their top-level schema reconstruct from cache without a network round-trip once the cells are present. ### Patch Changes - [#3925](https://github.com/reactive/data-client/pull/3925) [`6e8e499`](https://github.com/reactive/data-client/commit/6e8e499441741b58ad35127b517e8d83fc7a58fd) - Fix cached journey being mutated on repeated result-cache hits. `GlobalCache.getResults` called `paths.shift()` on a cache hit, mutating the `journey` array stored by reference on the `WeakDependencyMap` `Link` node. After the first hit stripped the placeholder input slot, every subsequent hit on the same cached entry would shift off a real `EntityPath`, progressively losing subscription entries. This could cause missed `countRef` tracking (premature GC of still-referenced entities) and incorrect `entityExpiresAt` calculations. The hit path now returns a non-mutating copy. - Updated dependencies [[`959465a`](https://github.com/reactive/data-client/commit/959465a064db687176e483932987b083f19718eb), [`84078d7`](https://github.com/reactive/data-client/commit/84078d7d36bf5cf0fd16a479ce16c48c5d804f32), [`6e8e499`](https://github.com/reactive/data-client/commit/6e8e499441741b58ad35127b517e8d83fc7a58fd), [`396d163`](https://github.com/reactive/data-client/commit/396d163e6f4991818519ec33d903a85437483dfd), [`84078d7`](https://github.com/reactive/data-client/commit/84078d7d36bf5cf0fd16a479ce16c48c5d804f32)]: - @data-client/endpoint@0.18.0 ## 0.17.0 ### Minor Changes - [#3914](https://github.com/reactive/data-client/pull/3914) [`930c8ed`](https://github.com/reactive/data-client/commit/930c8ed04b6f9fcb2d131f39cc706a5eeb0edc4d) - resource() accepts [nonFilterArgumentKeys](https://dataclient.io/rest/api/Collection#nonfilterargumentkeys) ```ts const PostResource = resource({ path: '/:group/posts/:id', searchParams: {} as { orderBy?: string; author?: string }, schema: Post, nonFilterArgumentKeys: ['orderBy'], }); ``` ## 0.16.6 ### Patch Changes - [#3868](https://github.com/reactive/data-client/pull/3868) [`8a7c8d9`](https://github.com/reactive/data-client/commit/8a7c8d9cc4228a6281849f56121699f237af4b0f) - Add `content` property to RestEndpoint for typed response parsing Set `content` to control how the response body is parsed, with automatic return type inference: ```ts const downloadFile = new RestEndpoint({ path: '/files/:id/download', content: 'blob', dataExpiryLength: 0, }); const blob: Blob = await ctrl.fetch(downloadFile, { id: '123' }); ``` Accepted values: `'json'`, `'blob'`, `'text'`, `'arrayBuffer'`, `'stream'`. Non-JSON content types (`'blob'`, `'text'`, `'arrayBuffer'`, `'stream'`) constrain `schema` to `undefined` at the type level, with a runtime check that throws if a normalizable schema is set. When `content` is not set, auto-detection now handles binary Content-Types (`image/*`, `application/octet-stream`, `application/pdf`, etc.) by returning `response.blob()` instead of corrupting data via `.text()`. - [#3904](https://github.com/reactive/data-client/pull/3904) [`8af3d5e`](https://github.com/reactive/data-client/commit/8af3d5ee3dbbb637805e99cbd01801d3587bedbd) - Export `CollectionOptions` from the public `@data-client/endpoint` and `@data-client/rest` entrypoints. - [#3910](https://github.com/reactive/data-client/pull/3910) [`81c63a0`](https://github.com/reactive/data-client/commit/81c63a00c668d805b6b8d0d9efdf2aacb5d32253) - Fix [Collection](https://dataclient.io/rest/api/Collection) extender body types to match their HTTP method semantics PATCH extenders (`.move`, `.remove`) now type their body as `Partial`, matching [`partialUpdate`](https://dataclient.io/rest/api/resource#partialupdate). Previously they required the full body type even though they are PATCH endpoints. Standalone `RestEndpoint` without an explicit `body` option now derives a typed body from the Collection's entity schema instead of falling back to `any`. ```ts const MyResource = resource({ path: '/articles/:id', schema: Article, body: {} as { title: string; content: string }, }); // move (PATCH) now accepts partial body MyResource.getList.move({ id: '1' }, { title: 'new title' }); // push (POST) still requires full body MyResource.getList.push({ title: 'hi', content: 'there' }); ``` - Updated dependencies [[`8af3d5e`](https://github.com/reactive/data-client/commit/8af3d5ee3dbbb637805e99cbd01801d3587bedbd)]: - @data-client/endpoint@0.16.6 ## 0.16.5 ### Patch Changes - [#3866](https://github.com/reactive/data-client/pull/3866) [`16f5d92`](https://github.com/reactive/data-client/commit/16f5d92598de05e92b88af98a9d63eecf27ab819) - Bundle `path-to-regexp` as tree-shaken ESM Bundle only the functions we use (`compile`, `parse`, `pathToRegexp`) from `path-to-regexp` into the ESM/browser build via rollup. This eliminates the CJS/ESM boundary that broke StackBlitz WebContainers and reduces bundle size by tree-shaking unused exports (`match`, `stringify`, and the `ID` regex). ## 0.16.4 ### Patch Changes - [#3862](https://github.com/reactive/data-client/pull/3862) [`a214720`](https://github.com/reactive/data-client/commit/a214720fd12e1360d00e194b389aa82aff6b91fd) - Fix StackBlitz WebContainers compatibility with path-to-regexp Use namespace import (`import *`) instead of named imports for the CJS `path-to-regexp` dependency. Named imports trigger webpack's per-export presence validation, which fails in StackBlitz's WebContainers environment. Namespace imports defer property access to runtime, bypassing the check with no tree-shaking loss. ## 0.16.3 ### Patch Changes - [#3858](https://github.com/reactive/data-client/pull/3858) [`c83a81d`](https://github.com/reactive/data-client/commit/c83a81d4183b4b0f7c3a41f5b49fdba890406a6b) - Fix `maxEntityDepth` missing from Entity types on TypeScript 4.0 `maxEntityDepth` was not included in the TS 4.0 legacy type definitions, so TypeScript 4.0 users could not set or reference this property on Entity classes. - [#3860](https://github.com/reactive/data-client/pull/3860) [`886f2cf`](https://github.com/reactive/data-client/commit/886f2cf9032d5bb929b4bab63d61dc34398ca539) - Fix compatibility with StackBlitz WebContainers Consolidate `path-to-regexp` imports into a single module to avoid CJS/ESM interop failures in StackBlitz's WebContainers environment, where webpack could not resolve the `pathToRegexp` named export from the CJS `path-to-regexp` package. Also caches `pathToRegexp()` results, improving repeated `testKey()` performance. - Updated dependencies [[`c83a81d`](https://github.com/reactive/data-client/commit/c83a81d4183b4b0f7c3a41f5b49fdba890406a6b)]: - @data-client/endpoint@0.16.3 ## 0.16.2 ### Patch Changes - [#3847](https://github.com/reactive/data-client/pull/3847) [`e93e820`](https://github.com/reactive/data-client/commit/e93e820a112683badd4020c7c04c2284a0f6d8bf) - Fix TypeScript for `RestEndpoint` subclasses when the path is inferred as `string` If you extend `RestEndpoint` with a generic such as `O extends RestGenerics = any`, TypeScript can widen a path literal to `string`. Constructor callbacks like `getOptimisticResponse`, `key`, `url`, and `process` could then get the wrong parameter types (or unusable unions), even though calling the endpoint still worked at runtime. The same problem could show up when you set `searchParams: undefined` explicitly next to a `body` and a widened path. Both cases now type-check as you would expect. ```typescript import { Entity } from '@data-client/endpoint'; import { RestEndpoint, RestGenerics } from '@data-client/rest'; class Item extends Entity { readonly id = ''; } class AppRestEndpoint<O extends RestGenerics = any> extends RestEndpoint<O> {} new AppRestEndpoint({ path: '/items' as string, schema: Item, body: {} as { name: string }, getOptimisticResponse(_snap, body) { body.name; return body; }, }); new AppRestEndpoint({ path: '/search' as string, searchParams: undefined, schema: Item, body: {} as { q: string }, getOptimisticResponse(_snap, body) { body.q; return body; }, }); ``` ## 0.16.1 ### Patch Changes - [#3845](https://github.com/reactive/data-client/pull/3845) [`14095fe`](https://github.com/reactive/data-client/commit/14095fe768625cf11ce3d80d3493571029cf5b67) - Fix type errors when using concrete body types with subclassed RestEndpoint Subclassing RestEndpoint (the standard pattern for adding auth headers, custom serialization, etc.) could produce type errors when specifying concrete body types. ```ts // Before: type error on body ❌ class AuthdEndpoint<O extends RestGenerics = any> extends RestEndpoint<O> {} new AuthdEndpoint({ method: 'PUT', path: '/users/:id', body: {} as { username: string; email: string }, }); // After: works correctly ✓ ``` ## 0.16.0 ### Minor Changes - [#3829](https://github.com/reactive/data-client/pull/3829) [`63633c7`](https://github.com/reactive/data-client/commit/63633c714b5c041e04891255683e5a899c3d3f22) - Add [schema.Lazy](https://dataclient.io/rest/api/Lazy) for deferred relationship denormalization. `schema.Lazy` wraps a relationship field so denormalization returns raw primary keys instead of resolved entities. Use `.query` with [useQuery](/docs/api/useQuery) to resolve on demand in a separate memo/GC scope. New exports: `schema.Lazy`, `Lazy` ```ts class Department extends Entity { buildings: string[] = []; static schema = { buildings: new schema.Lazy([Building]), }; } // dept.buildings = ['bldg-1', 'bldg-2'] (raw PKs) const buildings = useQuery(Department.schema.buildings.query, dept.buildings); ``` - [#3783](https://github.com/reactive/data-client/pull/3783) [`1f34136`](https://github.com/reactive/data-client/commit/1f34136f1d0902ee5456089f2d2f9f35c9f4a758) - Add `Collection.moveWith()` for custom move schemas Analogous to [`addWith()`](https://dataclient.io/rest/api/Collection#addWith), `moveWith()` constructs a custom move schema that controls how entities are added to their destination collection. The remove behavior is automatically derived from the collection type (Array or Values). New exports: `unshift` merge function for convenience. ```ts import { Collection, unshift } from '@data-client/rest'; class MyCollection extends Collection { constructor(schema, options) { super(schema, options); this.move = this.moveWith(unshift); } } ``` - [#3757](https://github.com/reactive/data-client/pull/3757) [`02555a2`](https://github.com/reactive/data-client/commit/02555a23ef11c0a6c829d795067b634c0594fe14) - RestEndpoint.path and Resource.path syntax updated Upgrading path-to-regexp from 6 to 8. - https://github.com/pillarjs/path-to-regexp/releases/tag/v8.0.0 - https://github.com/pillarjs/path-to-regexp/releases/tag/v7.0.0 BREAKING CHANGES: - /:optional? -> {/:optional} - /:repeating+ -> /\*repeating (typed as string[]) - /:repeating* -> {/*repeating} (typed as string[]) - /:id(\d+) -> /:id (custom regex removed) - /:with-dash -> /:"with-dash" - `(`, `)`, `[`, `]`, `+`, `?`, `!` must be escaped `"\\("` - `{}()[]+?!:*\` are all characters that need escaping Migrate using: `npx skills add https://github.com/reactive/data-client --skill path-to-regexp-v8-migration` ### Patch Changes - [#3782](https://github.com/reactive/data-client/pull/3782) [`3b85c82`](https://github.com/reactive/data-client/commit/3b85c820f8046a056d9180ff5d2fe1a883b6998c) - Fix `searchParams: undefined` being widened to `any` in TypeScript 6 non-strict mode TypeScript 6.0 widens `undefined` to `any` during generic inference when `strictNullChecks` is off. This caused `RestEndpoint` with `searchParams: undefined` to incorrectly accept arbitrary arguments. - [#3757](https://github.com/reactive/data-client/pull/3757) [`02555a2`](https://github.com/reactive/data-client/commit/02555a23ef11c0a6c829d795067b634c0594fe14) - Fix `undefined` optional path params being interpolated as literal `"undefined"` in URLs - Updated dependencies [[`63633c7`](https://github.com/reactive/data-client/commit/63633c714b5c041e04891255683e5a899c3d3f22), [`1f34136`](https://github.com/reactive/data-client/commit/1f34136f1d0902ee5456089f2d2f9f35c9f4a758), [`869f28f`](https://github.com/reactive/data-client/commit/869f28fc651ca5e8b0f935089fc0b8d8ce8585cb)]: - @data-client/endpoint@0.16.0 ## 0.15.7 ### Patch Changes - [#3738](https://github.com/reactive/data-client/pull/3738) [`4425a37`](https://github.com/reactive/data-client/commit/4425a371484d3eaed66240ea8c9c1c8874e220f1) - Add `Collection.move` schema and `RestEndpoint.move` extender for moving entities between collections. `move` removes from collections matching the entity's existing state and adds to collections matching the new values (from the body/last arg). Works for both Array and Values collections. Path parameters filter collections by URL segments: ```ts const UserResource = resource({ path: '/groups/:group/users/:id', schema: User, }); // PATCH /groups/five/users/2 - moves user 2 from 'five' group to 'ten' group await ctrl.fetch( UserResource.getList.move, { group: 'five', id: '2' }, { id: '2', group: 'ten' }, ); ``` Search parameters filter collections by query args: ```ts const TaskResource = resource({ path: '/tasks/:id', searchParams: {} as { status: string }, schema: Task, }); // PATCH /tasks/3 - moves task 3 from 'backlog' to 'in-progress' await ctrl.fetch( TaskResource.getList.move, { id: '3' }, { id: '3', status: 'in-progress' }, ); ``` - [#3739](https://github.com/reactive/data-client/pull/3739) [`b301d4c`](https://github.com/reactive/data-client/commit/b301d4c65cd720cfe321b02162550ba758f47192) Thanks [@Dark-Brain07](https://github.com/Dark-Brain07)! - Add `toJSON()` to `NetworkError` for structured serialization in devtools and logging - Updated dependencies [[`4425a37`](https://github.com/reactive/data-client/commit/4425a371484d3eaed66240ea8c9c1c8874e220f1)]: - @data-client/endpoint@0.15.7 ## 0.15.6 ### Patch Changes - [#3726](https://github.com/reactive/data-client/pull/3726) [`9d94eb4`](https://github.com/reactive/data-client/commit/9d94eb46f9fd4513747ae3154298fa3b1d7487e9) - Fix `sideEffect: false` type being lost with `method: 'POST'` `sideEffect` set explicitly now always takes priority over `method` inference, including through `.extend()` chains. Previously `sideEffect: false` resolved to `never`, losing type information. ```ts // Before: sideEffect typed as `never` ❌ const ep = new RestEndpoint({ method: 'POST', sideEffect: false, ... }); // After: sideEffect typed as `false` ✓ const ep = new RestEndpoint({ method: 'POST', sideEffect: false, ... }); ``` ## 0.15.5 ### Patch Changes - [`e571bda`](https://github.com/reactive/data-client/commit/e571bdabd136fddee7aa414c91a775c5f66ce094) Thanks [@ntucker](https://github.com/ntucker)! - Add direct exports for schema classes from `@data-client/endpoint` Schema classes (`Union`, `Invalidate`, `Collection`, `Query`, `Values`, `All`) can now be imported directly instead of requiring the `schema` namespace. #### Before ```ts import { schema } from '@data-client/endpoint'; const myUnion = new schema.Union({ users: User, groups: Group }, 'type'); ``` #### After ```ts import { Union } from '@data-client/endpoint'; const myUnion = new Union({ users: User, groups: Group }, 'type'); ``` The `schema` namespace export remains available for backward compatibility. - Updated dependencies [[`e571bda`](https://github.com/reactive/data-client/commit/e571bdabd136fddee7aa414c91a775c5f66ce094)]: - @data-client/endpoint@0.15.5 ## 0.15.4 ### Patch Changes - [#3703](https://github.com/reactive/data-client/pull/3703) [`4fe8779`](https://github.com/reactive/data-client/commit/4fe8779706cb14d9018b3375d07b486a758ccb57) Thanks [@ntucker](https://github.com/ntucker)! - Improve normalize/denormalize performance 10-15% - Replace `Object.keys().forEach()` with indexed for loops - Replace `reduce()` with spreading to direct object mutation - Cache getter results to avoid repeated property lookups - Centralize arg extraction with pre-allocated loop - Eliminate Map double-get pattern #### Microbenchmark Results | # | Optimization | Before | After | Improvement | | --- | ---------------------------- | ----------------- | ----------------- | ---------------- | | 1 | **forEach → forLoop** | 7,164 ops/sec | 7,331 ops/sec | **+2.3%** | | 2 | **reduce+spread → mutation** | 912 ops/sec | 7,468 ops/sec | **+719% (8.2x)** | | 3 | **getter repeated → cached** | 1,652,211 ops/sec | 4,426,994 ops/sec | **+168% (2.7x)** | | 4 | **slice+map → indexed** | 33,221 ops/sec | 54,701 ops/sec | **+65% (1.65x)** | | 5 | **Map double-get → single** | 23,046 ops/sec | 23,285 ops/sec | **+1%** | #### Impact Summary by Codepath | Codepath | Optimizations Applied | Expected Improvement | | ------------------------------------------ | --------------------- | -------------------- | | **normalize** (setResponse) | 1, 2, 4 | 10-15% | | **denormalize** (getResponse) | 1, 2, 4 | 10-15% | | **Controller queries** (get, getQueryMeta) | 5, 6 | 5-10% | - Updated dependencies [[`4fe8779`](https://github.com/reactive/data-client/commit/4fe8779706cb14d9018b3375d07b486a758ccb57)]: - @data-client/endpoint@0.15.4 ## 0.15.2 ### Patch Changes - [`243219c`](https://github.com/reactive/data-client/commit/243219ccc1acc8ffcbfe54e8cc4a9027819eb66a) Thanks [@ntucker](https://github.com/ntucker)! - Patch bump due to publishing mishap - Updated dependencies [[`243219c`](https://github.com/reactive/data-client/commit/243219ccc1acc8ffcbfe54e8cc4a9027819eb66a)]: - @data-client/endpoint@0.15.2 ## 0.15.0 ### Minor Changes - [#3685](https://github.com/reactive/data-client/pull/3685) [`56d575e`](https://github.com/reactive/data-client/commit/56d575e0219d5455df74321aee7bf85c2d490a61) Thanks [@ntucker](https://github.com/ntucker)! - Add [Union](https://dataclient.io/rest/api/Union) support to [schema.Invalidate](https://dataclient.io/rest/api/Invalidate) and [resource().delete](https://dataclient.io/rest/api/resource#delete) for polymorphic delete operations. [resource()](https://dataclient.io/rest/api/resource) with Union schema now automatically wraps the delete endpoint schema in Invalidate: ```ts const FeedResource = resource({ path: '/feed/:id', schema: FeedUnion, // Union of Post, Comment, etc. }); // FeedResource.delete automatically uses Invalidate(FeedUnion) await ctrl.fetch(FeedResource.delete, { id: '123' }); ``` For standalone endpoints, use `schema.Invalidate` directly: ```ts new schema.Invalidate(MyUnionSchema); ``` - [#3461](https://github.com/reactive/data-client/pull/3461) [`939a4b0`](https://github.com/reactive/data-client/commit/939a4b01127ea1df9b4653931593487e4b0c23a2) Thanks [@ntucker](https://github.com/ntucker)! - Add delegate.INVALID to queryKey This is used in schema.All.queryKey(). #### Before ```ts queryKey(args: any, unvisit: any, delegate: IQueryDelegate): any { if (!found) return INVALID; } ``` #### After ```ts queryKey(args: any, unvisit: any, delegate: IQueryDelegate): any { if (!found) return delegate.INVALID; } ``` - [#3461](https://github.com/reactive/data-client/pull/3461) [`939a4b0`](https://github.com/reactive/data-client/commit/939a4b01127ea1df9b4653931593487e4b0c23a2) Thanks [@ntucker](https://github.com/ntucker)! - Add delegate.invalidate() to normalization #### Before ```ts normalize( input: any, parent: any, key: string | undefined, args: any[], visit: (...args: any) => any, delegate: INormalizeDelegate, ): string { delegate.setEntity(this as any, pk, INVALID); } ``` #### After ```ts normalize( input: any, parent: any, key: string | undefined, args: any[], visit: (...args: any) => any, delegate: INormalizeDelegate, ): string { delegate.invalidate(this as any, pk); } ``` - [#3449](https://github.com/reactive/data-client/pull/3449) [`1f491a9`](https://github.com/reactive/data-client/commit/1f491a9e0082dca64ad042aaf7d377e17f459ae7) Thanks [@ntucker](https://github.com/ntucker)! - BREAKING CHANGE: schema.normalize(...args, addEntity, getEntity, checkLoop) -> schema.normalize(...args, delegate) We consolidate all 'callback' functions during recursion calls into a single 'delegate' argument. ```ts /** Helpers during schema.normalize() */ export interface INormalizeDelegate { /** Action meta-data for this normalize call */ readonly meta: { fetchedAt: number; date: number; expiresAt: number }; /** Gets any previously normalized entity from store */ getEntity: GetEntity; /** Updates an entity using merge lifecycles when it has previously been set */ mergeEntity( schema: Mergeable & { indexes?: any }, pk: string, incomingEntity: any, ): void; /** Sets an entity overwriting any previously set values */ setEntity( schema: { key: string; indexes?: any }, pk: string, entity: any, meta?: { fetchedAt: number; date: number; expiresAt: number }, ): void; /** Returns true when we're in a cycle, so we should not continue recursing */ checkLoop(key: string, pk: string, input: object): boolean; } ``` #### Before ```ts addEntity(this, processedEntity, id); ``` #### After ```ts delegate.mergeEntity(this, id, processedEntity); ``` - [#3461](https://github.com/reactive/data-client/pull/3461) [`939a4b0`](https://github.com/reactive/data-client/commit/939a4b01127ea1df9b4653931593487e4b0c23a2) Thanks [@ntucker](https://github.com/ntucker)! - Remove `INVALID` symbol export Schemas can use delegate.invalidate() in normalize() or return delegate.INVALID in queryKey(). - [#3449](https://github.com/reactive/data-client/pull/3449) [`1f491a9`](https://github.com/reactive/data-client/commit/1f491a9e0082dca64ad042aaf7d377e17f459ae7) Thanks [@ntucker](https://github.com/ntucker)! - BREAKING CHANGE: schema.queryKey(args, queryKey, getEntity, getIndex) -> schema.queryKey(args, unvisit, delegate) BREAKING CHANGE: delegate.getIndex() returns the index directly, rather than object. We consolidate all 'callback' functions during recursion calls into a single 'delegate' argument. Our recursive call is renamed from queryKey to unvisit, and does not require the last two arguments. ```ts /** Accessors to the currently processing state while building query */ export interface IQueryDelegate { getEntity: GetEntity; getIndex: GetIndex; } ``` #### Before ```ts queryKey(args, queryKey, getEntity, getIndex) { getIndex(schema.key, indexName, value)[value]; getEntity(this.key, id); return queryKey(this.schema, args, getEntity, getIndex); } ``` #### After ```ts queryKey(args, unvisit, delegate) { delegate.getIndex(schema.key, indexName, value); delegate.getEntity(this.key, id); return unvisit(this.schema, args); } ``` ### Patch Changes - [#3449](https://github.com/reactive/data-client/pull/3449) [`1f491a9`](https://github.com/reactive/data-client/commit/1f491a9e0082dca64ad042aaf7d377e17f459ae7) Thanks [@ntucker](https://github.com/ntucker)! - Fix: ensure string id in Entity set when process returns undefined (meaning INVALID) - [`e2fff91`](https://github.com/reactive/data-client/commit/e2fff911e21864620dba8d9470142af9130aafed) Thanks [@ntucker](https://github.com/ntucker)! - fix: Collection.remove with Unions - [#3635](https://github.com/reactive/data-client/pull/3635) [`63ee107`](https://github.com/reactive/data-client/commit/63ee107be9d559e6ccbcb2f9c6fd7bf83165e551) Thanks [@ntucker](https://github.com/ntucker)! - Fix `getPage` types when paginationField is in body ```ts const ep = new RestEndpoint({ path: '/rpc', method: 'POST', body: {} as { page?: number; method: string }, paginationField: 'page', }); // Before: ep.getPage({ page: 2 }, { method: 'get' }) ❌ // After: ep.getPage({ page: 2, method: 'get' }) ✓ ``` - [#3684](https://github.com/reactive/data-client/pull/3684) [`53de2ee`](https://github.com/reactive/data-client/commit/53de2eefb891a4783e3f1c7724dc25dc9e6a8e1f) Thanks [@ntucker](https://github.com/ntucker)! - Optimize normalization performance with faster loops and Set-based cycle detection - [#3560](https://github.com/reactive/data-client/pull/3560) [`ba31c9b`](https://github.com/reactive/data-client/commit/ba31c9b2d3c4ec5620bb64e49daf9b18994b9290) Thanks [@ntucker](https://github.com/ntucker)! - Add Collection.remove ```ts ctrl.set(MyResource.getList.schema.remove, { id }); ``` ```ts const removeItem = MyResource.delete.extend({ schema: MyResource.getList.schema.remove, }); ``` - [#3558](https://github.com/reactive/data-client/pull/3558) [`fcb7d7d`](https://github.com/reactive/data-client/commit/fcb7d7db8061c2a7e12632071ecb9c6ddd8d154f) Thanks [@ntucker](https://github.com/ntucker)! - Normalize delegate.invalidate() first argument only has `key` param. `indexes` optional param no longer provided as it was never used. ```ts normalize( input: any, parent: any, key: string | undefined, args: any[], visit: (...args: any) => any, delegate: INormalizeDelegate, ): string { delegate.invalidate({ key: this._entity.key }, pk); return pk; } ``` - [#3623](https://github.com/reactive/data-client/pull/3623) [`8be3b17`](https://github.com/reactive/data-client/commit/8be3b1725707c4bcbf0fdd6e72ddd78d85fd125f) Thanks [@ntucker](https://github.com/ntucker)! - Add RestEndpoint.remove Creates a PATCH endpoint that both removes an entity from a Collection and updates the entity with the provided body data. ```ts const getTodos = new RestEndpoint({ path: '/todos', schema: new schema.Collection([Todo]), }); // Removes Todo from collection AND updates it with new data await ctrl.fetch( getTodos.remove, {}, { id: '123', title: 'Done', completed: true }, ); ``` ```ts // Remove user from group list and update their group await ctrl.fetch( UserResource.getList.remove, { group: 'five' }, { id: 2, username: 'user2', group: 'newgroup' }, ); // User is removed from the 'five' group list // AND the user entity is updated with group: 'newgroup' ``` - [#3558](https://github.com/reactive/data-client/pull/3558) [`fcb7d7d`](https://github.com/reactive/data-client/commit/fcb7d7db8061c2a7e12632071ecb9c6ddd8d154f) Thanks [@ntucker](https://github.com/ntucker)! - Unions can query() without type discriminator #### Before ```tsx // @ts-expect-error const event = useQuery(EventUnion, { id }); // event is undefined const newsEvent = useQuery(EventUnion, { id, type: 'news' }); // newsEvent is found ``` #### After ```tsx const event = useQuery(EventUnion, { id }); // event is found const newsEvent = useQuery(EventUnion, { id, type: 'news' }); // newsEvent is found ``` - [`35552c7`](https://github.com/reactive/data-client/commit/35552c716e3b688d69212654f9f95a05ea26a7f8) Thanks [@ntucker](https://github.com/ntucker)! - Include GPT link badge in readme - Updated dependencies [[`1f491a9`](https://github.com/reactive/data-client/commit/1f491a9e0082dca64ad042aaf7d377e17f459ae7), [`56d575e`](https://github.com/reactive/data-client/commit/56d575e0219d5455df74321aee7bf85c2d490a61), [`e2fff91`](https://github.com/reactive/data-client/commit/e2fff911e21864620dba8d9470142af9130aafed), [`939a4b0`](https://github.com/reactive/data-client/commit/939a4b01127ea1df9b4653931593487e4b0c23a2), [`939a4b0`](https://github.com/reactive/data-client/commit/939a4b01127ea1df9b4653931593487e4b0c23a2), [`53de2ee`](https://github.com/reactive/data-client/commit/53de2eefb891a4783e3f1c7724dc25dc9e6a8e1f), [`ba31c9b`](https://github.com/reactive/data-client/commit/ba31c9b2d3c4ec5620bb64e49daf9b18994b9290), [`fcb7d7d`](https://github.com/reactive/data-client/commit/fcb7d7db8061c2a7e12632071ecb9c6ddd8d154f), [`1f491a9`](https://github.com/reactive/data-client/commit/1f491a9e0082dca64ad042aaf7d377e17f459ae7), [`4dde1d6`](https://github.com/reactive/data-client/commit/4dde1d616e38d59b645573b12bbaba2f9cac7895), [`bab907c`](https://github.com/reactive/data-client/commit/bab907ce824c0f7da961d74c9fb8b64ce7c95141), [`5699005`](https://github.com/reactive/data-client/commit/5699005700206306bc70ff8237bf7ceaac241b82), [`939a4b0`](https://github.com/reactive/data-client/commit/939a4b01127ea1df9b4653931593487e4b0c23a2), [`fcb7d7d`](https://github.com/reactive/data-client/commit/fcb7d7db8061c2a7e12632071ecb9c6ddd8d154f), [`1f491a9`](https://github.com/reactive/data-client/commit/1f491a9e0082dca64ad042aaf7d377e17f459ae7), [`35552c7`](https://github.com/reactive/data-client/commit/35552c716e3b688d69212654f9f95a05ea26a7f8)]: - @data-client/endpoint@0.15.0 ## 0.14.25 ### Patch Changes - [#3417](https://github.com/reactive/data-client/pull/3417) [`a6af54c`](https://github.com/reactive/data-client/commit/a6af54c1bc2193de47c96938df74b243cb82bfe6) Thanks [@ntucker](https://github.com/ntucker)! - Update getOptimisticResponse snapshot types to include getResponseMeta - [#3407](https://github.com/reactive/data-client/pull/3407) [`d84899d`](https://github.com/reactive/data-client/commit/d84899de4fb784375ab7a34fff6fe23a2ed98037) Thanks [@ntucker](https://github.com/ntucker)! - Support dynamic invalidation/deletes Returning `undefined` from [Entity.process](https://dataclient.io/rest/api/Entity#process) will cause the [Entity](https://dataclient.io/rest/api/Entity) to be [invalidated](https://dataclient.io/docs/concepts/expiry-policy#invalidate-entity). This this allows us to invalidate dynamically; based on the particular response data. ```ts class PriceLevel extends Entity { price = 0; amount = 0; pk() { return this.price; } static process( input: [number, number], parent: any, key: string | undefined, ): any { const [price, amount] = input; if (amount === 0) return undefined; return { price, amount }; } } ``` - Updated dependencies [[`a6af54c`](https://github.com/reactive/data-client/commit/a6af54c1bc2193de47c96938df74b243cb82bfe6), [`d84899d`](https://github.com/reactive/data-client/commit/d84899de4fb784375ab7a34fff6fe23a2ed98037)]: - @data-client/endpoint@0.14.25 ## 0.14.22 ### Patch Changes - [#3390](https://github.com/reactive/data-client/pull/3390) [`32cccdb`](https://github.com/reactive/data-client/commit/32cccdb921cd8d7643b641a9e8872aa89782a94a) Thanks [@ntucker](https://github.com/ntucker)! - Improve performance by using Map() instead of Object for unbounded keys ## 0.14.21 ### Patch Changes - [#3384](https://github.com/reactive/data-client/pull/3384) [`24ad679`](https://github.com/reactive/data-client/commit/24ad679f58c7eb0d0e6917790b4ebb5ee234e1d3) Thanks [@ntucker](https://github.com/ntucker)! - Reduce bundle sizes by 30% by removing unneeded polyfills - Updated dependencies [[`24ad679`](https://github.com/reactive/data-client/commit/24ad679f58c7eb0d0e6917790b4ebb5ee234e1d3)]: - @data-client/endpoint@0.14.21 ## 0.14.20 ### Patch Changes - [`c3514c6`](https://github.com/reactive/data-client/commit/c3514c6afa2cd76dafa02adcfad6f6481a34b5de) Thanks [@ntucker](https://github.com/ntucker)! - Remove unnecessary polyfills in build - Updated dependencies [[`c3514c6`](https://github.com/reactive/data-client/commit/c3514c6afa2cd76dafa02adcfad6f6481a34b5de)]: - @data-client/endpoint@0.14.20 ## 0.14.19 ### Patch Changes - [`cb4fb92`](https://github.com/reactive/data-client/commit/cb4fb922e305502ba8ab99c99b6012e753a87a3a) Thanks [@ntucker](https://github.com/ntucker)! - Remove typing redundancy - [#3371](https://github.com/reactive/data-client/pull/3371) [`679d76a`](https://github.com/reactive/data-client/commit/679d76a36234dcf5993c0358f94d7e1db0505cc6) Thanks [@ntucker](https://github.com/ntucker)! - Add react-native entry to package.json exports - [#3353](https://github.com/reactive/data-client/pull/3353) [`165afed`](https://github.com/reactive/data-client/commit/165afed083c0c63e9356bc8d1ee30dee8b916ed6) Thanks [@renovate](https://github.com/apps/renovate)! - Polyfills no longer pollute global scope - Updated dependencies [[`cb4fb92`](https://github.com/reactive/data-client/commit/cb4fb922e305502ba8ab99c99b6012e753a87a3a), [`679d76a`](https://github.com/reactive/data-client/commit/679d76a36234dcf5993c0358f94d7e1db0505cc6), [`165afed`](https://github.com/reactive/data-client/commit/165afed083c0c63e9356bc8d1ee30dee8b916ed6)]: - @data-client/endpoint@0.14.19 ## 0.14.18 ### Patch Changes - [#3333](https://github.com/reactive/data-client/pull/3333) [`1777546`](https://github.com/reactive/data-client/commit/17775462d236bf714f518b861a63d5ae9f1f6357) Thanks [@renovate](https://github.com/apps/renovate)! - Resource.extend() compatibility with TypeScript 5 Previously [extending existing members](https://dataclient.io/rest/api/resource#extend-override) with no typed overrides (like [path](https://dataclient.io/rest/api/resource#path)) would not work starting with TypeScript 5.7. ```ts const UserResource = UserResourceBase.extend({ partialUpdate: { getOptimisticResponse(snap, params, body) { params.id; params.group; // @ts-expect-error params.nothere; return { id: params.id, ...body, }; }, }, }); ``` ## 0.14.17 ### Patch Changes - [#3281](https://github.com/reactive/data-client/pull/3281) [`99cd041`](https://github.com/reactive/data-client/commit/99cd04152532e13d8fb092ea800d381391d5aacd) Thanks [@ntucker](https://github.com/ntucker)! - Collections work with nested args This fixes [integration with qs library](https://dataclient.io/rest/api/RestEndpoint#using-qs-library) and more complex search parameters. - [`25be07f`](https://github.com/reactive/data-client/commit/25be07f51c501003330d758993542bee3bd804e1) Thanks [@ntucker](https://github.com/ntucker)! - Update README to not say 'mixin' twice - Updated dependencies [[`99cd041`](https://github.com/reactive/data-client/commit/99cd04152532e13d8fb092ea800d381391d5aacd)]: - @data-client/endpoint@0.14.17 ## 0.14.16 ### Patch Changes - [`4580e62`](https://github.com/reactive/data-client/commit/4580e628764ab43de3e4607f8584bc6cb4173021) Thanks [@ntucker](https://github.com/ntucker)! - Update docstring for EntityMixin - [#3243](https://github.com/reactive/data-client/pull/3243) [`43a955c`](https://github.com/reactive/data-client/commit/43a955c18684b4e0f5c1d79b2504e8ad2910816b) Thanks [@ntucker](https://github.com/ntucker)! - `schema.Entity` -> [EntityMixin](https://dataclient.io/rest/api/EntityMixin) ```ts import { EntityMixin } from '@data-client/rest'; export class Article { id = ''; title = ''; content = ''; tags: string[] = []; } export class ArticleEntity extends EntityMixin(Article) {} ``` We keep `schema.Entity` for legacy, and add schema.EntityMixin and [EntityMixin](https://dataclient.io/rest/api/EntityMixin) as direct export - Updated dependencies [[`4580e62`](https://github.com/reactive/data-client/commit/4580e628764ab43de3e4607f8584bc6cb4173021), [`1f7b191`](https://github.com/reactive/data-client/commit/1f7b1913e9301230d9fdae23baba9e3c582e005c), [`43a955c`](https://github.com/reactive/data-client/commit/43a955c18684b4e0f5c1d79b2504e8ad2910816b)]: - @data-client/endpoint@0.14.16 ## 0.14.13 ### Patch Changes - [#3215](https://github.com/reactive/data-client/pull/3215) [`e74f7dc`](https://github.com/reactive/data-client/commit/e74f7dc0750fdf32e455bf2c36eff119afba6476) Thanks [@renovate](https://github.com/apps/renovate)! - Update path-to-regexp for [CVE-2024-45296](https://redirect.github.com/pillarjs/path-to-regexp/security/advisories/GHSA-9wv6-86v2-598j) ## 0.14.12 ### Patch Changes - [`2b10a49`](https://github.com/reactive/data-client/commit/2b10a4997093570b96533ef7b99c89be722a6fa7) Thanks [@ntucker](https://github.com/ntucker)! - Add ResourceInterface export - [`3b337e7`](https://github.com/reactive/data-client/commit/3b337e74e3f22f2fe48f6eb37084bbf58859bbe1) Thanks [@ntucker](https://github.com/ntucker)! - Add schema table to README - [`11d4ccf`](https://github.com/reactive/data-client/commit/11d4ccfb4c630c25b847bf59ca1028eed8c2369e) Thanks [@ntucker](https://github.com/ntucker)! - Fix: Collection adders (push/unshift) should _not_ be Queryable - Updated dependencies [[`3b337e7`](https://github.com/reactive/data-client/commit/3b337e74e3f22f2fe48f6eb37084bbf58859bbe1), [`11d4ccf`](https://github.com/reactive/data-client/commit/11d4ccfb4c630c25b847bf59ca1028eed8c2369e)]: - @data-client/endpoint@0.14.12 ## 0.14.11 ### Patch Changes - [`87a65ba`](https://github.com/reactive/data-client/commit/87a65ba8b5f266a299ac3d9c78b6605deee5f4e2) Thanks [@ntucker](https://github.com/ntucker)! - Fix Entity types for TS 4.0 and below - [`a436050`](https://github.com/reactive/data-client/commit/a43605035d3791ad73393ce229ed85c8e8f2cb88) Thanks [@ntucker](https://github.com/ntucker)! - Fix README markup - Updated dependencies [[`87a65ba`](https://github.com/reactive/data-client/commit/87a65ba8b5f266a299ac3d9c78b6605deee5f4e2)]: - @data-client/endpoint@0.14.11 ## 0.14.10 ### Patch Changes - [#3188](https://github.com/reactive/data-client/pull/3188) [`cde7121`](https://github.com/reactive/data-client/commit/cde71212706a46bbfd13dd76e8cfc478b22fe2ab) Thanks [@ntucker](https://github.com/ntucker)! - Do not require [Entity.pk()](https://dataclient.io/rest/api/Entity#pk) Default implementation uses `this.id` - [#3188](https://github.com/reactive/data-client/pull/3188) [`cde7121`](https://github.com/reactive/data-client/commit/cde71212706a46bbfd13dd76e8cfc478b22fe2ab) Thanks [@ntucker](https://github.com/ntucker)! - Update README to remove Entity.pk() when it is default ('id') - Updated dependencies [[`cde7121`](https://github.com/reactive/data-client/commit/cde71212706a46bbfd13dd76e8cfc478b22fe2ab), [`cde7121`](https://github.com/reactive/data-client/commit/cde71212706a46bbfd13dd76e8cfc478b22fe2ab)]: - @data-client/endpoint@0.14.10 ## 0.14.9 ### Patch Changes - [`c263931`](https://github.com/reactive/data-client/commit/c26393176518550a16a2e71aea55a8379f30385e) Thanks [@ntucker](https://github.com/ntucker)! - Update README - [`366c609`](https://github.com/reactive/data-client/commit/366c609dbda9707f8ecfaef5020c67dd1c7e262b) Thanks [@ntucker](https://github.com/ntucker)! - Make NetworkError messages include more useful information Add URL so it's clear _what_ is causing issues when response is not 'ok' ## 0.14.8 ### Patch Changes - [`bad1fb9`](https://github.com/reactive/data-client/commit/bad1fb909f8d60f19450bbf40df00d90e03a61c2) Thanks [@ntucker](https://github.com/ntucker)! - Update package description ## 0.14.6 ### Patch Changes - [#3165](https://github.com/reactive/data-client/pull/3165) [`3fa9eb9`](https://github.com/reactive/data-client/commit/3fa9eb907d8760171da065168796b87e802d6666) Thanks [@ntucker](https://github.com/ntucker)! - [Query](https://dataclient.io/rest/api/Query) can take [Object Schemas](https://dataclient.io/rest/api/Object) This enables joining arbitrary objects (whose pk works with the same arguments.) ```ts class Ticker extends Entity { product_id = ''; price = 0; pk(): string { return this.product_id; } } class Stats extends Entity { product_id = ''; last = 0; pk(): string { return this.product_id; } } const queryPrice = new schema.Query( { ticker: Ticker, stats: Stats }, ({ ticker, stats }) => ticker?.price ?? stats?.last, ); ``` - Updated dependencies [[`3fa9eb9`](https://github.com/reactive/data-client/commit/3fa9eb907d8760171da065168796b87e802d6666)]: - @data-client/endpoint@0.14.6 ## 0.14.4 ### Patch Changes - [`0adad92`](https://github.com/reactive/data-client/commit/0adad9209265c388eb6d334afe681610bccfb877) Thanks [@ntucker](https://github.com/ntucker)! - Update debugging link - Updated dependencies [[`0adad92`](https://github.com/reactive/data-client/commit/0adad9209265c388eb6d334afe681610bccfb877)]: - @data-client/endpoint@0.14.4 ## 0.14.3 ### Patch Changes - [`501cb82`](https://github.com/reactive/data-client/commit/501cb82c999030fd269b40eb760ae0dda568c569) Thanks [@ntucker](https://github.com/ntucker)! - Remove name in toJSON() for Entities - [`501cb82`](https://github.com/reactive/data-client/commit/501cb82c999030fd269b40eb760ae0dda568c569) Thanks [@ntucker](https://github.com/ntucker)! - Add toString() to Collection - [`3058a8a`](https://github.com/reactive/data-client/commit/3058a8a7738eeea0a197c9ba2db2e8ee51e2fca3) Thanks [@ntucker](https://github.com/ntucker)! - Collection non-known (not Array/Values) key format improvement Now wraps in parens `()`: "(Todo)" - [#3158](https://github.com/reactive/data-client/pull/3158) [`34e2e51`](https://github.com/reactive/data-client/commit/34e2e51e89908649f1297c23a71cdafecf1d3b6f) Thanks [@ntucker](https://github.com/ntucker)! - createResource() -> [resource()](https://dataclient.io/rest/api/resource) Note: `createResource` is still exported (it is the same) - Updated dependencies [[`501cb82`](https://github.com/reactive/data-client/commit/501cb82c999030fd269b40eb760ae0dda568c569), [`501cb82`](https://github.com/reactive/data-client/commit/501cb82c999030fd269b40eb760ae0dda568c569), [`3058a8a`](https://github.com/reactive/data-client/commit/3058a8a7738eeea0a197c9ba2db2e8ee51e2fca3)]: - @data-client/endpoint@0.14.3 ## 0.14.1 ### Patch Changes - [#3151](https://github.com/reactive/data-client/pull/3151) [`428d618`](https://github.com/reactive/data-client/commit/428d618ce057d4eef23592a64ec9d1c6fb82f43f) Thanks [@ntucker](https://github.com/ntucker)! - Collection.key is shorter and more readable `[Todo]` for Arrays or `{Todo}` for Values - [#3151](https://github.com/reactive/data-client/pull/3151) [`428d618`](https://github.com/reactive/data-client/commit/428d618ce057d4eef23592a64ec9d1c6fb82f43f) Thanks [@ntucker](https://github.com/ntucker)! - fix: Collection.key robust against class name mangling - [#3151](https://github.com/reactive/data-client/pull/3151) [`428d618`](https://github.com/reactive/data-client/commit/428d618ce057d4eef23592a64ec9d1c6fb82f43f) Thanks [@ntucker](https://github.com/ntucker)! - Collections now work with polymorhpic schemas like Union Collections.key on polymorphic types lists their possible Entity keys: `[PushEvent;PullRequestEvent]` - Updated dependencies [[`428d618`](https://github.com/reactive/data-client/commit/428d618ce057d4eef23592a64ec9d1c6fb82f43f), [`428d618`](https://github.com/reactive/data-client/commit/428d618ce057d4eef23592a64ec9d1c6fb82f43f), [`428d618`](https://github.com/reactive/data-client/commit/428d618ce057d4eef23592a64ec9d1c6fb82f43f)]: - @data-client/endpoint@0.14.1 ## 0.14.0 ### Minor Changes - [#3134](https://github.com/reactive/data-client/pull/3134) [`2ad1811`](https://github.com/reactive/data-client/commit/2ad1811149cdc419f6462ace08efdb7766195b36) Thanks [@ntucker](https://github.com/ntucker)! - Change Schema.normalize `visit()` interface; removing non-contextual arguments. ```ts /** Visits next data + schema while recurisvely normalizing */ export interface Visit { (schema: any, value: any, parent: any, key: any, args: readonly any[]): any; creating?: boolean; } ``` This results in a 10% normalize performance boost. ```ts title="Before" processedEntity[key] = visit( processedEntity[key], processedEntity, key, this.schema[key], addEntity, visitedEntities, storeEntities, args, ); ``` ```ts title="After" processedEntity[key] = visit( this.schema[key], processedEntity[key], processedEntity, key, args, ); ``` The information needed from these arguments are provided by [closing](<https://en.wikipedia.org/wiki/Closure_(computer_programming)>) `visit()` around them. - [#3134](https://github.com/reactive/data-client/pull/3134) [`2ad1811`](https://github.com/reactive/data-client/commit/2ad1811149cdc419f6462ace08efdb7766195b36) Thanks [@ntucker](https://github.com/ntucker)! - Change Schema.normalize interface from direct data access,