Releases: reactive/data-client
@data-client/vue@0.2.0-beta-20251022010821-0e5f6bd2963b6deecb68b5febe71cdd3b10c801a
Minor Changes
Patch Changes
- Updated dependencies []:
@data-client/rest@0.15.0-beta-20251022010821-0e5f6bd2963b6deecb68b5febe71cdd3b10c801a
@data-client/graphql@0.15.0-beta-20251022010821-0e5f6bd2963b6deecb68b5febe71cdd3b10c801a
@data-client/endpoint@0.15.0-beta-20251022010821-0e5f6bd2963b6deecb68b5febe71cdd3b10c801a
@data-client/test@0.15.0-beta-20251006024044-92bd01c4976f2921993b8c9f1e4dbb87af87ba7b
Minor Changes
-
#3394
d44d36aThanks @ntucker! - Change NetworkManager bookkeeping data structure for inflight fetchesBREAKING CHANGE: NetworkManager.fetched, NetworkManager.rejectors, NetworkManager.resolvers, NetworkManager.fetchedAt
-> NetworkManager.fetchingBefore
if (action.key in this.fetched)
After
if (this.fetching.has(action.key))
-
769cb78Thanks @ntucker! - Support 0.15 of @data-client/react
Patch Changes
@data-client/rest@0.15.0-beta-20251006024044-92bd01c4976f2921993b8c9f1e4dbb87af87ba7b
Minor Changes
-
#3461
939a4b0Thanks @ntucker! - Add delegate.INVALID to queryKeyThis is used in schema.All.queryKey().
Before
queryKey(args: any, unvisit: any, delegate: IQueryDelegate): any { if (!found) return INVALID; }
After
queryKey(args: any, unvisit: any, delegate: IQueryDelegate): any { if (!found) return delegate.INVALID; }
-
#3461
939a4b0Thanks @ntucker! - Add delegate.invalidate() to normalizationBefore
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
normalize( input: any, parent: any, key: string | undefined, args: any[], visit: (...args: any) => any, delegate: INormalizeDelegate, ): string { delegate.invalidate(this as any, pk); }
-
#3449
1f491a9Thanks @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.
/** 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
addEntity(this, processedEntity, id);
After
delegate.mergeEntity(this, id, processedEntity);
-
#3461
939a4b0Thanks @ntucker! - RemoveINVALIDsymbol exportSchemas can use delegate.invalidate() in normalize() or return delegate.INVALID in queryKey().
-
#3449
1f491a9Thanks @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.
/** Accessors to the currently processing state while building query */ export interface IQueryDelegate { getEntity: GetEntity; getIndex: GetIndex; }
Before
queryKey(args, queryKey, getEntity, getIndex) { getIndex(schema.key, indexName, value)[value]; getEntity(this.key, id); return queryKey(this.schema, args, getEntity, getIndex); }
After
queryKey(args, unvisit, delegate) { delegate.getIndex(schema.key, indexName, value); delegate.getEntity(this.key, id); return unvisit(this.schema, args); }
Patch Changes
-
#3449
1f491a9Thanks @ntucker! - Fix: ensure string id in Entity set when process returns undefined (meaning INVALID) -
#3560
ba31c9bThanks @ntucker! - Add Collection.removectrl.set(MyResource.getList.schema.remove, { id });
const removeItem = MyResource.delete.extend({ schema: MyResource.getList.schema.remove, });
-
#3558
fcb7d7dThanks @ntucker! - Normalize delegate.invalidate() first argument only haskeyparam.indexesoptional param no longer provided as it was never used.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; }
-
#3558
fcb7d7dThanks @ntucker! - Unions can query() without type discriminatorBefore
// @ts-expect-error const event = useQuery(EventUnion, { id }); // event is undefined const newsEvent = useQuery(EventUnion, { id, type: 'news' }); // newsEvent is found
After
const event = useQuery(EventUnion, { id }); // event is found const newsEvent = useQuery(EventUnion, { id, type: 'news' }); // newsEvent is found
-
Updated dependencies [
1f491a9,939a4b0,939a4b0,ba31c9b,fcb7d7d,1f491a9,4dde1d6,bab907c,5699005,939a4b0,fcb7d7d,1f491a9,35552c7]:
@data-client/react@0.15.0-beta-20251006024044-92bd01c4976f2921993b8c9f1e4dbb87af87ba7b
Minor Changes
-
#3459
997ca20Thanks @ntucker! - BREAKING CHANGE: useDebounce() returns [val, isPending]This was previously exported in
@data-client/react/nextto make migrations easy. This will
still be available there.Before
import { useDebounce } from '@data-client/react'; const debouncedQuery = useDebounce(query, 100);
After
import { useDebounce } from '@data-client/react'; const [debouncedQuery] = useDebounce(query, 100);
Before
import { useDebounce } from '@data-client/react/next'; const [debouncedQuery, isPending] = useDebounce(query, 100);
After
import { useDebounce } from '@data-client/react'; const [debouncedQuery, isPending] = useDebounce(query, 100);
-
#3449
1f491a9Thanks @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.
/** 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
addEntity(this, processedEntity, id);
After
delegate.mergeEntity(this, id, processedEntity);
-
#3451
4939456Thanks @ntucker! - state.entityMeta -> state.entitiesMeta -
#3449
1f491a9Thanks @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.
/** Accessors to the currently processing state while building query */ export interface IQueryDelegate { getEntity: GetEntity; getIndex: GetIndex; }
Before
queryKey(args, queryKey, getEntity, getIndex) { getIndex(schema.key, indexName, value)[value]; getEntity(this.key, id); return queryKey(this.schema, args, getEntity, getIndex); }
After
queryKey(args, unvisit, delegate) { delegate.getIndex(schema.key, indexName, value); delegate.getEntity(this.key, id); return unvisit(this.schema, args); }
Patch Changes
-
#3449
1f491a9Thanks @ntucker! - Fix controller.get and controller.getQueryMeta 'state' argument types -
#3558
fcb7d7dThanks @ntucker! - Normalize delegate.invalidate() first argument only haskeyparam.indexesoptional param no longer provided as it was never used.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; }
-
#3468
4dde1d6Thanks @ntucker! - Improve performance of get/denormalize for small responses- 10-20% performance improvement due to removing immutablejs check for every call
-
Updated dependencies [
1f491a9,fcb7d7d,1f491a9,4939456,d44d36a,4dde1d6,1f491a9]:
@data-client/normalizr@0.15.0-beta-20251006024044-92bd01c4976f2921993b8c9f1e4dbb87af87ba7b
Minor Changes
-
#3421
246cde6Thanks @ntucker! - BREAKING CHANGE: Denormalize always transforms immutablejs entities into the classPreviously using ImmutableJS structures when calling denormalize() would maintain
nested schemas as immutablejs structures still. Now everything is converted to normal JS.
This is how the types have always been specified. -
#3468
4dde1d6Thanks @ntucker! - BREAKING: denormalize no longer detects ImmutableJS stateUse
/immexports to handle ImmutableJS stateBefore
import { MemoCache, denormalize } from '@data-client/normalizr'; const memo = new MemoCache();
After
import { MemoCache } from '@data-client/normalizr'; import { MemoPolicy, denormalize } from '@data-client/normalizr/imm'; const memo = new MemoCache(MemoPolicy);
-
#3461
939a4b0Thanks @ntucker! - Add delegate.INVALID to queryKeyThis is used in schema.All.queryKey().
Before
queryKey(args: any, unvisit: any, delegate: IQueryDelegate): any { if (!found) return INVALID; }
After
queryKey(args: any, unvisit: any, delegate: IQueryDelegate): any { if (!found) return delegate.INVALID; }
-
#3461
939a4b0Thanks @ntucker! - Add delegate.invalidate() to normalizationBefore
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
normalize( input: any, parent: any, key: string | undefined, args: any[], visit: (...args: any) => any, delegate: INormalizeDelegate, ): string { delegate.invalidate(this as any, pk); }
-
#3454
66e1906Thanks @ntucker! - BREAKING CHANGE: MemoCache.query() and MemoCache.buildQueryKey() take state as one argumentBefore
this.memo.buildQueryKey(schema, args, state.entities, state.indexes, key);
After
this.memo.buildQueryKey(schema, args, state, key);
Before
this.memo.query(schema, args, state.entities, state.indexes);
After
this.memo.query(schema, args, state);
-
#3449
1f491a9Thanks @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.
/** 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
addEntity(this, processedEntity, id);
After
delegate.mergeEntity(this, id, processedEntity);
-
#3468
4dde1d6Thanks @ntucker! - delegate.getEntity(key) -> delegate.getEntities(this.key)Return value is a restricted interface with keys() and entries() iterator methods.
This applies to both schema.queryKey and schema.normalize method delegates.const entities = delegate.getEntities(key); // foreach on keys for (const key of entities.keys()) { } // Object.keys() (convert to array) return [...entities.keys()]; // foreach on full entry for (const [key, entity] of entities.entries()) { }
Before
const entities = delegate.getEntity(this.key); if (entities) Object.keys(entities).forEach(collectionPk => { if (!filterCollections(JSON.parse(collectionPk))) return; delegate.mergeEntity(this, collectionPk, normalizedValue); });
After
const entities = delegate.getEntities(this.key); if (entities) for (const collectionKey of entities.keys()) { if (!filterCollections(JSON.parse(collectionKey))) continue; delegate.mergeEntity(this, collectionKey, normalizedValue); }
-
#3451
4939456Thanks @ntucker! - state.entityMeta -> state.entitiesMeta -
#3372
25b153aThanks @ntucker! - MemoCache.query returns{ data, paths }just like denormalize.datacould be INVALIDBefore
return this.memo.query(schema, args, state);
After
const { data } = this.memo.query(schema, args, state); return typeof data === 'symbol' ? undefined : (data as any);
-
#3449
1f491a9Thanks @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.
/** Accessors to the currently processing state while building query */ export interface IQueryDelegate { getEntity: GetEntity; getIndex: GetIndex; }
Before
queryKey(args, queryKey, getEntity, getIndex) { getIndex(schema.key, indexName, value)[value]; getEntity(this.key, id); return queryKey(this.schema, args, getEntity, getIndex); }
After
queryKey(args, unvisit, delegate) { delegate.getIndex(schema.key, indexName, value); delegate.getEntity(this.key, id); return unvisit(this.schema, args); }
Patch Changes
-
#3468
4dde1d6Thanks @ntucker! - Add /imm exports path for handling ImmutableJS stateMemoCache
import { MemoCache } from '@data-client/normalizr'; import { MemoPolicy } from '@data-client/normalizr/imm'; const memo = new MemoCache(MemoPolicy); // entities is an ImmutableJS Map const value = MemoCache.denormalize(Todo, '1', entities);
denormalize
non-memoized denormalize
import { denormalize } from '@data-client/normalizr/imm'; // entities is an ImmutableJS Map const value = denormalize(Todo, '1', entities);
-
#3558
fcb7d7dThanks @ntucker! - Normalize delegate.invalidate() first argument only haskeyparam.indexesoptional param no longer provided as it was never used.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; }
-
#3468
4dde1d6Thanks @ntucker! - Improve performance of ge...
@data-client/img@0.15.0-beta-20251006024044-92bd01c4976f2921993b8c9f1e4dbb87af87ba7b
@data-client/graphql@0.15.0-beta-20251006024044-92bd01c4976f2921993b8c9f1e4dbb87af87ba7b
Minor Changes
-
#3461
939a4b0Thanks @ntucker! - Add delegate.INVALID to queryKeyThis is used in schema.All.queryKey().
Before
queryKey(args: any, unvisit: any, delegate: IQueryDelegate): any { if (!found) return INVALID; }
After
queryKey(args: any, unvisit: any, delegate: IQueryDelegate): any { if (!found) return delegate.INVALID; }
-
#3461
939a4b0Thanks @ntucker! - Add delegate.invalidate() to normalizationBefore
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
normalize( input: any, parent: any, key: string | undefined, args: any[], visit: (...args: any) => any, delegate: INormalizeDelegate, ): string { delegate.invalidate(this as any, pk); }
-
#3449
1f491a9Thanks @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.
/** 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
addEntity(this, processedEntity, id);
After
delegate.mergeEntity(this, id, processedEntity);
-
#3461
939a4b0Thanks @ntucker! - RemoveINVALIDsymbol exportSchemas can use delegate.invalidate() in normalize() or return delegate.INVALID in queryKey().
-
#3449
1f491a9Thanks @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.
/** Accessors to the currently processing state while building query */ export interface IQueryDelegate { getEntity: GetEntity; getIndex: GetIndex; }
Before
queryKey(args, queryKey, getEntity, getIndex) { getIndex(schema.key, indexName, value)[value]; getEntity(this.key, id); return queryKey(this.schema, args, getEntity, getIndex); }
After
queryKey(args, unvisit, delegate) { delegate.getIndex(schema.key, indexName, value); delegate.getEntity(this.key, id); return unvisit(this.schema, args); }
Patch Changes
-
#3449
1f491a9Thanks @ntucker! - Fix: ensure string id in Entity set when process returns undefined (meaning INVALID) -
#3560
ba31c9bThanks @ntucker! - Add Collection.removectrl.set(MyResource.getList.schema.remove, { id });
const removeItem = MyResource.delete.extend({ schema: MyResource.getList.schema.remove, });
-
#3558
fcb7d7dThanks @ntucker! - Normalize delegate.invalidate() first argument only haskeyparam.indexesoptional param no longer provided as it was never used.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; }
-
#3558
fcb7d7dThanks @ntucker! - Unions can query() without type discriminatorBefore
// @ts-expect-error const event = useQuery(EventUnion, { id }); // event is undefined const newsEvent = useQuery(EventUnion, { id, type: 'news' }); // newsEvent is found
After
const event = useQuery(EventUnion, { id }); // event is found const newsEvent = useQuery(EventUnion, { id, type: 'news' }); // newsEvent is found
-
Updated dependencies [
1f491a9,939a4b0,939a4b0,ba31c9b,fcb7d7d,1f491a9,4dde1d6,bab907c,5699005,939a4b0,fcb7d7d,1f491a9,35552c7]: