diff --git a/.changeset/hip-queens-design.md b/.changeset/hip-queens-design.md new file mode 100644 index 000000000000..f76d1acbb89b --- /dev/null +++ b/.changeset/hip-queens-design.md @@ -0,0 +1,6 @@ +--- +'@data-client/core': minor +'@data-client/react': patch +--- + +action.meta.args -> action.args diff --git a/.changeset/hot-kangaroos-dream.md b/.changeset/hot-kangaroos-dream.md new file mode 100644 index 000000000000..3f4ba3b8df9e --- /dev/null +++ b/.changeset/hot-kangaroos-dream.md @@ -0,0 +1,32 @@ +--- +'@data-client/core': minor +--- + +Add `actions` export + +`actions` is a namespace for all action creators. It is typically +preferred to use [Controller's](https://dataclient.io/docs/api/Controller) type-safe dispatch methods, as +members of this namespace could have breaking changes in a minor release. + +```ts +import { actions, type Manager, type Middleware } from '@data-client/core'; + +export default class MyManager implements Manager { + getMiddleware = (): Middleware => controller => next => { + const todo = { id: '5', title: 'my first todo' }; + + // These do the same thing + controller.dispatch( + actions.createSet(Todo, { args: [{ id: todo.id }], value: todo }), + ); + // This is simpler; type-enforced; and will only change in major versions + controller.set(Todo, { id: todo.id }, todo); + + return async action => next(action); + }; + + cleanup() {} +} +``` + +BREAKING CHANGE: Removed `createFetch`, `createSet`, `createSetResponse` from export. Use action.createFetch instead. diff --git a/.changeset/rich-frogs-move.md b/.changeset/rich-frogs-move.md index 9314c09c8a2c..4cb49d9c5e63 100644 --- a/.changeset/rich-frogs-move.md +++ b/.changeset/rich-frogs-move.md @@ -8,8 +8,9 @@ Change normalize() interface function normalize( schema, input, - { date, expiresAt, fetchedAt, args }, + args, { entities, indexes, entityMeta }, + { date, expiresAt, fetchedAt }, ); ``` @@ -19,8 +20,9 @@ function normalize( const { result, entities, indexes, entityMeta } = normalize( action.endpoint.schema, payload, - action.meta, + action.args, state, + action.meta, ); ``` diff --git a/.changeset/stupid-worms-beam.md b/.changeset/stupid-worms-beam.md new file mode 100644 index 000000000000..fd233c3e7f15 --- /dev/null +++ b/.changeset/stupid-worms-beam.md @@ -0,0 +1,6 @@ +--- +'@data-client/core': minor +'@data-client/react': patch +--- + +action.meta.key -> action.key diff --git a/examples/benchmark/normalizr.js b/examples/benchmark/normalizr.js index d632f4229da3..7e1f80e5b8f6 100644 --- a/examples/benchmark/normalizr.js +++ b/examples/benchmark/normalizr.js @@ -36,11 +36,11 @@ const queryInfer = queryMemo.buildQueryKey( let githubState = normalize(User, userData); +const date = Date.now() const actionMeta = { - fetchedAt: Date.now(), - date: Date.now(), - expiresAt: Date.now() + 10000000, - args: [], + fetchedAt: date, + date, + expiresAt: date + 10000000, }; export default function addNormlizrSuite(suite) { @@ -55,7 +55,7 @@ export default function addNormlizrSuite(suite) { let curState = initialState; return suite .add('normalizeLong', () => { - normalize(ProjectSchema, data, actionMeta, curState); + normalize(ProjectSchema, data, [], curState, actionMeta); curState = { ...initialState, entities: {}, endpoints: {} }; }) .add('infer All', () => { diff --git a/examples/coin-app/src/resources/StreamManager.ts b/examples/coin-app/src/resources/StreamManager.ts index a7ff07f18195..5112c794c1c9 100644 --- a/examples/coin-app/src/resources/StreamManager.ts +++ b/examples/coin-app/src/resources/StreamManager.ts @@ -61,7 +61,7 @@ export default class StreamManager implements Manager { ) break; if ('channel' in action.endpoint) { - this.subscribe(action.meta.args[0]?.product_id); + this.subscribe(action.args[0]?.product_id); // consume subscription if we use it return Promise.resolve(); } @@ -79,7 +79,7 @@ export default class StreamManager implements Manager { this.send( JSON.stringify({ type: 'unsubscribe', - product_ids: [action.meta.args[0]?.product_id], + product_ids: [action.args[0]?.product_id], channels: [action.endpoint.channel], }), ); diff --git a/examples/normalizr-github/schema.js b/examples/normalizr-github/schema.js index db1dd9994d76..e357317ba247 100644 --- a/examples/normalizr-github/schema.js +++ b/examples/normalizr-github/schema.js @@ -4,7 +4,7 @@ class BaseEntity extends Entity { id = 0; pk() { - return `${this.id}`; + return this.id; } } diff --git a/examples/normalizr-relationships/schema.js b/examples/normalizr-relationships/schema.js index e37d7f0ef7fa..cdc516f44ff6 100644 --- a/examples/normalizr-relationships/schema.js +++ b/examples/normalizr-relationships/schema.js @@ -4,7 +4,7 @@ class BaseEntity extends Entity { id = 0; pk() { - return `${this.id}`; + return this.id; } } @@ -34,7 +34,7 @@ class Comment extends BaseEntity { commenter: User, }; - static process(value, parent, key) { + static process(value, parent) { return { ...value, post: parent.id }; } } diff --git a/packages/core/src/actions.ts b/packages/core/src/actions.ts index ce260e286ee9..ec1b7b8eb9d3 100644 --- a/packages/core/src/actions.ts +++ b/packages/core/src/actions.ts @@ -28,98 +28,98 @@ type EndpointDefault = EndpointInterface & { update?: EndpointUpdateFunction; }; -/* SET */ -export interface SetMeta { - args: readonly any[]; - fetchedAt: number; - date: number; - expiresAt: number; +/** General meta-data for operators */ +export interface ActionMeta { + readonly fetchedAt: number; + readonly date: number; + readonly expiresAt: number; } +/** Action for Controller.set() */ export interface SetAction { type: typeof SET_TYPE; schema: S; - meta: SetMeta; + args: readonly any[]; + meta: ActionMeta; value: {} | ((previousValue: Denormalize) => {}); } /* setResponse */ -export interface SetResponseMeta { +export interface SetResponseActionBase< + E extends EndpointAndUpdate = EndpointDefault, +> { + type: typeof SET_RESPONSE_TYPE; + endpoint: E; args: readonly any[]; key: string; - fetchedAt: number; - date: number; - expiresAt: number; + meta: ActionMeta; } export interface SetResponseActionSuccess< E extends EndpointAndUpdate = EndpointDefault, -> { - type: typeof SET_RESPONSE_TYPE; - endpoint: E; - meta: SetResponseMeta; +> extends SetResponseActionBase { response: ResolveType; error?: false; } export interface SetResponseActionError< E extends EndpointAndUpdate = EndpointDefault, -> { - type: typeof SET_RESPONSE_TYPE; - endpoint: E; - meta: SetResponseMeta; +> extends SetResponseActionBase { response: UnknownError; error: true; } +/** Action for Controller.setResponse() */ export type SetResponseAction< E extends EndpointAndUpdate = EndpointDefault, > = SetResponseActionSuccess | SetResponseActionError; /* FETCH */ -export interface FetchMeta { - args: A; - key: string; +export interface FetchMeta { + fetchedAt: number; resolve: (value?: any | PromiseLike) => void; reject: (reason?: any) => void; promise: PromiseLike; - fetchedAt: number; } +/** Action for Controller.fetch() */ export interface FetchAction = EndpointDefault> { type: typeof FETCH_TYPE; endpoint: E; - meta: FetchMeta]>; + args: readonly [...Parameters]; + key: string; + meta: FetchMeta; } /* OPTIMISTIC */ +/** Action for Endpoint.getOptimisticResponse() */ export interface OptimisticAction< E extends EndpointAndUpdate = EndpointDefault, > { type: typeof OPTIMISTIC_TYPE; endpoint: E; - meta: SetResponseMeta; + args: readonly any[]; + key: string; + meta: ActionMeta; error?: false; } /* SUBSCRIBE */ +/** Action for Controller.subscribe() */ export interface SubscribeAction< E extends EndpointAndUpdate = EndpointDefault, > { type: typeof SUBSCRIBE_TYPE; endpoint: E; - meta: { - args: readonly any[]; - key: string; - }; + args: readonly any[]; + key: string; } +/** Action for Controller.unsubscribe() */ export interface UnsubscribeAction< E extends EndpointAndUpdate = EndpointDefault, > { type: typeof UNSUBSCRIBE_TYPE; endpoint: E; - meta: { - args: readonly any[]; - key: string; - }; + args: readonly any[]; + key: string; } /* EXPIRY */ @@ -136,9 +136,7 @@ export interface InvalidateAllAction { export interface InvalidateAction { type: typeof INVALIDATE_TYPE; - meta: { - key: string; - }; + key: string; } /* RESET */ diff --git a/packages/core/src/controller/Controller.ts b/packages/core/src/controller/Controller.ts index 9cb603d3b00b..d6ef72b86ad4 100644 --- a/packages/core/src/controller/Controller.ts +++ b/packages/core/src/controller/Controller.ts @@ -20,17 +20,19 @@ import { } from '@data-client/normalizr'; import AbortOptimistic from './AbortOptimistic.js'; -import createExpireAll from './createExpireAll.js'; -import createFetch from './createFetch.js'; -import createInvalidate from './createInvalidate.js'; -import createInvalidateAll from './createInvalidateAll.js'; -import createReset from './createReset.js'; -import createSet from './createSet.js'; -import createSetResponse from './createSetResponse.js'; import { createUnsubscription, createSubscription, -} from './createSubscription.js'; +} from './actions/createSubscription.js'; +import { + createExpireAll, + createFetch, + createInvalidate, + createInvalidateAll, + createReset, + createSet, + createSetResponse, +} from './actions/index.js'; import ensurePojo from './ensurePojo.js'; import type { EndpointUpdateFunction } from './types.js'; import { initialState } from '../state/reducer/createReducer.js'; diff --git a/packages/core/src/controller/actions/createExpireAll.ts b/packages/core/src/controller/actions/createExpireAll.ts new file mode 100644 index 000000000000..6f948014344b --- /dev/null +++ b/packages/core/src/controller/actions/createExpireAll.ts @@ -0,0 +1,11 @@ +import { EXPIREALL_TYPE } from '../../actionTypes.js'; +import type { ExpireAllAction } from '../../types.js'; + +export function createExpireAll( + testKey: (key: string) => boolean, +): ExpireAllAction { + return { + type: EXPIREALL_TYPE, + testKey, + }; +} diff --git a/packages/core/src/controller/createFetch.ts b/packages/core/src/controller/actions/createFetch.ts similarity index 68% rename from packages/core/src/controller/createFetch.ts rename to packages/core/src/controller/actions/createFetch.ts index 877703f85edd..1253a61a7000 100644 --- a/packages/core/src/controller/createFetch.ts +++ b/packages/core/src/controller/actions/createFetch.ts @@ -1,36 +1,35 @@ import type { EndpointInterface, NI } from '@data-client/normalizr'; -import { EndpointUpdateFunction } from './types.js'; -import { FETCH_TYPE } from '../actionTypes.js'; -import type { FetchAction, FetchMeta } from '../types.js'; +import { FETCH_TYPE } from '../../actionTypes.js'; +import type { FetchAction, FetchMeta } from '../../types.js'; +import { EndpointUpdateFunction } from '../types.js'; /** * Requesting a fetch to begin */ -export default function createFetch< +export function createFetch< E extends EndpointInterface & { update?: EndpointUpdateFunction }, >( endpoint: E, { args }: { args: readonly [...Parameters] }, ): FetchAction { - const key = endpoint.key(...args); let resolve: (value?: any | PromiseLike) => void = 0 as any; let reject: (reason?: any) => void = 0 as any; const promise = new Promise((a, b) => { [resolve, reject] = [a, b]; }); - const meta: FetchMeta = { - args, - key, + const meta: FetchMeta = { + fetchedAt: Date.now(), resolve, reject, promise, - fetchedAt: Date.now(), }; return { type: FETCH_TYPE, - meta, endpoint, + args, + key: endpoint.key(...args), + meta, }; } diff --git a/packages/core/src/controller/actions/createInvalidate.ts b/packages/core/src/controller/actions/createInvalidate.ts new file mode 100644 index 000000000000..635c838fb277 --- /dev/null +++ b/packages/core/src/controller/actions/createInvalidate.ts @@ -0,0 +1,14 @@ +import type { EndpointInterface } from '@data-client/normalizr'; + +import { INVALIDATE_TYPE } from '../../actionTypes.js'; +import type { InvalidateAction } from '../../types.js'; + +export function createInvalidate( + endpoint: E, + { args }: { args: readonly [...Parameters] }, +): InvalidateAction { + return { + type: INVALIDATE_TYPE, + key: endpoint.key(...args), + }; +} diff --git a/packages/core/src/controller/actions/createInvalidateAll.ts b/packages/core/src/controller/actions/createInvalidateAll.ts new file mode 100644 index 000000000000..018e4b96a18c --- /dev/null +++ b/packages/core/src/controller/actions/createInvalidateAll.ts @@ -0,0 +1,11 @@ +import { INVALIDATEALL_TYPE } from '../../actionTypes.js'; +import type { InvalidateAllAction } from '../../types.js'; + +export function createInvalidateAll( + testKey: (key: string) => boolean, +): InvalidateAllAction { + return { + type: INVALIDATEALL_TYPE, + testKey, + }; +} diff --git a/packages/core/src/controller/actions/createMeta.ts b/packages/core/src/controller/actions/createMeta.ts new file mode 100644 index 000000000000..9314b62ecfb6 --- /dev/null +++ b/packages/core/src/controller/actions/createMeta.ts @@ -0,0 +1,13 @@ +import type { ActionMeta } from '../../actions.js'; + +export function createMeta( + expiryLength: number, + fetchedAt?: number, +): ActionMeta { + const now = Date.now(); + return { + fetchedAt: fetchedAt ?? now, + date: now, + expiresAt: now + expiryLength, + }; +} diff --git a/packages/core/src/controller/actions/createOptimistic.ts b/packages/core/src/controller/actions/createOptimistic.ts new file mode 100644 index 000000000000..8134e01659e9 --- /dev/null +++ b/packages/core/src/controller/actions/createOptimistic.ts @@ -0,0 +1,32 @@ +import type { EndpointInterface } from '@data-client/normalizr'; + +import { createMeta } from './createMeta.js'; +import { OPTIMISTIC_TYPE } from '../../actionTypes.js'; +import type { OptimisticAction } from '../../types.js'; +import type { EndpointUpdateFunction } from '../types.js'; + +export function createOptimistic< + E extends EndpointInterface & { + update?: EndpointUpdateFunction; + }, +>( + endpoint: E, + args: readonly [...Parameters], + fetchedAt: number, +): OptimisticAction { + /* istanbul ignore next */ + if ( + process.env.NODE_ENV === 'development' && + (endpoint.dataExpiryLength ?? 0) < 0 + ) { + throw new Error('Negative expiry length are not allowed.'); + } + + return { + type: OPTIMISTIC_TYPE, + endpoint, + args, + key: endpoint.key(...args), + meta: createMeta(endpoint.dataExpiryLength ?? 60000, fetchedAt), + }; +} diff --git a/packages/core/src/controller/actions/createReset.ts b/packages/core/src/controller/actions/createReset.ts new file mode 100644 index 000000000000..9050f20fff30 --- /dev/null +++ b/packages/core/src/controller/actions/createReset.ts @@ -0,0 +1,9 @@ +import { RESET_TYPE } from '../../actionTypes.js'; +import type { ResetAction } from '../../types.js'; + +export function createReset(): ResetAction { + return { + type: RESET_TYPE, + date: Date.now(), + }; +} diff --git a/packages/core/src/controller/actions/createSet.ts b/packages/core/src/controller/actions/createSet.ts new file mode 100644 index 000000000000..dc2fe8596ffe --- /dev/null +++ b/packages/core/src/controller/actions/createSet.ts @@ -0,0 +1,31 @@ +import type { + Denormalize, + Queryable, + SchemaArgs, +} from '@data-client/normalizr'; + +import { createMeta } from './createMeta.js'; +import { SET_TYPE } from '../../actionTypes.js'; +import type { SetAction } from '../../types.js'; +import ensurePojo from '../ensurePojo.js'; + +export function createSet( + schema: S, + { + args, + fetchedAt, + value, + }: { + args: readonly [...SchemaArgs]; + value: {} | ((previousValue: Denormalize) => {}); + fetchedAt?: number; + }, +): SetAction { + return { + type: SET_TYPE, + schema, + value, + args: args.map(ensurePojo) as SchemaArgs, + meta: createMeta(60000, fetchedAt), + }; +} diff --git a/packages/core/src/controller/createSetResponse.ts b/packages/core/src/controller/actions/createSetResponse.ts similarity index 68% rename from packages/core/src/controller/createSetResponse.ts rename to packages/core/src/controller/actions/createSetResponse.ts index a258120a22ee..17cbdf7d411e 100644 --- a/packages/core/src/controller/createSetResponse.ts +++ b/packages/core/src/controller/actions/createSetResponse.ts @@ -1,11 +1,12 @@ import type { EndpointInterface, ResolveType } from '@data-client/normalizr'; -import ensurePojo from './ensurePojo.js'; -import { EndpointUpdateFunction } from './types.js'; -import { SET_RESPONSE_TYPE } from '../actionTypes.js'; -import type { SetResponseAction, SetResponseMeta } from '../types.js'; +import { createMeta } from './createMeta.js'; +import { SET_RESPONSE_TYPE } from '../../actionTypes.js'; +import type { SetResponseAction } from '../../types.js'; +import ensurePojo from '../ensurePojo.js'; +import { EndpointUpdateFunction } from '../types.js'; -export default function createSetResponse< +export function createSetResponse< E extends EndpointInterface & { update?: EndpointUpdateFunction; }, @@ -19,7 +20,7 @@ export default function createSetResponse< }, ): SetResponseAction; -export default function createSetResponse< +export function createSetResponse< E extends EndpointInterface & { update?: EndpointUpdateFunction; }, @@ -33,7 +34,7 @@ export default function createSetResponse< }, ): SetResponseAction; -export default function createSetResponse< +export function createSetResponse< E extends EndpointInterface & { update?: EndpointUpdateFunction; }, @@ -59,21 +60,14 @@ export default function createSetResponse< if (process.env.NODE_ENV === 'development' && expiryLength < 0) { throw new Error('Negative expiry length are not allowed.'); } - const date = Date.now(); - const meta: SetResponseMeta = { - args: args.map(ensurePojo), - fetchedAt: fetchedAt ?? date, - date, - expiresAt: date + expiryLength, - key: endpoint.key(...args), - }; - const action: SetResponseAction = { + return { type: SET_RESPONSE_TYPE, - response, endpoint, - meta, + response, + args: args.map(ensurePojo), + key: endpoint.key(...args), + meta: createMeta(expiryLength, fetchedAt), + error, }; - if (error) (action as any).error = true; - return action; } diff --git a/packages/core/src/controller/createSubscription.ts b/packages/core/src/controller/actions/createSubscription.ts similarity index 64% rename from packages/core/src/controller/createSubscription.ts rename to packages/core/src/controller/actions/createSubscription.ts index 9014e5da4668..bdfc634bcd35 100644 --- a/packages/core/src/controller/createSubscription.ts +++ b/packages/core/src/controller/actions/createSubscription.ts @@ -1,7 +1,7 @@ import type { EndpointInterface } from '@data-client/normalizr'; -import { SUBSCRIBE_TYPE, UNSUBSCRIBE_TYPE } from '../actionTypes.js'; -import type { SubscribeAction, UnsubscribeAction } from '../types.js'; +import { SUBSCRIBE_TYPE, UNSUBSCRIBE_TYPE } from '../../actionTypes.js'; +import type { SubscribeAction, UnsubscribeAction } from '../../types.js'; export function createSubscription( endpoint: E, @@ -10,10 +10,8 @@ export function createSubscription( return { type: SUBSCRIBE_TYPE, endpoint, - meta: { - args, - key: endpoint.key(...args), - }, + args, + key: endpoint.key(...args), }; } @@ -24,9 +22,7 @@ export function createUnsubscription( return { type: UNSUBSCRIBE_TYPE, endpoint, - meta: { - args, - key: endpoint.key(...args), - }, + args, + key: endpoint.key(...args), }; } diff --git a/packages/core/src/controller/actions/index.ts b/packages/core/src/controller/actions/index.ts new file mode 100644 index 000000000000..ef8f44d2fc19 --- /dev/null +++ b/packages/core/src/controller/actions/index.ts @@ -0,0 +1,13 @@ +export { + createSubscription, + createUnsubscription, +} from './createSubscription.js'; +export { createSetResponse } from './createSetResponse.js'; +export { createSet } from './createSet.js'; +export { createReset } from './createReset.js'; +export { createOptimistic } from './createOptimistic.js'; +export { createMeta } from './createMeta.js'; +export { createInvalidateAll } from './createInvalidateAll.js'; +export { createInvalidate } from './createInvalidate.js'; +export { createFetch } from './createFetch.js'; +export { createExpireAll } from './createExpireAll.js'; diff --git a/packages/core/src/controller/createExpireAll.ts b/packages/core/src/controller/createExpireAll.ts deleted file mode 100644 index a28d3e8efb60..000000000000 --- a/packages/core/src/controller/createExpireAll.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { EXPIREALL_TYPE } from '../actionTypes.js'; -import type { ExpireAllAction } from '../types.js'; - -export default function createExpireAll( - testKey: (key: string) => boolean, -): ExpireAllAction { - return { - type: EXPIREALL_TYPE, - testKey, - }; -} diff --git a/packages/core/src/controller/createInvalidate.ts b/packages/core/src/controller/createInvalidate.ts deleted file mode 100644 index 31b5d6ac03fe..000000000000 --- a/packages/core/src/controller/createInvalidate.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { EndpointInterface } from '@data-client/normalizr'; - -import { INVALIDATE_TYPE } from '../actionTypes.js'; -import type { InvalidateAction } from '../types.js'; - -export default function createInvalidate( - endpoint: E, - { args }: { args: readonly [...Parameters] }, -): InvalidateAction { - return { - type: INVALIDATE_TYPE, - meta: { - key: endpoint.key(...args), - }, - }; -} diff --git a/packages/core/src/controller/createInvalidateAll.ts b/packages/core/src/controller/createInvalidateAll.ts deleted file mode 100644 index e43759488616..000000000000 --- a/packages/core/src/controller/createInvalidateAll.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { INVALIDATEALL_TYPE } from '../actionTypes.js'; -import type { InvalidateAllAction } from '../types.js'; - -export default function createInvalidateAll( - testKey: (key: string) => boolean, -): InvalidateAllAction { - return { - type: INVALIDATEALL_TYPE, - testKey, - }; -} diff --git a/packages/core/src/controller/createOptimistic.ts b/packages/core/src/controller/createOptimistic.ts deleted file mode 100644 index 7f6277e3f507..000000000000 --- a/packages/core/src/controller/createOptimistic.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { EndpointInterface } from '@data-client/normalizr'; - -import type { EndpointUpdateFunction } from './types.js'; -import { OPTIMISTIC_TYPE } from '../actionTypes.js'; -import type { OptimisticAction } from '../types.js'; - -export default function createOptimistic< - E extends EndpointInterface & { - update?: EndpointUpdateFunction; - }, ->( - endpoint: E, - { - args, - fetchedAt, - }: { - args: readonly [...Parameters]; - fetchedAt: number; - }, -): OptimisticAction { - const expiryLength: number = endpoint.dataExpiryLength ?? 60000; - /* istanbul ignore next */ - if (process.env.NODE_ENV === 'development' && expiryLength < 0) { - throw new Error('Negative expiry length are not allowed.'); - } - const now = Date.now(); - const meta: OptimisticAction['meta'] = { - args, - fetchedAt, - date: now, - expiresAt: now + expiryLength, - key: endpoint.key(...args), - }; - - const action: OptimisticAction = { - type: OPTIMISTIC_TYPE, - endpoint, - meta, - }; - return action; -} diff --git a/packages/core/src/controller/createReset.ts b/packages/core/src/controller/createReset.ts deleted file mode 100644 index b86f874821df..000000000000 --- a/packages/core/src/controller/createReset.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { RESET_TYPE } from '../actionTypes.js'; -import type { ResetAction } from '../types.js'; - -export default function createReset(): ResetAction { - return { - type: RESET_TYPE, - date: Date.now(), - }; -} diff --git a/packages/core/src/controller/createSet.ts b/packages/core/src/controller/createSet.ts deleted file mode 100644 index 81892e7a1e1b..000000000000 --- a/packages/core/src/controller/createSet.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { - Denormalize, - Queryable, - SchemaArgs, -} from '@data-client/normalizr'; - -import ensurePojo from './ensurePojo.js'; -import { SET_TYPE } from '../actionTypes.js'; -import type { SetAction, SetMeta } from '../types.js'; - -export default function createSet( - schema: S, - { - args, - fetchedAt, - value, - }: { - args: readonly [...SchemaArgs]; - value: {} | ((previousValue: Denormalize) => {}); - fetchedAt?: number; - }, -): SetAction { - const expiryLength: number = 60000; - /* istanbul ignore next */ - if (process.env.NODE_ENV === 'development' && expiryLength < 0) { - throw new Error('Negative expiry length are not allowed.'); - } - const now = Date.now(); - const meta: SetMeta = { - args: args.map(ensurePojo), - fetchedAt: fetchedAt ?? now, - date: now, - expiresAt: now + expiryLength, - }; - - const action: SetAction = { - type: SET_TYPE, - value, - schema, - meta, - }; - return action; -} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index c0808c065a7b..3335e6e662e5 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -39,9 +39,7 @@ export type { DataClientDispatch, GenericDispatch, } from './controller/Controller.js'; -export { default as createFetch } from './controller/createFetch.js'; -export { default as createSet } from './controller/createSet.js'; -export { default as createSetResponse } from './controller/createSetResponse.js'; +export * as actions from './controller/actions/index.js'; export * from './controller/types.js'; export * as actionTypes from './actionTypes.js'; diff --git a/packages/core/src/manager/NetworkManager.ts b/packages/core/src/manager/NetworkManager.ts index 9d0606c8d4e1..c98e07539180 100644 --- a/packages/core/src/manager/NetworkManager.ts +++ b/packages/core/src/manager/NetworkManager.ts @@ -1,6 +1,6 @@ import { SET_RESPONSE_TYPE, FETCH_TYPE, RESET_TYPE } from '../actionTypes.js'; +import { createSetResponse } from '../controller/actions/index.js'; import Controller from '../controller/Controller.js'; -import createSetResponse from '../controller/createSetResponse.js'; import type { FetchAction, Manager, @@ -62,15 +62,14 @@ export default class NetworkManager implements Manager { case SET_RESPONSE_TYPE: // only set after new state is computed return next(action).then(() => { - if (action.meta.key in this.fetched) { + if (action.key in this.fetched) { // Note: meta *must* be set by reducer so this should be safe - const error = - controller.getState().meta[action.meta.key]?.error; + const error = controller.getState().meta[action.key]?.error; // processing errors result in state meta having error, so we should reject the promise if (error) { this.handleSet( createSetResponse(action.endpoint, { - args: action.meta.args, + args: action.args, response: error, fetchedAt: action.meta.fetchedAt, error: true, @@ -103,7 +102,7 @@ export default class NetworkManager implements Manager { /** Used by DevtoolsManager to determine whether to log an action */ skipLogging(action: ActionTypes) { /* istanbul ignore next */ - return action.type === FETCH_TYPE && action.meta.key in this.fetched; + return action.type === FETCH_TYPE && action.key in this.fetched; } /** On mount */ @@ -153,11 +152,11 @@ export default class NetworkManager implements Manager { * for ensures mutation requests always go through. */ protected handleFetch(action: FetchAction) { - const { key, resolve, reject, fetchedAt } = action.meta; + const { resolve, reject, fetchedAt } = action.meta; const throttle = !action.endpoint.sideEffect; const deferedFetch = () => { - let promise = action.endpoint(...action.meta.args); + let promise = action.endpoint(...action.args); const resolvePromise = ( promise: Promise, ) => @@ -191,7 +190,7 @@ export default class NetworkManager implements Manager { // don't update state with promises started before last clear if (fetchedAt >= lastReset) { this.controller.resolve(action.endpoint, { - args: action.meta.args, + args: action.args, response, fetchedAt, }); @@ -203,7 +202,7 @@ export default class NetworkManager implements Manager { // don't update state with promises started before last clear if (fetchedAt >= lastReset) { this.controller.resolve(action.endpoint, { - args: action.meta.args, + args: action.args, response: error, fetchedAt, error: true, @@ -215,7 +214,7 @@ export default class NetworkManager implements Manager { }; if (throttle) { - return this.throttle(key, deferedFetch, fetchedAt) + return this.throttle(action.key, deferedFetch, fetchedAt) .then(data => resolve(data)) .catch(error => reject(error)); } else { @@ -229,16 +228,16 @@ export default class NetworkManager implements Manager { */ protected handleSet(action: SetResponseAction) { // this can still turn out to be untrue since this is async - if (action.meta.key in this.fetched) { + if (action.key in this.fetched) { let promiseHandler: (value?: any) => void; if (action.error) { - promiseHandler = this.rejectors[action.meta.key]; + promiseHandler = this.rejectors[action.key]; } else { - promiseHandler = this.resolvers[action.meta.key]; + promiseHandler = this.resolvers[action.key]; } promiseHandler(action.response); // since we're resolved we no longer need to keep track of this promise - this.clear(action.meta.key); + this.clear(action.key); } } diff --git a/packages/core/src/manager/PollingSubscription.ts b/packages/core/src/manager/PollingSubscription.ts index 5d28547bbe7f..6ea9b51a65d6 100644 --- a/packages/core/src/manager/PollingSubscription.ts +++ b/packages/core/src/manager/PollingSubscription.ts @@ -34,8 +34,8 @@ export default class PollingSubscription implements Subscription { throw new Error('frequency needed for polling subscription'); this.endpoint = action.endpoint; this.frequency = action.endpoint.pollFrequency; - this.args = action.meta.args; - this.key = action.meta.key; + this.args = action.args; + this.key = action.key; this.frequencyHistogram.set(this.frequency, 1); this.controller = controller; this.connectionListener = diff --git a/packages/core/src/manager/SubscriptionManager.ts b/packages/core/src/manager/SubscriptionManager.ts index eb6ae6c0e221..09623bde6e2e 100644 --- a/packages/core/src/manager/SubscriptionManager.ts +++ b/packages/core/src/manager/SubscriptionManager.ts @@ -79,7 +79,7 @@ export default class SubscriptionManager * */ protected handleSubscribe(action: SubscribeAction) { - const key = action.meta.key; + const key = action.key; if (key in this.subscriptions) { const frequency = action.endpoint.pollFrequency; @@ -96,7 +96,7 @@ export default class SubscriptionManager * */ protected handleUnsubscribe(action: UnsubscribeAction) { - const key = action.meta.key; + const key = action.key; /* istanbul ignore else */ if (key in this.subscriptions) { diff --git a/packages/core/src/manager/__tests__/__snapshots__/pollingSubscription.ts.snap b/packages/core/src/manager/__tests__/__snapshots__/pollingSubscription.ts.snap index 1cb3e4dee17c..3dec856b9f35 100644 --- a/packages/core/src/manager/__tests__/__snapshots__/pollingSubscription.ts.snap +++ b/packages/core/src/manager/__tests__/__snapshots__/pollingSubscription.ts.snap @@ -9,10 +9,10 @@ exports[`PollingSubscription fresh data cleanup() should not run even if interva exports[`PollingSubscription fresh data should call after period 1`] = ` [ { + "args": [], "endpoint": [Function], + "key": "test.com", "meta": { - "args": [], - "key": "test.com", "promise": Promise {}, "reject": [Function], "resolve": [Function], @@ -25,10 +25,10 @@ exports[`PollingSubscription fresh data should call after period 1`] = ` exports[`PollingSubscription fresh data should call after period 2`] = ` [ { + "args": [], "endpoint": [Function], + "key": "test.com", "meta": { - "args": [], - "key": "test.com", "promise": Promise {}, "reject": [Function], "resolve": [Function], diff --git a/packages/core/src/manager/__tests__/logoutManager.ts b/packages/core/src/manager/__tests__/logoutManager.ts index 32894d2a34df..7ffefb11dccf 100644 --- a/packages/core/src/manager/__tests__/logoutManager.ts +++ b/packages/core/src/manager/__tests__/logoutManager.ts @@ -2,7 +2,7 @@ import { CoolerArticleResource } from '__tests__/new'; import { Controller, initialState } from '../..'; import { FETCH_TYPE, RESET_TYPE } from '../../actionTypes'; -import createSetResponse from '../../controller/createSetResponse'; +import { createSetResponse } from '../../controller/actions'; import LogoutManager from '../LogoutManager.js'; function onError(e: any) { diff --git a/packages/core/src/manager/__tests__/networkManager.ts b/packages/core/src/manager/__tests__/networkManager.ts index 73b2a48ee17d..26bd72264ca2 100644 --- a/packages/core/src/manager/__tests__/networkManager.ts +++ b/packages/core/src/manager/__tests__/networkManager.ts @@ -2,8 +2,8 @@ import { Endpoint } from '@data-client/endpoint'; import { Article, ArticleResource } from '__tests__/new'; import { SET_RESPONSE_TYPE } from '../../actionTypes'; +import { createFetch } from '../../controller/actions'; import Controller from '../../controller/Controller'; -import createFetch from '../../controller/createFetch'; import NetworkManager from '../../manager/NetworkManager'; import { initialState } from '../../state/reducer/createReducer'; import { Middleware, SetResponseAction } from '../../types'; @@ -155,7 +155,7 @@ describe('NetworkManager', () => { middleware(API)(next)(fetchResolveAction); const response = await fetchResolveAction.endpoint( - ...fetchResolveAction.meta.args, + ...fetchResolveAction.args, ); // mutations resolve before dispatch, so we must wait for next tick to see set @@ -165,9 +165,10 @@ describe('NetworkManager', () => { type: SET_RESPONSE_TYPE, endpoint: fetchResolveAction.endpoint, response, + args: fetchResolveAction.args, + key: fetchResolveAction.key, + error: expect.anything(), meta: { - args: fetchResolveAction.meta.args, - key: fetchResolveAction.meta.key, date: expect.any(Number), expiresAt: expect.any(Number), fetchedAt: expect.any(Number), @@ -190,7 +191,7 @@ describe('NetworkManager', () => { middleware(API)(next)(fetchSetWithUpdatersAction); const response = await fetchSetWithUpdatersAction.endpoint( - ...fetchSetWithUpdatersAction.meta.args, + ...fetchSetWithUpdatersAction.args, ); // mutations resolve before dispatch, so we must wait for next tick to see set @@ -200,9 +201,10 @@ describe('NetworkManager', () => { type: SET_RESPONSE_TYPE, endpoint: fetchSetWithUpdatersAction.endpoint, response, + args: fetchSetWithUpdatersAction.args, + key: fetchSetWithUpdatersAction.key, + error: expect.anything(), meta: { - args: fetchSetWithUpdatersAction.meta.args, - key: fetchSetWithUpdatersAction.meta.key, date: expect.any(Number), expiresAt: expect.any(Number), fetchedAt: expect.any(Number), @@ -225,7 +227,7 @@ describe('NetworkManager', () => { middleware(API)(next)(fetchRpcWithUpdatersAction); const response = await fetchRpcWithUpdatersAction.endpoint( - ...fetchRpcWithUpdatersAction.meta.args, + ...fetchRpcWithUpdatersAction.args, ); // mutations resolve before dispatch, so we must wait for next tick to see set @@ -235,9 +237,10 @@ describe('NetworkManager', () => { type: SET_RESPONSE_TYPE, endpoint: fetchRpcWithUpdatersAction.endpoint, response, + args: fetchRpcWithUpdatersAction.args, + key: fetchRpcWithUpdatersAction.key, + error: expect.anything(), meta: { - args: fetchRpcWithUpdatersAction.meta.args, - key: fetchRpcWithUpdatersAction.meta.key, date: expect.any(Number), expiresAt: expect.any(Number), fetchedAt: expect.any(Number), @@ -260,7 +263,7 @@ describe('NetworkManager', () => { middleware(API)(next)(fetchRpcWithUpdatersAndOptimisticAction); const response = await fetchRpcWithUpdatersAndOptimisticAction.endpoint( - ...fetchRpcWithUpdatersAndOptimisticAction.meta.args, + ...fetchRpcWithUpdatersAndOptimisticAction.args, ); expect(next).toHaveBeenCalled(); @@ -270,9 +273,10 @@ describe('NetworkManager', () => { type: SET_RESPONSE_TYPE, endpoint: fetchRpcWithUpdatersAndOptimisticAction.endpoint, response, + args: fetchRpcWithUpdatersAndOptimisticAction.args, + key: fetchRpcWithUpdatersAndOptimisticAction.key, + error: expect.anything(), meta: { - args: fetchRpcWithUpdatersAndOptimisticAction.meta.args, - key: fetchRpcWithUpdatersAndOptimisticAction.meta.key, date: expect.any(Number), expiresAt: expect.any(Number), fetchedAt: expect.any(Number), @@ -294,7 +298,7 @@ describe('NetworkManager', () => { endpoint: detailEndpoint.extend({ dataExpiryLength: 314 }), }); - await fetchResolveAction.endpoint(...fetchResolveAction.meta.args); + await fetchResolveAction.endpoint(...fetchResolveAction.args); expect(dispatch).toHaveBeenCalled(); const { meta } = dispatch.mock.calls[0][0]; @@ -315,7 +319,7 @@ describe('NetworkManager', () => { endpoint: detailEndpoint.extend({ dataExpiryLength: undefined }), }); - await fetchResolveAction.endpoint(...fetchResolveAction.meta.args); + await fetchResolveAction.endpoint(...fetchResolveAction.args); expect(dispatch).toHaveBeenCalled(); const { meta } = dispatch.mock.calls[0][0]; @@ -339,8 +343,8 @@ describe('NetworkManager', () => { expect(dispatch).toHaveBeenCalledWith({ type: SET_RESPONSE_TYPE, response: error, + key: fetchRejectAction.key, meta: { - key: fetchRejectAction.meta.key, date: expect.any(Number), expiresAt: expect.any(Number), }, diff --git a/packages/core/src/manager/__tests__/pollingSubscription.ts b/packages/core/src/manager/__tests__/pollingSubscription.ts index 9516debddc35..1d9a0660a281 100644 --- a/packages/core/src/manager/__tests__/pollingSubscription.ts +++ b/packages/core/src/manager/__tests__/pollingSubscription.ts @@ -2,7 +2,7 @@ import { Endpoint } from '@data-client/endpoint'; import { Article, PollingArticleResource } from '__tests__/new'; import Controller from '../../controller/Controller'; -import { createSubscription } from '../../controller/createSubscription'; +import { createSubscription } from '../../controller/actions/createSubscription'; import { initialState } from '../../state/reducer/createReducer'; import ConnectionListener from '../ConnectionListener'; import DefaultConnectionListener from '../DefaultConnectionListener'; diff --git a/packages/core/src/manager/__tests__/subscriptionManager.ts b/packages/core/src/manager/__tests__/subscriptionManager.ts index b808d363bc47..ac635783f2ee 100644 --- a/packages/core/src/manager/__tests__/subscriptionManager.ts +++ b/packages/core/src/manager/__tests__/subscriptionManager.ts @@ -57,11 +57,9 @@ describe('SubscriptionManager', () => { : () => Promise.resolve(response); return { type: SUBSCRIBE_TYPE, - endpoint: PollingArticleResource.get, - meta: { - key: PollingArticleResource.get.key({ id: response.id }), - args: [{ id: response.id }], - }, + endpoint: PollingArticleResource.get.extend({ fetch }), + args: [{ id: response.id }], + key: PollingArticleResource.get.key({ id: response.id }), }; } function createUnsubscribeAction( @@ -70,10 +68,8 @@ describe('SubscriptionManager', () => { return { type: UNSUBSCRIBE_TYPE, endpoint: PollingArticleResource.get, - meta: { - key: PollingArticleResource.get.key({ id: response.id }), - args: [{ id: response.id }], - }, + key: PollingArticleResource.get.key({ id: response.id }), + args: [{ id: response.id }], }; } @@ -93,14 +89,14 @@ describe('SubscriptionManager', () => { middleware(API)(next)(action); expect(next).not.toHaveBeenCalled(); - expect((manager as any).subscriptions[action.meta.key]).toBeDefined(); + expect((manager as any).subscriptions[action.key]).toBeDefined(); }); it('subscribe should add a subscription (no frequency)', () => { const action = createSubscribeAction({ id: 597 }); middleware(API)(next)(action); expect(next).not.toHaveBeenCalled(); - expect((manager as any).subscriptions[action.meta.key]).toBeDefined(); + expect((manager as any).subscriptions[action.key]).toBeDefined(); }); it('subscribe with same should call subscription.add', () => { @@ -108,20 +104,20 @@ describe('SubscriptionManager', () => { middleware(API)(next)(action); expect( - (manager as any).subscriptions[action.meta.key].add.mock.calls.length, + (manager as any).subscriptions[action.key].add.mock.calls.length, ).toBe(1); middleware(API)(next)(action); expect( - (manager as any).subscriptions[action.meta.key].add.mock.calls.length, + (manager as any).subscriptions[action.key].add.mock.calls.length, ).toBe(2); }); it('subscribe with another should create another', () => { const action = createSubscribeAction({ id: 7, title: 'four cakes' }); middleware(API)(next)(action); - expect((manager as any).subscriptions[action.meta.key]).toBeDefined(); + expect((manager as any).subscriptions[action.key]).toBeDefined(); expect( - (manager as any).subscriptions[action.meta.key].add.mock.calls.length, + (manager as any).subscriptions[action.key].add.mock.calls.length, ).toBe(0); }); it('subscribe with another should not call previous', () => { @@ -134,13 +130,13 @@ describe('SubscriptionManager', () => { it('unsubscribe should delete when remove returns true', () => { const action = createUnsubscribeAction({ id: 7, title: 'four cakes' }); - (manager as any).subscriptions[action.meta.key].remove.mockImplementation( + (manager as any).subscriptions[action.key].remove.mockImplementation( () => true, ); middleware(API)(next)(action); - expect((manager as any).subscriptions[action.meta.key]).not.toBeDefined(); + expect((manager as any).subscriptions[action.key]).not.toBeDefined(); }); it('unsubscribe should delete when remove returns true (no frequency)', () => { @@ -149,27 +145,26 @@ describe('SubscriptionManager', () => { ); const action = createUnsubscribeAction({ id: 50, title: 'four cakes' }); - (manager as any).subscriptions[action.meta.key].remove.mockImplementation( + (manager as any).subscriptions[action.key].remove.mockImplementation( () => true, ); middleware(API)(next)(action); - expect((manager as any).subscriptions[action.meta.key]).not.toBeDefined(); + expect((manager as any).subscriptions[action.key]).not.toBeDefined(); }); it('unsubscribe should not delete when remove returns false', () => { const action = createUnsubscribeAction({ id: 5, title: 'four cakes' }); - (manager as any).subscriptions[action.meta.key].remove.mockImplementation( + (manager as any).subscriptions[action.key].remove.mockImplementation( () => false, ); middleware(API)(next)(action); - expect((manager as any).subscriptions[action.meta.key]).toBeDefined(); + expect((manager as any).subscriptions[action.key]).toBeDefined(); expect( - (manager as any).subscriptions[action.meta.key].remove.mock.calls - .length, + (manager as any).subscriptions[action.key].remove.mock.calls.length, ).toBe(1); }); @@ -181,7 +176,7 @@ describe('SubscriptionManager', () => { middleware(API)(next)(action); - expect((manager as any).subscriptions[action.meta.key]).not.toBeDefined(); + expect((manager as any).subscriptions[action.key]).not.toBeDefined(); expect(spy.mock.calls[0]).toMatchInlineSnapshot(` [ diff --git a/packages/core/src/state/__tests__/reducer.ts b/packages/core/src/state/__tests__/reducer.ts index 3211b72f0eb7..ae00ed24a562 100644 --- a/packages/core/src/state/__tests__/reducer.ts +++ b/packages/core/src/state/__tests__/reducer.ts @@ -39,9 +39,9 @@ describe('reducer', () => { type: SET_RESPONSE_TYPE, response, endpoint: ArticleResource.get, + args: [{ id }], + key: ArticleResource.get.url({ id }), meta: { - args: [{ id }], - key: ArticleResource.get.url({ id }), date: 5000000000, expiresAt: 5000500000, fetchedAt: 5000000000, @@ -221,8 +221,8 @@ describe('reducer', () => { type: SET_TYPE, value, schema: Counter, + args: [{ id }], meta: { - args: [{ id }], date: 0, fetchedAt: 0, expiresAt: 1000000000000, @@ -251,8 +251,8 @@ describe('reducer', () => { type: SET_TYPE, value, schema: Counter, + args: [{ id }], meta: { - args: [{ id }], date: 0, fetchedAt: 0, expiresAt: 1000000000000, @@ -279,8 +279,8 @@ describe('reducer', () => { type: SET_TYPE, value, schema: Article, + args: [{ id }], meta: { - args: [{ id }], date: 0, fetchedAt: 0, expiresAt: 1000000000000, @@ -301,8 +301,8 @@ describe('reducer', () => { type: SET_TYPE, value, schema: Article, + args: [{ id }], meta: { - args: [{ id }], date: 0, fetchedAt: 0, expiresAt: 1000000000000, @@ -323,9 +323,9 @@ describe('reducer', () => { type: SET_RESPONSE_TYPE, response, endpoint: ArticleResource.get, + args: [{ id }], + key: ArticleResource.get.key(response), meta: { - args: [{ id }], - key: ArticleResource.get.key(response), date: 0, fetchedAt: 0, expiresAt: 1000000000000, @@ -344,9 +344,9 @@ describe('reducer', () => { type: SET_RESPONSE_TYPE, response: { id }, endpoint: ArticleResource.delete, + args: [{ id }], + key: ArticleResource.delete.key({ id }), meta: { - args: [{ id }], - key: ArticleResource.delete.key({ id }), fetchedAt: 0, date: 0, expiresAt: 0, @@ -492,9 +492,7 @@ describe('reducer', () => { const id = 20; const action: InvalidateAction = { type: INVALIDATE_TYPE, - meta: { - key: id.toString(), - }, + key: id.toString(), }; const iniState: any = { ...initialState, @@ -533,9 +531,9 @@ describe('reducer', () => { type: SET_RESPONSE_TYPE, response: error, endpoint: ArticleResource.get, + args: [{ id }], + key: ArticleResource.get.key({ id }), meta: { - args: [{ id }], - key: ArticleResource.get.key({ id }), fetchedAt: 5000000000, date: 5000000000, expiresAt: 5000500000, @@ -553,9 +551,9 @@ describe('reducer', () => { type: SET_RESPONSE_TYPE, response: error, endpoint: ArticleResource.get, + args: [{ id }], + key: ArticleResource.get.key({ id }), meta: { - args: [{ id }], - key: ArticleResource.get.key({ id }), fetchedAt: 0, date: 0, expiresAt: 10000000000000000000, @@ -574,9 +572,9 @@ describe('reducer', () => { type: SET_RESPONSE_TYPE, response: error, endpoint: ArticleResource.delete, + args: [{ id }], + key: ArticleResource.delete.key({ id }), meta: { - args: [{ id }], - key: ArticleResource.delete.key({ id }), fetchedAt: 0, date: 0, expiresAt: 0, @@ -605,9 +603,9 @@ describe('reducer', () => { const action: FetchAction = { type: FETCH_TYPE, endpoint: ArticleResource.get, + args: [{ id: 5 }], + key: ArticleResource.get.url({ id: 5 }), meta: { - args: [{ id: 5 }], - key: ArticleResource.get.url({ id: 5 }), reject: (v: any) => null, resolve: (v: any) => null, promise: new Promise((v: any) => null), diff --git a/packages/core/src/state/reducer/fetchReducer.ts b/packages/core/src/state/reducer/fetchReducer.ts index 769666335f18..46d5199b406c 100644 --- a/packages/core/src/state/reducer/fetchReducer.ts +++ b/packages/core/src/state/reducer/fetchReducer.ts @@ -1,16 +1,17 @@ -import createOptimistic from '../../controller/createOptimistic.js'; -import type { - State, - SetResponseAction, - OptimisticAction, - FetchAction, -} from '../../types.js'; +import { createOptimistic } from '../../controller/actions/createOptimistic.js'; +import type { State, FetchAction } from '../../types.js'; export function fetchReducer(state: State, action: FetchAction) { - let setAction: SetResponseAction | OptimisticAction; - if (action.endpoint.getOptimisticResponse && action.endpoint.sideEffect) { - setAction = createOptimistic(action.endpoint, action.meta); + const setAction = createOptimistic( + action.endpoint, + action.args, + action.meta.fetchedAt, + ); + return { + ...state, + optimistic: [...state.optimistic, setAction], + }; } else { // If 'fetch' action reaches the reducer there are no middlewares installed to handle it /* istanbul ignore next */ @@ -19,14 +20,10 @@ export function fetchReducer(state: State, action: FetchAction) { 'Fetch appears unhandled - you are likely missing the NetworkManager middleware', ); console.warn( - 'See https://dataclient.io/docs/guides/redux#indextsx for hooking up redux', + 'See https://dataclient.io/docs/guides/redux for hooking up redux', ); } return state; } - return { - ...state, - optimistic: [...state.optimistic, setAction], - }; } diff --git a/packages/core/src/state/reducer/invalidateReducer.ts b/packages/core/src/state/reducer/invalidateReducer.ts index ef2ab3780957..a4d333327412 100644 --- a/packages/core/src/state/reducer/invalidateReducer.ts +++ b/packages/core/src/state/reducer/invalidateReducer.ts @@ -22,7 +22,7 @@ export function invalidateReducer( meta[key] = itemMeta; }; if (action.type === INVALIDATE_TYPE) { - invalidateKey(action.meta.key); + invalidateKey(action.key); } else { Object.keys(endpoints).forEach(key => { if (action.testKey(key)) { diff --git a/packages/core/src/state/reducer/setReducer.ts b/packages/core/src/state/reducer/setReducer.ts index 36d5d39ba9f7..d2e5c81afefd 100644 --- a/packages/core/src/state/reducer/setReducer.ts +++ b/packages/core/src/state/reducer/setReducer.ts @@ -10,11 +10,7 @@ export function setReducer( ) { let value: any; if (typeof action.value === 'function') { - const previousValue = controller.get( - action.schema, - ...action.meta.args, - state, - ); + const previousValue = controller.get(action.schema, ...action.args, state); if (previousValue === undefined) return state; value = action.value(previousValue); } else { @@ -24,8 +20,9 @@ export function setReducer( const { entities, indexes, entityMeta } = normalize( action.schema, value, - action.meta, + action.args, state, + action.meta, ); return { entities, diff --git a/packages/core/src/state/reducer/setResponseReducer.ts b/packages/core/src/state/reducer/setResponseReducer.ts index 016b5a238c2c..cd06f2984f48 100644 --- a/packages/core/src/state/reducer/setResponseReducer.ts +++ b/packages/core/src/state/reducer/setResponseReducer.ts @@ -29,7 +29,7 @@ export function setResponseReducer( response = action.endpoint.getOptimisticResponse.call( action.endpoint, controller.snapshot(state, action.meta.fetchedAt), - ...action.meta.args, + ...action.args, ); } catch (e: any) { // AbortOptimistic means 'do nothing', otherwise we count the exception as endpoint failure @@ -44,16 +44,17 @@ export function setResponseReducer( const { result, entities, indexes, entityMeta } = normalize( action.endpoint.schema, response, - action.meta, + action.args, state, + action.meta, ); const endpoints: Record = { ...state.endpoints, - [action.meta.key]: result, + [action.key]: result, }; try { if (action.endpoint.update) { - const updaters = action.endpoint.update(result, ...action.meta.args); + const updaters = action.endpoint.update(result, ...action.args); Object.keys(updaters).forEach(key => { endpoints[key] = updaters[key](endpoints[key]); }); @@ -62,7 +63,7 @@ export function setResponseReducer( // integrity of this state update is still guaranteed } catch (error) { console.error( - `The following error occured during Endpoint.update() for ${action.meta.key}`, + `The following error occured during Endpoint.update() for ${action.key}`, ); console.error(error); } @@ -73,10 +74,10 @@ export function setResponseReducer( entityMeta, meta: { ...state.meta, - [action.meta.key]: { + [action.key]: { date: action.meta.date, expiresAt: action.meta.expiresAt, - prevExpiresAt: state.meta[action.meta.key]?.expiresAt, + prevExpiresAt: state.meta[action.key]?.expiresAt, }, }, optimistic: filterOptimistic(state, action), @@ -86,7 +87,7 @@ export function setResponseReducer( } catch (error: any) { if (typeof error === 'object') { error.message = `Error processing ${ - action.meta.key + action.key }\n\nFull Schema: ${JSON.stringify( action.endpoint.schema, undefined, @@ -123,7 +124,7 @@ function reduceError( ...state, meta: { ...state.meta, - [action.meta.key]: { + [action.key]: { date: action.meta.date, error, expiresAt: action.meta.expiresAt, @@ -140,7 +141,7 @@ function filterOptimistic( ) { return state.optimistic.filter( optimisticAction => - optimisticAction.meta.key !== resolvingAction.meta.key || + optimisticAction.key !== resolvingAction.key || (optimisticAction.type === OPTIMISTIC_TYPE ? optimisticAction.meta.fetchedAt !== resolvingAction.meta.fetchedAt : optimisticAction.meta.date > resolvingAction.meta.date), diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 376369cb0c9c..837b91073493 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -12,6 +12,8 @@ import type { } from './actions.js'; import type { Dispatch, Middleware, MiddlewareAPI } from './middlewareTypes.js'; +export * from './actions.js'; + export type { AbstractInstanceType, UpdateFunction }; export type PK = string; @@ -27,9 +29,9 @@ export interface State { readonly meta: { readonly [key: string]: { readonly date: number; - readonly error?: ErrorTypes; readonly expiresAt: number; readonly prevExpiresAt?: number; + readonly error?: ErrorTypes; readonly invalidated?: boolean; readonly errorPolicy?: 'hard' | 'soft' | undefined; }; @@ -37,9 +39,9 @@ export interface State { readonly entityMeta: { readonly [entityKey: string]: { readonly [pk: string]: { + readonly fetchedAt: number; readonly date: number; readonly expiresAt: number; - readonly fetchedAt: number; }; }; }; @@ -47,8 +49,6 @@ export interface State { readonly lastReset: number; } -export * from './actions.js'; - export interface Manager { getMiddleware(): Middleware; cleanup(): void; diff --git a/packages/endpoint/src/schemas/Collection.ts b/packages/endpoint/src/schemas/Collection.ts index 31d0f241859c..340d257eac7d 100644 --- a/packages/endpoint/src/schemas/Collection.ts +++ b/packages/endpoint/src/schemas/Collection.ts @@ -200,11 +200,11 @@ export default class CollectionSchema< mergeMetaWithStore( existingMeta: { - expiresAt: number; - date: number; fetchedAt: number; + date: number; + expiresAt: number; }, - incomingMeta: { expiresAt: number; date: number; fetchedAt: number }, + incomingMeta: { fetchedAt: number; date: number; expiresAt: number }, existing: any, incoming: any, ) { diff --git a/packages/endpoint/src/schemas/EntitySchema.ts b/packages/endpoint/src/schemas/EntitySchema.ts index 75ad7cde986b..c064fe61ddde 100644 --- a/packages/endpoint/src/schemas/EntitySchema.ts +++ b/packages/endpoint/src/schemas/EntitySchema.ts @@ -157,11 +157,11 @@ export default function EntitySchema( */ static mergeMetaWithStore( existingMeta: { - expiresAt: number; - date: number; fetchedAt: number; + date: number; + expiresAt: number; }, - incomingMeta: { expiresAt: number; date: number; fetchedAt: number }, + incomingMeta: { fetchedAt: number; date: number; expiresAt: number }, existing: any, incoming: any, ) { diff --git a/packages/endpoint/src/schemas/__tests__/Collection.test.ts b/packages/endpoint/src/schemas/__tests__/Collection.test.ts index 37dff8316f6f..12ae091f6c9a 100644 --- a/packages/endpoint/src/schemas/__tests__/Collection.test.ts +++ b/packages/endpoint/src/schemas/__tests__/Collection.test.ts @@ -104,7 +104,7 @@ describe(`${schema.Collection.name} normalization`, () => { const state = normalize( userTodos, [{ id: '5', title: 'finish collections' }], - { args: [{ userId: '1' }] }, + [{ userId: '1' }], ); expect(state).toMatchSnapshot(); //const a: string[] | undefined = state.result; @@ -116,7 +116,7 @@ describe(`${schema.Collection.name} normalization`, () => { const state = normalize( new schema.Collection(new schema.Array(Todo)), [{ id: '5', title: 'finish collections' }], - { args: [{ userId: '1' }] }, + [{ userId: '1' }], ); expect(state).toMatchSnapshot(); //const a: string[] | undefined = state.result; @@ -182,7 +182,7 @@ describe(`${schema.Collection.name} normalization`, () => { const state = normalize( User.schema.todos.push, [{ id: '10', title: 'create new items' }], - { args: [{ userId: '1' }] }, + [{ userId: '1' }], init, ); expect(state).toMatchSnapshot(); @@ -195,7 +195,7 @@ describe(`${schema.Collection.name} normalization`, () => { ...normalize( initializingSchema, [{ id: '10', title: 'create new items' }], - { args: [{ userId: '1' }] }, + [{ userId: '1' }], initialState, ), }; @@ -204,7 +204,7 @@ describe(`${schema.Collection.name} normalization`, () => { ...normalize( initializingSchema, [{ id: '10', title: 'create new items' }], - { args: [{ userId: '1', ignoredMe: '5' }] }, + [{ userId: '1', ignoredMe: '5' }], state, ), }; @@ -213,7 +213,7 @@ describe(`${schema.Collection.name} normalization`, () => { ...normalize( initializingSchema, [{ id: '20', title: 'second user' }], - { args: [{ userId: '2' }] }, + [{ userId: '2' }], state, ), }; @@ -225,7 +225,7 @@ describe(`${schema.Collection.name} normalization`, () => { { id: '10', title: 'create new items' }, { id: '20', title: 'the ignored one' }, ], - { args: [{}] }, + [{}], state, ), }; @@ -244,7 +244,7 @@ describe(`${schema.Collection.name} normalization`, () => { ...normalize( sch.push, [{ id: '30', title: 'pushed to the end' }], - { args: [{ userId: '1' }] }, + [{ userId: '1' }], state, ), }; @@ -425,7 +425,7 @@ describe(`${schema.Collection.name} denormalization`, () => { const pushedState = normalize( User.schema.todos.push, [{ id: '10', title: 'create new items' }], - { args: [{ userId: '1' }] }, + [{ userId: '1' }], normalizeNested, ); const todos = memo.denormalize( @@ -452,7 +452,7 @@ describe(`${schema.Collection.name} denormalization`, () => { const unshiftState = normalize( User.schema.todos.unshift, [{ id: '2', title: 'from the start' }], - { args: [{ userId: '1' }] }, + [{ userId: '1' }], normalizeNested, ); const todos = memo.denormalize( diff --git a/packages/endpoint/src/schemas/__tests__/Entity.test.ts b/packages/endpoint/src/schemas/__tests__/Entity.test.ts index 6ccc0e40678f..c356cbf39d50 100644 --- a/packages/endpoint/src/schemas/__tests__/Entity.test.ts +++ b/packages/endpoint/src/schemas/__tests__/Entity.test.ts @@ -103,7 +103,7 @@ describe(`${Entity.name} normalization`, () => { const secondEntities = normalize( MyEntity, { id: '1', title: 'second' }, - {}, + [], { entities, entityMeta, indexes: {} }, ).entities; expect(entities.MyEntity['1']).toBeDefined(); diff --git a/packages/endpoint/src/schemas/__tests__/EntitySchema.test.ts b/packages/endpoint/src/schemas/__tests__/EntitySchema.test.ts index b7e5bede00fd..f3242d5833d5 100644 --- a/packages/endpoint/src/schemas/__tests__/EntitySchema.test.ts +++ b/packages/endpoint/src/schemas/__tests__/EntitySchema.test.ts @@ -348,7 +348,7 @@ describe(`${schema.Entity.name} normalization`, () => { const secondEntities = normalize( MyEntity, { id: '1', title: 'second' }, - {}, + [], { entities, entityMeta, indexes: {} }, ).entities; expect(entities.MyEntity['1']).toBeDefined(); diff --git a/packages/endpoint/src/schemas/__tests__/__snapshots__/Serializable.test.ts.snap b/packages/endpoint/src/schemas/__tests__/__snapshots__/Serializable.test.ts.snap index 2031c52cf486..5e24ec7a4d65 100644 --- a/packages/endpoint/src/schemas/__tests__/__snapshots__/Serializable.test.ts.snap +++ b/packages/endpoint/src/schemas/__tests__/__snapshots__/Serializable.test.ts.snap @@ -61,4 +61,4 @@ exports[`Serializable normalization normalizes date and custom as passthrough 1` } `; -exports[`Serializable normalization normalizes date and custom as passthrough 2`] = `"{"result":{"user":"1","anotherItem":{"thing":500},"time":"2020-06-07T02:00:15+0000"},"entities":{"User":{"1":{"id":"1","name":"Nacho","createdAt":"2020-06-07T02:00:15+0000"}}},"indexes":{},"entityMeta":{"User":{"1":{"expiresAt":null,"date":1557831718135,"fetchedAt":0}}}}"`; +exports[`Serializable normalization normalizes date and custom as passthrough 2`] = `"{"result":{"user":"1","anotherItem":{"thing":500},"time":"2020-06-07T02:00:15+0000"},"entities":{"User":{"1":{"id":"1","name":"Nacho","createdAt":"2020-06-07T02:00:15+0000"}}},"indexes":{},"entityMeta":{"User":{"1":{"fetchedAt":0,"date":1557831718135,"expiresAt":null}}}}"`; diff --git a/packages/normalizr/docs/api.md b/packages/normalizr/docs/api.md index b328a73f5f32..ddd9eb479193 100644 --- a/packages/normalizr/docs/api.md +++ b/packages/normalizr/docs/api.md @@ -9,12 +9,13 @@ - [Union](#uniondefinition-schemaattribute) - [Values](#valuesdefinition-schemaattribute) -## `normalize(schema, data)` +## `normalize(schema, data, args?, prevState?, meta?)` Normalizes input data per the schema definition provided. - `schema`: **required** A schema definition - `data`: **required** Input JSON (or plain JS object) data that needs normalization. +- `args`: Array of args to use in lookups for mutable/querable types like Entity and Collection ### Usage @@ -213,7 +214,7 @@ const tweet = new schema.Entity( } ); -const normalizedData = normalize(data, tweet); +const normalizedData = normalize(tweet, data); ``` #### Output @@ -242,7 +243,7 @@ const patronsSchema = new schema.Entity('patrons', undefined, { idAttribute: (value) => (value.guest_id ? `${value.id}-${value.guest_id}` : value.id) }); -normalize(data, [patronsSchema]); +normalize([patronsSchema], data); ``` #### Output @@ -281,7 +282,7 @@ const responseSchema = new schema.Object({ users: new schema.Array(user) }); // or shorthand const responseSchema = { users: new schema.Array(user) }; -const normalizedData = normalize(data, responseSchema); +const normalizedData = normalize(responseSchema, data); ``` #### Output @@ -327,7 +328,7 @@ const unionSchema = new schema.Union( 'type' ); -const normalizedData = normalize(data, { owner: unionSchema }); +const normalizedData = normalize({ owner: unionSchema }, data); ``` #### Output @@ -364,7 +365,7 @@ const data = { firstThing: { id: 1 }, secondThing: { id: 2 } }; const item = new schema.Entity('items'); const valuesSchema = new schema.Values(item); -const normalizedData = normalize(data, valuesSchema); +const normalizedData = normalize(valuesSchema, data); ``` #### Output @@ -402,7 +403,7 @@ const valuesSchema = new schema.Values( (input, parent, key) => `${input.type}s` ); -const normalizedData = normalize(data, valuesSchema); +const normalizedData = normalize(valuesSchema, data); ``` #### Output diff --git a/packages/normalizr/src/__tests__/normalizerMerge.test.tsx b/packages/normalizr/src/__tests__/normalizerMerge.test.tsx index 4962d8958bcf..bf587ac2185f 100644 --- a/packages/normalizr/src/__tests__/normalizerMerge.test.tsx +++ b/packages/normalizr/src/__tests__/normalizerMerge.test.tsx @@ -17,7 +17,7 @@ describe('normalizer() merging', () => { const { result, entities } = normalize( Article, { id, title: 'hello' }, - {}, + [], { entities: first, entityMeta: firstEM, indexes: {} }, ); @@ -52,7 +52,7 @@ describe('normalizer() merging', () => { const { entities } = normalize( Article, { id, title: 'hi', content: 'this is the content' }, - {}, + [], { entities: entitiesA, indexes: {}, entityMeta: {} }, ); @@ -69,12 +69,11 @@ describe('normalizer() merging', () => { content: 'this is the content', }); - const { result, entities } = normalize( - Article, - { id, title: null }, - {}, - { entities: first, entityMeta: firstEM, indexes: {} }, - ); + const { result, entities } = normalize(Article, { id, title: null }, [], { + entities: first, + entityMeta: firstEM, + indexes: {}, + }); const merged = denormalize(Article, result, entities); expect(merged).toBeInstanceOf(Article); @@ -95,12 +94,11 @@ describe('normalizer() merging', () => { content: 'this is the content', }); - normalize( - Article, - { id, title: 'hello' }, - {}, - { entities: first, indexes: {}, entityMeta: {} }, - ); + normalize(Article, { id, title: 'hello' }, [], { + entities: first, + indexes: {}, + entityMeta: {}, + }); const merged = denormalize(Article, id, first); expect(merged).toBeInstanceOf(Article); @@ -120,14 +118,11 @@ describe('normalizer() merging', () => { }); const nested = { id, title: 'hello' }; - const { entities } = normalize( - Article, - nested, - { - args: [], - }, - { entities: first, indexes: {}, entityMeta: {} }, - ); + const { entities } = normalize(Article, nested, [], { + entities: first, + indexes: {}, + entityMeta: {}, + }); expect(entities).toMatchInlineSnapshot(` { diff --git a/packages/normalizr/src/normalize.ts b/packages/normalizr/src/normalize.ts index 883a3f600600..4fc9a3f32b48 100644 --- a/packages/normalizr/src/normalize.ts +++ b/packages/normalizr/src/normalize.ts @@ -80,7 +80,7 @@ const addEntities = }; }; }, - actionMeta: { expiresAt: number; date: number; fetchedAt: number }, + actionMeta: { fetchedAt: number; date: number; expiresAt: number }, ) => (schema: EntityInterface, processedEntity: any, id: string) => { const schemaKey = schema.key; @@ -213,9 +213,9 @@ interface StoreData { entityMeta: { readonly [entityKey: string]: { readonly [pk: string]: { + readonly fetchedAt: number; readonly date: number; readonly expiresAt: number; - readonly fetchedAt: number; }; }; }; @@ -226,10 +226,9 @@ const emptyStore: StoreData = { entityMeta: {}, }; interface NormalizeMeta { - expiresAt?: number; - date?: number; - fetchedAt?: number; - args?: readonly any[]; + expiresAt: number; + date: number; + fetchedAt: number; } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export const normalize = < @@ -242,13 +241,9 @@ export const normalize = < >( schema: S | undefined, input: any, - { - date = Date.now(), - expiresAt = Infinity, - fetchedAt = 0, - args = [], - }: NormalizeMeta = {}, + args: readonly any[] = [], { entities, indexes, entityMeta }: StoreData = emptyStore, + meta: NormalizeMeta = { fetchedAt: 0, date: Date.now(), expiresAt: Infinity }, ): NormalizedSchema => { // no schema means we don't process at all if (schema === undefined || schema === null) @@ -321,7 +316,7 @@ See https://dataclient.io/rest/api/RestEndpoint#parseResponse for more informati ret.entities, ret.indexes, ret.entityMeta, - { expiresAt, date, fetchedAt }, + meta, ); const visit = getVisit(addEntity, createGetEntity(entities)); diff --git a/packages/react/src/__tests__/__snapshots__/hooks-endpoint.web.tsx.snap b/packages/react/src/__tests__/__snapshots__/hooks-endpoint.web.tsx.snap index bba6bab93fad..6a0428518da0 100644 --- a/packages/react/src/__tests__/__snapshots__/hooks-endpoint.web.tsx.snap +++ b/packages/react/src/__tests__/__snapshots__/hooks-endpoint.web.tsx.snap @@ -34,14 +34,14 @@ exports[`useController().getState ExternalDataProvider should eventually update exports[`useController.fetch should dispatch an action that fetches a create 1`] = ` { + "args": [ + { + "content": "hi", + }, + ], "endpoint": [Function], + "key": "POST http://test.com/article-cooler", "meta": { - "args": [ - { - "content": "hi", - }, - ], - "key": "POST http://test.com/article-cooler", "reject": [Function], "resolve": [Function], }, @@ -51,17 +51,17 @@ exports[`useController.fetch should dispatch an action that fetches a create 1`] exports[`useController.fetch should dispatch an action that fetches a full update 1`] = ` { + "args": [ + { + "id": 1, + }, + { + "content": "changed", + }, + ], "endpoint": [Function], + "key": "PUT http://test.com/article-cooler/1", "meta": { - "args": [ - { - "id": 1, - }, - { - "content": "changed", - }, - ], - "key": "PUT http://test.com/article-cooler/1", "reject": [Function], "resolve": [Function], }, @@ -71,17 +71,17 @@ exports[`useController.fetch should dispatch an action that fetches a full updat exports[`useController.fetch should dispatch an action that fetches a partial update 1`] = ` { + "args": [ + { + "id": 1, + }, + { + "content": "changed", + }, + ], "endpoint": [Function], + "key": "PATCH http://test.com/article-cooler/1", "meta": { - "args": [ - { - "id": 1, - }, - { - "content": "changed", - }, - ], - "key": "PATCH http://test.com/article-cooler/1", "reject": [Function], "resolve": [Function], }, @@ -91,14 +91,14 @@ exports[`useController.fetch should dispatch an action that fetches a partial up exports[`useController.fetch should dispatch an action with updater in the meta if update shapes params are passed in 1`] = ` { + "args": [ + { + "content": "hi", + }, + ], "endpoint": [Function], + "key": "POST http://test.com/article-cooler", "meta": { - "args": [ - { - "content": "hi", - }, - ], - "key": "POST http://test.com/article-cooler", "reject": [Function], "resolve": [Function], }, @@ -108,14 +108,14 @@ exports[`useController.fetch should dispatch an action with updater in the meta exports[`useController.fetch should refresh get details 1`] = ` { + "args": [ + { + "id": 1, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-cooler/1", "meta": { - "args": [ - { - "id": 1, - }, - ], - "key": "GET http://test.com/article-cooler/1", "reject": [Function], "resolve": [Function], }, diff --git a/packages/react/src/__tests__/hooks-endpoint.web.tsx b/packages/react/src/__tests__/hooks-endpoint.web.tsx index 7f2dce0f28d3..656e565c562e 100644 --- a/packages/react/src/__tests__/hooks-endpoint.web.tsx +++ b/packages/react/src/__tests__/hooks-endpoint.web.tsx @@ -40,7 +40,7 @@ async function testDispatchFetch( delete call[0]?.meta?.promise; expect(call[0]).toMatchSnapshot(); const action = call[0]; - const res = await action.endpoint(...action.meta.args); + const res = await action.endpoint(...action.args); expect(res).toEqual(payloads[i]); i++; } @@ -244,9 +244,7 @@ describe('useController().invalidate', () => { invalidate(PaginatedArticleResource.getList); expect(dispatch).toHaveBeenCalledWith({ type: INVALIDATE_TYPE, - meta: { - key: PaginatedArticleResource.getList.key(), - }, + key: PaginatedArticleResource.getList.key(), }); }); it('should return the same === function each time', () => { diff --git a/packages/react/src/components/__tests__/provider.native.tsx b/packages/react/src/components/__tests__/provider.native.tsx index 4b132e9a110d..fcd89478c714 100644 --- a/packages/react/src/components/__tests__/provider.native.tsx +++ b/packages/react/src/components/__tests__/provider.native.tsx @@ -142,9 +142,9 @@ describe('', () => { type: SET_RESPONSE_TYPE, response: { id: 5, title: 'hi', content: 'more things here' }, endpoint: CoolerArticleResource.get, + args: [{ id: 5 }], + key: CoolerArticleResource.get.key({ id: 5 }), meta: { - args: [{ id: 5 }], - key: CoolerArticleResource.get.key({ id: 5 }), fetchedAt: 50, date: 50, expiresAt: 55, diff --git a/packages/react/src/components/__tests__/provider.tsx b/packages/react/src/components/__tests__/provider.tsx index 4df7934ef5ca..d7e23894b69d 100644 --- a/packages/react/src/components/__tests__/provider.tsx +++ b/packages/react/src/components/__tests__/provider.tsx @@ -141,9 +141,9 @@ describe('', () => { type: SET_RESPONSE_TYPE, response: { id: 5, title: 'hi', content: 'more things here' }, endpoint: CoolerArticleResource.get, + args: [{ id: 5 }], + key: CoolerArticleResource.get.key({ id: 5 }), meta: { - args: [{ id: 5 }], - key: CoolerArticleResource.get.key({ id: 5 }), fetchedAt: 50, date: 50, expiresAt: 55, diff --git a/packages/react/src/hooks/__tests__/__snapshots__/useDLE.native.tsx.snap b/packages/react/src/hooks/__tests__/__snapshots__/useDLE.native.tsx.snap index 8b257bfa8e92..fa5f8e47c939 100644 --- a/packages/react/src/hooks/__tests__/__snapshots__/useDLE.native.tsx.snap +++ b/packages/react/src/hooks/__tests__/__snapshots__/useDLE.native.tsx.snap @@ -2,14 +2,14 @@ exports[`useDLE should dispatch singles 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-cooler/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-cooler/5", "reject": [Function], "resolve": [Function], }, @@ -19,14 +19,14 @@ exports[`useDLE should dispatch singles 1`] = ` exports[`useDLE should dispatch with fetch shape defined dataExpiryLength 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-static/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-static/5", "reject": [Function], "resolve": [Function], }, @@ -36,14 +36,14 @@ exports[`useDLE should dispatch with fetch shape defined dataExpiryLength 1`] = exports[`useDLE should dispatch with fetch shape defined errorExpiryLength 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-static/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-static/5", "reject": [Function], "resolve": [Function], }, @@ -53,14 +53,14 @@ exports[`useDLE should dispatch with fetch shape defined errorExpiryLength 1`] = exports[`useDLE should dispatch with resource defined dataExpiryLength 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-static/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-static/5", "reject": [Function], "resolve": [Function], }, diff --git a/packages/react/src/hooks/__tests__/__snapshots__/useFetch.native.tsx.snap b/packages/react/src/hooks/__tests__/__snapshots__/useFetch.native.tsx.snap index e33eb7d8dd45..d70ea1141267 100644 --- a/packages/react/src/hooks/__tests__/__snapshots__/useFetch.native.tsx.snap +++ b/packages/react/src/hooks/__tests__/__snapshots__/useFetch.native.tsx.snap @@ -2,14 +2,14 @@ exports[`useFetch should dispatch singles 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-cooler/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-cooler/5", "reject": [Function], "resolve": [Function], }, @@ -19,14 +19,14 @@ exports[`useFetch should dispatch singles 1`] = ` exports[`useFetch should dispatch with fetch shape defined dataExpiryLength 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-static/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-static/5", "reject": [Function], "resolve": [Function], }, @@ -36,14 +36,14 @@ exports[`useFetch should dispatch with fetch shape defined dataExpiryLength 1`] exports[`useFetch should dispatch with fetch shape defined errorExpiryLength 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-static/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-static/5", "reject": [Function], "resolve": [Function], }, @@ -53,14 +53,14 @@ exports[`useFetch should dispatch with fetch shape defined errorExpiryLength 1`] exports[`useFetch should dispatch with resource defined dataExpiryLength 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-static/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-static/5", "reject": [Function], "resolve": [Function], }, diff --git a/packages/react/src/hooks/__tests__/__snapshots__/useFetch.web.tsx.snap b/packages/react/src/hooks/__tests__/__snapshots__/useFetch.web.tsx.snap index e33eb7d8dd45..d70ea1141267 100644 --- a/packages/react/src/hooks/__tests__/__snapshots__/useFetch.web.tsx.snap +++ b/packages/react/src/hooks/__tests__/__snapshots__/useFetch.web.tsx.snap @@ -2,14 +2,14 @@ exports[`useFetch should dispatch singles 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-cooler/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-cooler/5", "reject": [Function], "resolve": [Function], }, @@ -19,14 +19,14 @@ exports[`useFetch should dispatch singles 1`] = ` exports[`useFetch should dispatch with fetch shape defined dataExpiryLength 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-static/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-static/5", "reject": [Function], "resolve": [Function], }, @@ -36,14 +36,14 @@ exports[`useFetch should dispatch with fetch shape defined dataExpiryLength 1`] exports[`useFetch should dispatch with fetch shape defined errorExpiryLength 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-static/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-static/5", "reject": [Function], "resolve": [Function], }, @@ -53,14 +53,14 @@ exports[`useFetch should dispatch with fetch shape defined errorExpiryLength 1`] exports[`useFetch should dispatch with resource defined dataExpiryLength 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-static/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-static/5", "reject": [Function], "resolve": [Function], }, diff --git a/packages/react/src/hooks/__tests__/__snapshots__/useSuspense.native.tsx.snap b/packages/react/src/hooks/__tests__/__snapshots__/useSuspense.native.tsx.snap index f37650bc7ea0..43b1bf0d9fe2 100644 --- a/packages/react/src/hooks/__tests__/__snapshots__/useSuspense.native.tsx.snap +++ b/packages/react/src/hooks/__tests__/__snapshots__/useSuspense.native.tsx.snap @@ -110,14 +110,14 @@ First three members: []] exports[`useSuspense() should dispatch an action that fetches 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-cooler/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-cooler/5", "reject": [Function], "resolve": [Function], }, diff --git a/packages/react/src/hooks/__tests__/__snapshots__/useSuspense.web.tsx.snap b/packages/react/src/hooks/__tests__/__snapshots__/useSuspense.web.tsx.snap index f37650bc7ea0..43b1bf0d9fe2 100644 --- a/packages/react/src/hooks/__tests__/__snapshots__/useSuspense.web.tsx.snap +++ b/packages/react/src/hooks/__tests__/__snapshots__/useSuspense.web.tsx.snap @@ -110,14 +110,14 @@ First three members: []] exports[`useSuspense() should dispatch an action that fetches 1`] = ` { + "args": [ + { + "id": 5, + }, + ], "endpoint": [Function], + "key": "GET http://test.com/article-cooler/5", "meta": { - "args": [ - { - "id": 5, - }, - ], - "key": "GET http://test.com/article-cooler/5", "reject": [Function], "resolve": [Function], }, diff --git a/packages/react/src/hooks/__tests__/useFetch.web.tsx b/packages/react/src/hooks/__tests__/useFetch.web.tsx index b12c40de12ee..cf500b22c59f 100644 --- a/packages/react/src/hooks/__tests__/useFetch.web.tsx +++ b/packages/react/src/hooks/__tests__/useFetch.web.tsx @@ -39,7 +39,7 @@ async function testDispatchFetch( delete call[0]?.meta?.promise; expect(call[0]).toMatchSnapshot(); const action = call[0]; - const res = await action.endpoint(...action.meta.args); + const res = await action.endpoint(...action.args); expect(res).toEqual(payloads[i]); i++; } diff --git a/packages/react/src/hooks/__tests__/useSuspense.web.tsx b/packages/react/src/hooks/__tests__/useSuspense.web.tsx index b139bec35e27..4d371bf5fd46 100644 --- a/packages/react/src/hooks/__tests__/useSuspense.web.tsx +++ b/packages/react/src/hooks/__tests__/useSuspense.web.tsx @@ -72,7 +72,7 @@ async function testDispatchFetch( delete call[0]?.meta?.promise; expect(call[0]).toMatchSnapshot(); const action: FetchAction = call[0] as any; - const res = await action.endpoint(...action.meta.args); + const res = await action.endpoint(...action.args); expect(res).toEqual(payloads[i]); i++; } diff --git a/packages/react/src/internal.ts b/packages/react/src/internal.ts index e029905f9b8a..506cc384ba13 100644 --- a/packages/react/src/internal.ts +++ b/packages/react/src/internal.ts @@ -1,6 +1,6 @@ import { __INTERNAL__ } from '@data-client/core'; -export { createReducer, applyManager } from '@data-client/core'; +export { createReducer, applyManager, actions } from '@data-client/core'; export { default as useCacheState } from './hooks/useCacheState.js'; diff --git a/packages/test/src/createControllerInterceptor.tsx b/packages/test/src/createControllerInterceptor.tsx index 82c290f073ff..348b6b78e620 100644 --- a/packages/test/src/createControllerInterceptor.tsx +++ b/packages/test/src/createControllerInterceptor.tsx @@ -14,7 +14,7 @@ export function createControllerInterceptor( const dispatchInterceptor = function (action: ActionTypes) { if (action.type === actionTypes.FETCH_TYPE) { // eslint-disable-next-line prefer-const - let { key, args } = action.meta; + let { key, args } = action; let fixture: Fixture | Interceptor | undefined; if (Object.hasOwn(fixtureMap, key)) { fixture = fixtureMap[key]; @@ -124,7 +124,7 @@ export function createControllerInterceptor( ); } } else if (action.type === actionTypes.SUBSCRIBE_TYPE) { - const { key } = action.meta; + const { key } = action; if (Object.hasOwn(fixtureMap, key)) { return Promise.resolve(); } diff --git a/website/src/components/Playground/editor-types/@data-client/core.d.ts b/website/src/components/Playground/editor-types/@data-client/core.d.ts index ddb10d09636e..17ee4431682b 100644 --- a/website/src/components/Playground/editor-types/@data-client/core.d.ts +++ b/website/src/components/Playground/editor-types/@data-client/core.d.ts @@ -283,74 +283,73 @@ type EndpointAndUpdate = EndpointInterface & { type EndpointDefault = EndpointInterface & { update?: EndpointUpdateFunction; }; -interface SetMeta { - args: readonly any[]; - fetchedAt: number; - date: number; - expiresAt: number; +/** General meta-data for operators */ +interface ActionMeta { + readonly fetchedAt: number; + readonly date: number; + readonly expiresAt: number; } +/** Action for Controller.set() */ interface SetAction { type: typeof SET_TYPE; schema: S; - meta: SetMeta; + args: readonly any[]; + meta: ActionMeta; value: {} | ((previousValue: Denormalize) => {}); } -interface SetResponseMeta { +interface SetResponseActionBase = EndpointDefault> { + type: typeof SET_RESPONSE_TYPE; + endpoint: E; args: readonly any[]; key: string; - fetchedAt: number; - date: number; - expiresAt: number; + meta: ActionMeta; } -interface SetResponseActionSuccess = EndpointDefault> { - type: typeof SET_RESPONSE_TYPE; - endpoint: E; - meta: SetResponseMeta; +interface SetResponseActionSuccess = EndpointDefault> extends SetResponseActionBase { response: ResolveType; error?: false; } -interface SetResponseActionError = EndpointDefault> { - type: typeof SET_RESPONSE_TYPE; - endpoint: E; - meta: SetResponseMeta; +interface SetResponseActionError = EndpointDefault> extends SetResponseActionBase { response: UnknownError; error: true; } +/** Action for Controller.setResponse() */ type SetResponseAction = EndpointDefault> = SetResponseActionSuccess | SetResponseActionError; -interface FetchMeta { - args: A; - key: string; +interface FetchMeta { + fetchedAt: number; resolve: (value?: any | PromiseLike) => void; reject: (reason?: any) => void; promise: PromiseLike; - fetchedAt: number; } +/** Action for Controller.fetch() */ interface FetchAction = EndpointDefault> { type: typeof FETCH_TYPE; endpoint: E; - meta: FetchMeta]>; + args: readonly [...Parameters]; + key: string; + meta: FetchMeta; } +/** Action for Endpoint.getOptimisticResponse() */ interface OptimisticAction = EndpointDefault> { type: typeof OPTIMISTIC_TYPE; endpoint: E; - meta: SetResponseMeta; + args: readonly any[]; + key: string; + meta: ActionMeta; error?: false; } +/** Action for Controller.subscribe() */ interface SubscribeAction = EndpointDefault> { type: typeof SUBSCRIBE_TYPE; endpoint: E; - meta: { - args: readonly any[]; - key: string; - }; + args: readonly any[]; + key: string; } +/** Action for Controller.unsubscribe() */ interface UnsubscribeAction = EndpointDefault> { type: typeof UNSUBSCRIBE_TYPE; endpoint: E; - meta: { - args: readonly any[]; - key: string; - }; + args: readonly any[]; + key: string; } interface ExpireAllAction { type: typeof EXPIREALL_TYPE; @@ -362,9 +361,7 @@ interface InvalidateAllAction { } interface InvalidateAction { type: typeof INVALIDATE_TYPE; - meta: { - key: string; - }; + key: string; } interface ResetAction { type: typeof RESET_TYPE; @@ -403,9 +400,9 @@ interface State { readonly meta: { readonly [key: string]: { readonly date: number; - readonly error?: ErrorTypes; readonly expiresAt: number; readonly prevExpiresAt?: number; + readonly error?: ErrorTypes; readonly invalidated?: boolean; readonly errorPolicy?: 'hard' | 'soft' | undefined; }; @@ -413,16 +410,15 @@ interface State { readonly entityMeta: { readonly [entityKey: string]: { readonly [pk: string]: { + readonly fetchedAt: number; readonly date: number; readonly expiresAt: number; - readonly fetchedAt: number; }; }; }; readonly optimistic: (SetResponseAction | OptimisticAction)[]; readonly lastReset: number; } - interface Manager { getMiddleware(): Middleware$2; cleanup(): void; @@ -697,20 +693,12 @@ interface MiddlewareAPI = Reducer> { } type Middleware$1 = >({ dispatch, }: MiddlewareAPI) => (next: Dispatch$1) => Dispatch$1; -/** - * Requesting a fetch to begin - */ -declare function createFetch; -}>(endpoint: E, { args }: { +declare function createSubscription(endpoint: E, { args }: { args: readonly [...Parameters]; -}): FetchAction; - -declare function createSet(schema: S, { args, fetchedAt, value, }: { - args: readonly [...SchemaArgs]; - value: {} | ((previousValue: Denormalize) => {}); - fetchedAt?: number; -}): SetAction; +}): SubscribeAction; +declare function createUnsubscription(endpoint: E, { args }: { + args: readonly [...Parameters]; +}): UnsubscribeAction; declare function createSetResponse; @@ -729,6 +717,66 @@ declare function createSetResponse; +declare function createSet(schema: S, { args, fetchedAt, value, }: { + args: readonly [...SchemaArgs]; + value: {} | ((previousValue: Denormalize) => {}); + fetchedAt?: number; +}): SetAction; + +declare function createReset(): ResetAction; + +declare function createOptimistic; +}>(endpoint: E, args: readonly [...Parameters], fetchedAt: number): OptimisticAction; + +declare function createMeta(expiryLength: number, fetchedAt?: number): ActionMeta; + +declare function createInvalidateAll(testKey: (key: string) => boolean): InvalidateAllAction; + +declare function createInvalidate(endpoint: E, { args }: { + args: readonly [...Parameters]; +}): InvalidateAction; + +/** + * Requesting a fetch to begin + */ +declare function createFetch; +}>(endpoint: E, { args }: { + args: readonly [...Parameters]; +}): FetchAction; + +declare function createExpireAll(testKey: (key: string) => boolean): ExpireAllAction; + +//# sourceMappingURL=index.d.ts.map + +declare const index_d_createSubscription: typeof createSubscription; +declare const index_d_createUnsubscription: typeof createUnsubscription; +declare const index_d_createSetResponse: typeof createSetResponse; +declare const index_d_createSet: typeof createSet; +declare const index_d_createReset: typeof createReset; +declare const index_d_createOptimistic: typeof createOptimistic; +declare const index_d_createMeta: typeof createMeta; +declare const index_d_createInvalidateAll: typeof createInvalidateAll; +declare const index_d_createInvalidate: typeof createInvalidate; +declare const index_d_createFetch: typeof createFetch; +declare const index_d_createExpireAll: typeof createExpireAll; +declare namespace index_d { + export { + index_d_createSubscription as createSubscription, + index_d_createUnsubscription as createUnsubscription, + index_d_createSetResponse as createSetResponse, + index_d_createSet as createSet, + index_d_createReset as createReset, + index_d_createOptimistic as createOptimistic, + index_d_createMeta as createMeta, + index_d_createInvalidateAll as createInvalidateAll, + index_d_createInvalidate as createInvalidate, + index_d_createFetch as createFetch, + index_d_createExpireAll as createExpireAll, + }; +} + interface ConnectionListener { isOnline: () => boolean; addOnlineListener: (handler: () => void) => void; @@ -1077,4 +1125,4 @@ declare class DevToolsManager implements Manager { getMiddleware(): Middleware; } -export { AbstractInstanceType, ActionTypes, ConnectionListener, Controller, DataClientDispatch, DefaultConnectionListener, Denormalize, DenormalizeNullable, DevToolsConfig, DevToolsManager, Dispatch$1 as Dispatch, EndpointExtraOptions, EndpointInterface, EndpointUpdateFunction, EntityInterface, ErrorTypes, ExpireAllAction, ExpiryStatus, FetchAction, FetchFunction, FetchMeta, GCAction, GenericDispatch, InvalidateAction, InvalidateAllAction, LogoutManager, Manager, Middleware$2 as Middleware, MiddlewareAPI$1 as MiddlewareAPI, NI, NetworkError, NetworkManager, Normalize, NormalizeNullable, OptimisticAction, PK, PollingSubscription, Queryable, ResetAction, ResetError, ResolveType, ResultEntry, Schema, SchemaArgs, SetAction, SetMeta, SetResponseAction, SetResponseActionError, SetResponseActionSuccess, SetResponseMeta, State, SubscribeAction, SubscriptionManager, UnknownError, UnsubscribeAction, UpdateFunction, internal_d as __INTERNAL__, actionTypes_d as actionTypes, applyManager, createFetch, createReducer, createSet, createSetResponse, initialState }; +export { AbstractInstanceType, ActionMeta, ActionTypes, ConnectionListener, Controller, DataClientDispatch, DefaultConnectionListener, Denormalize, DenormalizeNullable, DevToolsConfig, DevToolsManager, Dispatch$1 as Dispatch, EndpointExtraOptions, EndpointInterface, EndpointUpdateFunction, EntityInterface, ErrorTypes, ExpireAllAction, ExpiryStatus, FetchAction, FetchFunction, FetchMeta, GCAction, GenericDispatch, InvalidateAction, InvalidateAllAction, LogoutManager, Manager, Middleware$2 as Middleware, MiddlewareAPI$1 as MiddlewareAPI, NI, NetworkError, NetworkManager, Normalize, NormalizeNullable, OptimisticAction, PK, PollingSubscription, Queryable, ResetAction, ResetError, ResolveType, ResultEntry, Schema, SchemaArgs, SetAction, SetResponseAction, SetResponseActionBase, SetResponseActionError, SetResponseActionSuccess, State, SubscribeAction, SubscriptionManager, UnknownError, UnsubscribeAction, UpdateFunction, internal_d as __INTERNAL__, actionTypes_d as actionTypes, index_d as actions, applyManager, createReducer, initialState }; diff --git a/website/src/components/Playground/editor-types/@data-client/normalizr.d.ts b/website/src/components/Playground/editor-types/@data-client/normalizr.d.ts index e9afaa1668cc..ba4c9d44acf9 100644 --- a/website/src/components/Playground/editor-types/@data-client/normalizr.d.ts +++ b/website/src/components/Playground/editor-types/@data-client/normalizr.d.ts @@ -165,20 +165,19 @@ interface StoreData { entityMeta: { readonly [entityKey: string]: { readonly [pk: string]: { + readonly fetchedAt: number; readonly date: number; readonly expiresAt: number; - readonly fetchedAt: number; }; }; }; } interface NormalizeMeta { - expiresAt?: number; - date?: number; - fetchedAt?: number; - args?: readonly any[]; + expiresAt: number; + date: number; + fetchedAt: number; } -declare const normalize: | undefined> = Record>, R = NormalizeNullable>(schema: S | undefined, input: any, { date, expiresAt, fetchedAt, args, }?: NormalizeMeta, { entities, indexes, entityMeta }?: StoreData) => NormalizedSchema; +declare const normalize: | undefined> = Record>, R = NormalizeNullable>(schema: S | undefined, input: any, args?: readonly any[], { entities, indexes, entityMeta }?: StoreData, meta?: NormalizeMeta) => NormalizedSchema; interface EntityCache { [key: string]: { diff --git a/website/src/components/Playground/editor-types/@data-client/react.d.ts b/website/src/components/Playground/editor-types/@data-client/react.d.ts index 001924f614da..6ca5e1b5c5c3 100644 --- a/website/src/components/Playground/editor-types/@data-client/react.d.ts +++ b/website/src/components/Playground/editor-types/@data-client/react.d.ts @@ -1,5 +1,5 @@ import * as _data_client_core from '@data-client/core'; -import { NetworkManager, Manager, State, Controller, EndpointInterface as EndpointInterface$1, FetchFunction as FetchFunction$1, Schema as Schema$1, ResolveType as ResolveType$1, Denormalize as Denormalize$1, DenormalizeNullable as DenormalizeNullable$1, Queryable as Queryable$1, NI, SchemaArgs, NetworkError as NetworkError$1, UnknownError as UnknownError$1, ErrorTypes as ErrorTypes$2, __INTERNAL__, createReducer, applyManager } from '@data-client/core'; +import { NetworkManager, Manager, State, Controller, EndpointInterface as EndpointInterface$1, FetchFunction as FetchFunction$1, Schema as Schema$1, ResolveType as ResolveType$1, Denormalize as Denormalize$1, DenormalizeNullable as DenormalizeNullable$1, Queryable as Queryable$1, NI, SchemaArgs, NetworkError as NetworkError$1, UnknownError as UnknownError$1, ErrorTypes as ErrorTypes$2, __INTERNAL__, createReducer, applyManager, actions } from '@data-client/core'; export { AbstractInstanceType, ActionTypes, Controller, DataClientDispatch, DefaultConnectionListener, Denormalize, DenormalizeNullable, DevToolsManager, Dispatch, EndpointExtraOptions, EndpointInterface, ErrorTypes, ExpiryStatus, FetchAction, FetchFunction, GenericDispatch, InvalidateAction, LogoutManager, Manager, Middleware, MiddlewareAPI, NetworkError, Normalize, NormalizeNullable, PK, PollingSubscription, ResetAction, ResolveType, Schema, SetAction, SetResponseAction, State, SubscribeAction, SubscriptionManager, UnknownError, UnsubscribeAction, UpdateFunction, actionTypes } from '@data-client/core'; import * as react_jsx_runtime from 'react/jsx-runtime'; import React, { JSX, Context } from 'react'; @@ -403,6 +403,7 @@ declare const internal_d_INVALID: typeof INVALID; declare const internal_d_MemoCache: typeof MemoCache; declare const internal_d_createReducer: typeof createReducer; declare const internal_d_applyManager: typeof applyManager; +declare const internal_d_actions: typeof actions; declare const internal_d_useCacheState: typeof useCacheState; declare namespace internal_d { export { @@ -411,6 +412,7 @@ declare namespace internal_d { internal_d_MemoCache as MemoCache, internal_d_createReducer as createReducer, internal_d_applyManager as applyManager, + internal_d_actions as actions, internal_d_useCacheState as useCacheState, }; }