@data-client/core 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/dist/index.js +133 -409
  2. package/dist/index.umd.min.js +1 -1
  3. package/dist/next.js +61 -101
  4. package/legacy/actionTypes.js +2 -2
  5. package/legacy/controller/Controller.js +276 -6
  6. package/legacy/controller/createFetch.js +3 -14
  7. package/legacy/controller/createInvalidate.js +1 -1
  8. package/legacy/controller/createInvalidateAll.js +1 -1
  9. package/legacy/controller/createOptimistic.js +1 -7
  10. package/legacy/controller/createReset.js +1 -1
  11. package/legacy/controller/createSet.js +31 -0
  12. package/legacy/controller/createSubscription.js +3 -7
  13. package/legacy/index.js +2 -5
  14. package/legacy/internal.js +2 -2
  15. package/legacy/manager/DevtoolsManager.js +2 -2
  16. package/legacy/manager/LogoutManager.js +2 -2
  17. package/legacy/manager/NetworkManager.js +28 -59
  18. package/legacy/manager/PollingSubscription.js +18 -27
  19. package/legacy/manager/SubscriptionManager.js +16 -42
  20. package/legacy/middlewareTypes.js +1 -1
  21. package/legacy/newActions.js +1 -1
  22. package/legacy/next/index.js +3 -3
  23. package/legacy/state/reducer/createReducer.js +2 -6
  24. package/legacy/state/reducer/fetchReducer.js +3 -13
  25. package/legacy/state/reducer/invalidateReducer.js +1 -1
  26. package/legacy/state/reducer/setReducer.js +9 -16
  27. package/legacy/types.js +2 -6
  28. package/lib/actionTypes.d.ts +1 -0
  29. package/lib/actionTypes.d.ts.map +1 -1
  30. package/lib/actionTypes.js +2 -2
  31. package/lib/controller/Controller.d.ts +126 -6
  32. package/lib/controller/Controller.d.ts.map +1 -1
  33. package/lib/controller/Controller.js +276 -6
  34. package/lib/controller/createFetch.d.ts +2 -2
  35. package/lib/controller/createFetch.d.ts.map +1 -1
  36. package/lib/controller/createFetch.js +3 -14
  37. package/lib/controller/createInvalidate.d.ts +1 -1
  38. package/lib/controller/createInvalidate.d.ts.map +1 -1
  39. package/lib/controller/createInvalidate.js +1 -1
  40. package/lib/controller/createInvalidateAll.d.ts +1 -1
  41. package/lib/controller/createInvalidateAll.d.ts.map +1 -1
  42. package/lib/controller/createInvalidateAll.js +1 -1
  43. package/lib/controller/createOptimistic.d.ts +2 -2
  44. package/lib/controller/createOptimistic.d.ts.map +1 -1
  45. package/lib/controller/createOptimistic.js +1 -7
  46. package/lib/controller/createReset.d.ts +1 -1
  47. package/lib/controller/createReset.d.ts.map +1 -1
  48. package/lib/controller/createReset.js +1 -1
  49. package/lib/controller/{createReceive.d.ts → createSet.d.ts} +6 -6
  50. package/lib/controller/createSet.d.ts.map +1 -0
  51. package/lib/controller/createSet.js +31 -0
  52. package/lib/controller/createSubscription.d.ts +3 -3
  53. package/lib/controller/createSubscription.d.ts.map +1 -1
  54. package/lib/controller/createSubscription.js +3 -7
  55. package/lib/index.d.ts +2 -6
  56. package/lib/index.d.ts.map +1 -1
  57. package/lib/index.js +2 -5
  58. package/lib/internal.d.ts +1 -1
  59. package/lib/internal.d.ts.map +1 -1
  60. package/lib/internal.js +2 -2
  61. package/lib/manager/DevtoolsManager.d.ts +1 -1
  62. package/lib/manager/DevtoolsManager.js +2 -2
  63. package/lib/manager/LogoutManager.d.ts +4 -5
  64. package/lib/manager/LogoutManager.d.ts.map +1 -1
  65. package/lib/manager/LogoutManager.js +2 -2
  66. package/lib/manager/NetworkManager.d.ts +4 -5
  67. package/lib/manager/NetworkManager.d.ts.map +1 -1
  68. package/lib/manager/NetworkManager.js +28 -61
  69. package/lib/manager/PollingSubscription.d.ts +9 -9
  70. package/lib/manager/PollingSubscription.d.ts.map +1 -1
  71. package/lib/manager/PollingSubscription.js +18 -27
  72. package/lib/manager/SubscriptionManager.d.ts +10 -15
  73. package/lib/manager/SubscriptionManager.d.ts.map +1 -1
  74. package/lib/manager/SubscriptionManager.js +16 -42
  75. package/lib/middlewareTypes.d.ts +5 -5
  76. package/lib/middlewareTypes.d.ts.map +1 -1
  77. package/lib/middlewareTypes.js +1 -1
  78. package/lib/newActions.d.ts +26 -18
  79. package/lib/newActions.d.ts.map +1 -1
  80. package/lib/newActions.js +1 -1
  81. package/lib/next/index.d.ts +2 -2
  82. package/lib/next/index.d.ts.map +1 -1
  83. package/lib/next/index.js +3 -3
  84. package/lib/state/reducer/createReducer.d.ts.map +1 -1
  85. package/lib/state/reducer/createReducer.js +2 -6
  86. package/lib/state/reducer/fetchReducer.d.ts +1 -2
  87. package/lib/state/reducer/fetchReducer.d.ts.map +1 -1
  88. package/lib/state/reducer/fetchReducer.js +3 -14
  89. package/lib/state/reducer/invalidateReducer.d.ts +3 -4
  90. package/lib/state/reducer/invalidateReducer.d.ts.map +1 -1
  91. package/lib/state/reducer/invalidateReducer.js +1 -1
  92. package/lib/state/reducer/setReducer.d.ts +2 -38
  93. package/lib/state/reducer/setReducer.d.ts.map +1 -1
  94. package/lib/state/reducer/setReducer.js +9 -17
  95. package/lib/types.d.ts +9 -30
  96. package/lib/types.d.ts.map +1 -1
  97. package/lib/types.js +2 -6
  98. package/package.json +3 -3
  99. package/src/actionTypes.ts +1 -1
  100. package/src/controller/Controller.ts +491 -10
  101. package/src/controller/createFetch.ts +4 -19
  102. package/src/controller/createInvalidate.ts +1 -1
  103. package/src/controller/createInvalidateAll.ts +1 -1
  104. package/src/controller/createOptimistic.ts +3 -9
  105. package/src/controller/createReset.ts +1 -1
  106. package/src/controller/{createReceive.ts → createSet.ts} +9 -17
  107. package/src/controller/createSubscription.ts +3 -10
  108. package/src/index.ts +2 -16
  109. package/src/internal.ts +1 -1
  110. package/src/manager/DevtoolsManager.ts +1 -1
  111. package/src/manager/LogoutManager.ts +4 -5
  112. package/src/manager/NetworkManager.ts +31 -80
  113. package/src/manager/PollingSubscription.ts +26 -27
  114. package/src/manager/SubscriptionManager.ts +22 -54
  115. package/src/manager/__tests__/__snapshots__/pollingSubscription.ts.snap +10 -8
  116. package/src/manager/__tests__/logoutManager.ts +5 -5
  117. package/src/manager/__tests__/manager.ts +2 -4
  118. package/src/manager/__tests__/networkManager.ts +8 -42
  119. package/src/manager/__tests__/pollingSubscription.ts +259 -151
  120. package/src/manager/__tests__/subscriptionManager.ts +7 -13
  121. package/src/middlewareTypes.ts +5 -10
  122. package/src/newActions.ts +33 -23
  123. package/src/next/index.ts +2 -2
  124. package/src/state/__tests__/reducer.ts +59 -297
  125. package/src/state/reducer/createReducer.ts +3 -11
  126. package/src/state/reducer/fetchReducer.ts +5 -18
  127. package/src/state/reducer/invalidateReducer.ts +2 -2
  128. package/src/state/reducer/setReducer.ts +10 -22
  129. package/src/types.ts +9 -78
  130. package/ts3.4/actionTypes.d.ts +1 -0
  131. package/ts3.4/controller/Controller.d.ts +168 -6
  132. package/ts3.4/controller/createFetch.d.ts +2 -2
  133. package/ts3.4/controller/createInvalidate.d.ts +1 -1
  134. package/ts3.4/controller/createInvalidateAll.d.ts +1 -1
  135. package/ts3.4/controller/createOptimistic.d.ts +1 -1
  136. package/ts3.4/controller/createReset.d.ts +1 -1
  137. package/ts3.4/controller/{createReceive.d.ts → createSet.d.ts} +6 -6
  138. package/ts3.4/controller/createSubscription.d.ts +3 -3
  139. package/ts3.4/index.d.ts +2 -7
  140. package/ts3.4/internal.d.ts +1 -1
  141. package/ts3.4/manager/DevtoolsManager.d.ts +1 -1
  142. package/ts3.4/manager/LogoutManager.d.ts +4 -5
  143. package/ts3.4/manager/NetworkManager.d.ts +4 -5
  144. package/ts3.4/manager/PollingSubscription.d.ts +9 -9
  145. package/ts3.4/manager/SubscriptionManager.d.ts +10 -15
  146. package/ts3.4/middlewareTypes.d.ts +5 -5
  147. package/ts3.4/newActions.d.ts +26 -18
  148. package/ts3.4/next/index.d.ts +2 -2
  149. package/ts3.4/state/reducer/fetchReducer.d.ts +1 -2
  150. package/ts3.4/state/reducer/invalidateReducer.d.ts +3 -4
  151. package/ts3.4/state/reducer/setReducer.d.ts +2 -38
  152. package/ts3.4/types.d.ts +8 -30
  153. package/legacy/compatibleActions.js +0 -2
  154. package/legacy/controller/BaseController.js +0 -289
  155. package/legacy/controller/createReceive.js +0 -36
  156. package/legacy/endpoint/index.js +0 -2
  157. package/legacy/endpoint/shapes.js +0 -2
  158. package/legacy/endpoint/types.js +0 -2
  159. package/legacy/legacyActions.js +0 -2
  160. package/legacy/next/Controller.js +0 -24
  161. package/legacy/previousActions.js +0 -2
  162. package/legacy/state/applyUpdatersToResults.js +0 -4
  163. package/legacy/state/legacy-actions/createFetch.js +0 -62
  164. package/legacy/state/legacy-actions/createReceive.js +0 -37
  165. package/legacy/state/legacy-actions/createReceiveError.js +0 -28
  166. package/legacy/state/legacy-actions/index.js +0 -4
  167. package/legacy/state/reducerInstance.js +0 -9
  168. package/lib/compatibleActions.d.ts +0 -47
  169. package/lib/compatibleActions.d.ts.map +0 -1
  170. package/lib/compatibleActions.js +0 -2
  171. package/lib/controller/BaseController.d.ts +0 -128
  172. package/lib/controller/BaseController.d.ts.map +0 -1
  173. package/lib/controller/BaseController.js +0 -289
  174. package/lib/controller/createReceive.d.ts.map +0 -1
  175. package/lib/controller/createReceive.js +0 -36
  176. package/lib/endpoint/index.d.ts +0 -3
  177. package/lib/endpoint/index.d.ts.map +0 -1
  178. package/lib/endpoint/index.js +0 -2
  179. package/lib/endpoint/shapes.d.ts +0 -25
  180. package/lib/endpoint/shapes.d.ts.map +0 -1
  181. package/lib/endpoint/shapes.js +0 -2
  182. package/lib/endpoint/types.d.ts +0 -45
  183. package/lib/endpoint/types.d.ts.map +0 -1
  184. package/lib/endpoint/types.js +0 -2
  185. package/lib/legacyActions.d.ts +0 -92
  186. package/lib/legacyActions.d.ts.map +0 -1
  187. package/lib/legacyActions.js +0 -2
  188. package/lib/next/Controller.d.ts +0 -14
  189. package/lib/next/Controller.d.ts.map +0 -1
  190. package/lib/next/Controller.js +0 -24
  191. package/lib/previousActions.d.ts +0 -91
  192. package/lib/previousActions.d.ts.map +0 -1
  193. package/lib/previousActions.js +0 -2
  194. package/lib/state/applyUpdatersToResults.d.ts +0 -13
  195. package/lib/state/applyUpdatersToResults.d.ts.map +0 -1
  196. package/lib/state/applyUpdatersToResults.js +0 -7
  197. package/lib/state/legacy-actions/createFetch.d.ts +0 -19
  198. package/lib/state/legacy-actions/createFetch.d.ts.map +0 -1
  199. package/lib/state/legacy-actions/createFetch.js +0 -62
  200. package/lib/state/legacy-actions/createReceive.d.ts +0 -14
  201. package/lib/state/legacy-actions/createReceive.d.ts.map +0 -1
  202. package/lib/state/legacy-actions/createReceive.js +0 -37
  203. package/lib/state/legacy-actions/createReceiveError.d.ts +0 -9
  204. package/lib/state/legacy-actions/createReceiveError.d.ts.map +0 -1
  205. package/lib/state/legacy-actions/createReceiveError.js +0 -28
  206. package/lib/state/legacy-actions/index.d.ts +0 -4
  207. package/lib/state/legacy-actions/index.d.ts.map +0 -1
  208. package/lib/state/legacy-actions/index.js +0 -4
  209. package/lib/state/reducerInstance.d.ts +0 -7
  210. package/lib/state/reducerInstance.d.ts.map +0 -1
  211. package/lib/state/reducerInstance.js +0 -9
  212. package/src/compatibleActions.ts +0 -96
  213. package/src/controller/BaseController.ts +0 -508
  214. package/src/endpoint/index.ts +0 -14
  215. package/src/endpoint/shapes.ts +0 -53
  216. package/src/endpoint/types.ts +0 -72
  217. package/src/legacyActions.ts +0 -163
  218. package/src/manager/__tests__/__snapshots__/pollingSubscription-endpoint.ts.snap +0 -49
  219. package/src/manager/__tests__/networkManager-legacy.ts +0 -394
  220. package/src/manager/__tests__/pollingSubscription-endpoint.ts +0 -423
  221. package/src/next/Controller.ts +0 -39
  222. package/src/previousActions.ts +0 -159
  223. package/src/state/__tests__/applyUpdatersToResults.ts +0 -40
  224. package/src/state/applyUpdatersToResults.ts +0 -29
  225. package/src/state/legacy-actions/createFetch.ts +0 -95
  226. package/src/state/legacy-actions/createReceive.ts +0 -68
  227. package/src/state/legacy-actions/createReceiveError.ts +0 -43
  228. package/src/state/legacy-actions/index.ts +0 -3
  229. package/src/state/reducerInstance.ts +0 -14
  230. package/ts3.4/compatibleActions.d.ts +0 -47
  231. package/ts3.4/controller/BaseController.d.ts +0 -170
  232. package/ts3.4/endpoint/index.d.ts +0 -3
  233. package/ts3.4/endpoint/shapes.d.ts +0 -25
  234. package/ts3.4/endpoint/types.d.ts +0 -45
  235. package/ts3.4/legacyActions.d.ts +0 -95
  236. package/ts3.4/next/Controller.d.ts +0 -14
  237. package/ts3.4/previousActions.d.ts +0 -94
  238. package/ts3.4/state/applyUpdatersToResults.d.ts +0 -13
  239. package/ts3.4/state/legacy-actions/createFetch.d.ts +0 -19
  240. package/ts3.4/state/legacy-actions/createReceive.d.ts +0 -14
  241. package/ts3.4/state/legacy-actions/createReceiveError.d.ts +0 -9
  242. package/ts3.4/state/legacy-actions/index.d.ts +0 -4
  243. package/ts3.4/state/reducerInstance.d.ts +0 -7
@@ -1,15 +1,97 @@
1
- import type { EndpointInterface } from '@data-client/normalizr';
1
+ import type {
2
+ ErrorTypes,
3
+ SnapshotInterface,
4
+ DenormalizeCache,
5
+ Schema,
6
+ Denormalize,
7
+ } from '@data-client/normalizr';
8
+ import {
9
+ WeakEntityMap,
10
+ ExpiryStatus,
11
+ EndpointInterface,
12
+ FetchFunction,
13
+ ResolveType,
14
+ DenormalizeNullable,
15
+ Path,
16
+ denormalizeCached,
17
+ isEntity,
18
+ denormalize,
19
+ } from '@data-client/normalizr';
20
+ import { inferResults, validateInference } from '@data-client/normalizr';
2
21
 
3
- import BaseController, {
4
- CompatibleDispatch,
5
- GenericDispatch,
6
- } from './BaseController.js';
7
22
  import createFetch from './createFetch.js';
23
+ import createInvalidate from './createInvalidate.js';
24
+ import createInvalidateAll from './createInvalidateAll.js';
25
+ import createReset from './createReset.js';
26
+ import createSet from './createSet.js';
27
+ import {
28
+ createUnsubscription,
29
+ createSubscription,
30
+ } from './createSubscription.js';
8
31
  import type { EndpointUpdateFunction } from './types.js';
32
+ import { initialState } from '../state/reducer/createReducer.js';
33
+ import selectMeta from '../state/selectMeta.js';
34
+ import type { ActionTypes, State } from '../types.js';
9
35
 
36
+ export type GenericDispatch = (value: any) => Promise<void>;
37
+ export type DataClientDispatch = (value: ActionTypes) => Promise<void>;
38
+
39
+ interface ConstructorProps<D extends GenericDispatch = DataClientDispatch> {
40
+ dispatch?: D;
41
+ getState?: () => State<unknown>;
42
+ globalCache?: DenormalizeCache;
43
+ }
44
+
45
+ const unsetDispatch = (action: unknown): Promise<void> => {
46
+ throw new Error(
47
+ `Dispatching while constructing your middleware is not allowed. ` +
48
+ `Other middleware would not be applied to this dispatch.`,
49
+ );
50
+ };
51
+ const unsetState = (): State<unknown> => {
52
+ // This is only the value until it is set by the CacheProvider
53
+ /* istanbul ignore next */
54
+ return initialState;
55
+ };
56
+
57
+ /**
58
+ * Imperative control of Rest Hooks store
59
+ * @see https://resthooks.io/docs/api/Controller
60
+ */
10
61
  export default class Controller<
11
- D extends GenericDispatch = CompatibleDispatch,
12
- > extends BaseController<D> {
62
+ D extends GenericDispatch = DataClientDispatch,
63
+ > {
64
+ /**
65
+ * Dispatches an action to Rest Hooks reducer.
66
+ *
67
+ * @see https://resthooks.io/docs/api/Controller#dispatch
68
+ */
69
+ declare readonly dispatch: D;
70
+ /**
71
+ * Gets the latest state snapshot that is fully committed.
72
+ *
73
+ * This can be useful for imperative use-cases like event handlers.
74
+ * This should *not* be used to render; instead useSuspense() or useCache()
75
+ * @see https://resthooks.io/docs/api/Controller#getState
76
+ */
77
+ declare readonly getState: () => State<unknown>;
78
+ declare readonly globalCache: DenormalizeCache;
79
+
80
+ constructor({
81
+ dispatch = unsetDispatch as any,
82
+ getState = unsetState,
83
+ globalCache = {
84
+ entities: {},
85
+ results: {},
86
+ },
87
+ }: ConstructorProps<D> = {}) {
88
+ this.dispatch = dispatch;
89
+ this.getState = getState;
90
+ this.globalCache = globalCache;
91
+ }
92
+
93
+ /*************** Action Dispatchers ***************/
94
+
13
95
  /**
14
96
  * Fetches the endpoint with given args, updating the Rest Hooks cache with the response or error upon completion.
15
97
  * @see https://resthooks.io/docs/api/Controller#fetch
@@ -19,14 +101,413 @@ export default class Controller<
19
101
  >(
20
102
  endpoint: E,
21
103
  ...args: readonly [...Parameters<E>]
22
- ): ReturnType<E> => {
104
+ ): E['schema'] extends undefined | null
105
+ ? ReturnType<E>
106
+ : Promise<Denormalize<E['schema']>> => {
23
107
  const action = createFetch(endpoint, {
24
108
  args,
25
109
  });
26
110
  this.dispatch(action);
27
111
 
28
- return action.meta.promise as ReturnType<E>;
112
+ if (endpoint.schema) {
113
+ return action.meta.promise.then(input =>
114
+ denormalize(input, endpoint.schema, {}, args),
115
+ ) as any;
116
+ }
117
+ return action.meta.promise as any;
118
+ };
119
+
120
+ /**
121
+ * Forces refetching and suspense on useSuspense with the same Endpoint and parameters.
122
+ * @see https://resthooks.io/docs/api/Controller#invalidate
123
+ */
124
+ invalidate = <E extends EndpointInterface>(
125
+ endpoint: E,
126
+ ...args: readonly [...Parameters<E>] | readonly [null]
127
+ ): Promise<void> =>
128
+ args[0] !== null
129
+ ? this.dispatch(
130
+ createInvalidate(endpoint, {
131
+ args: args as readonly [...Parameters<E>],
132
+ }),
133
+ )
134
+ : Promise.resolve();
135
+
136
+ /**
137
+ * Forces refetching and suspense on useSuspense on all matching endpoint result keys.
138
+ * @see https://resthooks.io/docs/api/Controller#invalidateAll
139
+ */
140
+ invalidateAll = (options: { testKey: (key: string) => boolean }) =>
141
+ this.dispatch(createInvalidateAll((key: string) => options.testKey(key)));
142
+
143
+ /**
144
+ * Resets the entire Rest Hooks cache. All inflight requests will not resolve.
145
+ * @see https://resthooks.io/docs/api/Controller#resetEntireStore
146
+ */
147
+ resetEntireStore = (): Promise<void> => this.dispatch(createReset());
148
+
149
+ /**
150
+ * Stores response in cache for given Endpoint and args.
151
+ * @see https://resthooks.io/docs/api/Controller#set
152
+ */
153
+ setResponse = <
154
+ E extends EndpointInterface & {
155
+ update?: EndpointUpdateFunction<E>;
156
+ },
157
+ >(
158
+ endpoint: E,
159
+ ...rest: readonly [...Parameters<E>, any]
160
+ ): Promise<void> => {
161
+ const response: ResolveType<E> = rest[rest.length - 1];
162
+ const action = createSet(endpoint, {
163
+ args: rest.slice(0, rest.length - 1) as Parameters<E>,
164
+ response,
165
+ });
166
+ return this.dispatch(action);
167
+ };
168
+
169
+ /**
170
+ * @deprecated use https://resthooks.io/docs/api/Controller#setResponse instead
171
+ */
172
+ /* istanbul ignore next */ receive = <
173
+ E extends EndpointInterface & {
174
+ update?: EndpointUpdateFunction<E>;
175
+ },
176
+ >(
177
+ endpoint: E,
178
+ ...rest: readonly [...Parameters<E>, any]
179
+ ): Promise<void> => {
180
+ /* istanbul ignore next */
181
+ return this.setResponse(endpoint, ...rest);
182
+ };
183
+
184
+ /**
185
+ * Stores the result of Endpoint and args as the error provided.
186
+ * @see https://resthooks.io/docs/api/Controller#setError
187
+ */
188
+ setError = <
189
+ E extends EndpointInterface & {
190
+ update?: EndpointUpdateFunction<E>;
191
+ },
192
+ >(
193
+ endpoint: E,
194
+ ...rest: readonly [...Parameters<E>, Error]
195
+ ): Promise<void> => {
196
+ const response: Error = rest[rest.length - 1];
197
+ const action = createSet(endpoint, {
198
+ args: rest.slice(0, rest.length - 1) as Parameters<E>,
199
+ response,
200
+ error: true,
201
+ });
202
+ return this.dispatch(action);
203
+ };
204
+
205
+ /**
206
+ * Another name for setError
207
+ * @deprecated use https://resthooks.io/docs/api/Controller#setError instead
208
+ */
209
+ /* istanbul ignore next */ receiveError = <
210
+ E extends EndpointInterface & {
211
+ update?: EndpointUpdateFunction<E>;
212
+ },
213
+ >(
214
+ endpoint: E,
215
+ ...rest: readonly [...Parameters<E>, Error]
216
+ ): Promise<void> => {
217
+ /* istanbul ignore next */
218
+ return this.setError(endpoint, ...rest);
219
+ };
220
+
221
+ /**
222
+ * Resolves an inflight fetch. `fetchedAt` should `fetch`'s `createdAt`
223
+ * @see https://resthooks.io/docs/api/Controller#resolve
224
+ */
225
+ resolve = <
226
+ E extends EndpointInterface & {
227
+ update?: EndpointUpdateFunction<E>;
228
+ },
229
+ >(
230
+ endpoint: E,
231
+ meta:
232
+ | {
233
+ args: readonly [...Parameters<E>];
234
+ response: Error;
235
+ fetchedAt: number;
236
+ error: true;
237
+ }
238
+ | {
239
+ args: readonly [...Parameters<E>];
240
+ response: any;
241
+ fetchedAt: number;
242
+ error?: false;
243
+ },
244
+ ): Promise<void> => {
245
+ return this.dispatch(createSet(endpoint, meta as any));
246
+ };
247
+
248
+ /**
249
+ * Marks a new subscription to a given Endpoint.
250
+ * @see https://resthooks.io/docs/api/Controller#subscribe
251
+ */
252
+ subscribe = <
253
+ E extends EndpointInterface<
254
+ FetchFunction,
255
+ Schema | undefined,
256
+ undefined | false
257
+ >,
258
+ >(
259
+ endpoint: E,
260
+ ...args: readonly [...Parameters<E>] | readonly [null]
261
+ ): Promise<void> =>
262
+ args[0] !== null
263
+ ? this.dispatch(
264
+ createSubscription(endpoint, {
265
+ args: args as readonly [...Parameters<E>],
266
+ }),
267
+ )
268
+ : Promise.resolve();
269
+
270
+ /**
271
+ * Marks completion of subscription to a given Endpoint.
272
+ * @see https://resthooks.io/docs/api/Controller#unsubscribe
273
+ */
274
+ unsubscribe = <
275
+ E extends EndpointInterface<
276
+ FetchFunction,
277
+ Schema | undefined,
278
+ undefined | false
279
+ >,
280
+ >(
281
+ endpoint: E,
282
+ ...args: readonly [...Parameters<E>] | readonly [null]
283
+ ): Promise<void> =>
284
+ args[0] !== null
285
+ ? this.dispatch(
286
+ createUnsubscription(endpoint, {
287
+ args: args as readonly [...Parameters<E>],
288
+ }),
289
+ )
290
+ : Promise.resolve();
291
+
292
+ /*************** More ***************/
293
+
294
+ /* TODO:
295
+ abort = <E extends EndpointInterface>(
296
+ endpoint: E,
297
+ ...args: readonly [...Parameters<E>]
298
+ ): Promise<void>
299
+ */
300
+
301
+ /**
302
+ * Gets a snapshot (https://resthooks.io/docs/api/Snapshot)
303
+ * @see https://resthooks.io/docs/api/Controller#snapshot
304
+ */
305
+ snapshot = (state: State<unknown>, fetchedAt?: number): SnapshotInterface => {
306
+ return new Snapshot(this, state, fetchedAt);
307
+ };
308
+
309
+ /**
310
+ * Gets the error, if any, for a given endpoint. Returns undefined for no errors.
311
+ * @see https://resthooks.io/docs/api/Controller#getError
312
+ */
313
+ getError = <
314
+ E extends Pick<EndpointInterface, 'key'>,
315
+ Args extends readonly [...Parameters<E['key']>] | readonly [null],
316
+ >(
317
+ endpoint: E,
318
+ ...rest: [...Args, State<unknown>]
319
+ ): ErrorTypes | undefined => {
320
+ if (rest[0] === null) return;
321
+ const state = rest[rest.length - 1] as State<unknown>;
322
+ // this is typescript generics breaking
323
+ const args: any = rest.slice(0, rest.length - 1) as Parameters<E['key']>;
324
+ const key = endpoint.key(...args);
325
+
326
+ const meta = selectMeta(state, key);
327
+ const results = state.results[key];
328
+
329
+ if (results !== undefined && meta?.errorPolicy === 'soft') return;
330
+
331
+ return meta?.error as any;
29
332
  };
333
+
334
+ /**
335
+ * Gets the (globally referentially stable) response for a given endpoint/args pair from state given.
336
+ * @see https://resthooks.io/docs/api/Controller#getResponse
337
+ */
338
+ getResponse = <
339
+ E extends Pick<EndpointInterface, 'key' | 'schema' | 'invalidIfStale'>,
340
+ Args extends readonly [...Parameters<E['key']>] | readonly [null],
341
+ >(
342
+ endpoint: E,
343
+ ...rest: [...Args, State<unknown>]
344
+ ): {
345
+ data: DenormalizeNullable<E['schema']>;
346
+ expiryStatus: ExpiryStatus;
347
+ expiresAt: number;
348
+ } => {
349
+ const state = rest[rest.length - 1] as State<unknown>;
350
+ // this is typescript generics breaking
351
+ const args: any = rest.slice(0, rest.length - 1) as Parameters<E['key']>;
352
+ const isActive = args.length !== 1 || args[0] !== null;
353
+ const key = isActive ? endpoint.key(...args) : '';
354
+ const cacheResults = isActive ? state.results[key] : undefined;
355
+ const schema = endpoint.schema;
356
+ const meta = selectMeta(state, key);
357
+ let expiresAt = meta?.expiresAt;
358
+
359
+ let invalidResults = false;
360
+ let results;
361
+ if (cacheResults === undefined && endpoint.schema !== undefined) {
362
+ results = inferResults(
363
+ endpoint.schema,
364
+ args,
365
+ state.indexes,
366
+ state.entities,
367
+ );
368
+ invalidResults = !validateInference(results);
369
+ if (!expiresAt && invalidResults) expiresAt = 1;
370
+ } else {
371
+ results = cacheResults;
372
+ }
373
+
374
+ if (!isActive) {
375
+ return {
376
+ data: results as any,
377
+ expiryStatus: ExpiryStatus.Valid,
378
+ expiresAt: Infinity,
379
+ };
380
+ }
381
+
382
+ if (!endpoint.schema || !schemaHasEntity(endpoint.schema)) {
383
+ return {
384
+ data: results,
385
+ expiryStatus: meta?.invalidated
386
+ ? ExpiryStatus.Invalid
387
+ : cacheResults && !endpoint.invalidIfStale
388
+ ? ExpiryStatus.Valid
389
+ : ExpiryStatus.InvalidIfStale,
390
+ expiresAt: expiresAt || 0,
391
+ } as {
392
+ data: DenormalizeNullable<E['schema']>;
393
+ expiryStatus: ExpiryStatus;
394
+ expiresAt: number;
395
+ };
396
+ }
397
+
398
+ if (!this.globalCache.results[key])
399
+ this.globalCache.results[key] = new WeakEntityMap();
400
+
401
+ // second argument is false if any entities are missing
402
+ // eslint-disable-next-line prefer-const
403
+ const { data, paths } = denormalizeCached(
404
+ results,
405
+ schema,
406
+ state.entities,
407
+ this.globalCache.entities,
408
+ this.globalCache.results[key],
409
+ args,
410
+ ) as { data: DenormalizeNullable<E['schema']>; paths: Path[] };
411
+ const invalidDenormalize = typeof data === 'symbol';
412
+
413
+ // fallback to entity expiry time
414
+ if (!expiresAt) {
415
+ expiresAt = entityExpiresAt(paths, state.entityMeta);
416
+ }
417
+
418
+ // https://resthooks.io/docs/concepts/expiry-policy#expiry-status
419
+ // we don't track the difference between stale or fresh because that is tied to triggering
420
+ // conditions
421
+ const expiryStatus =
422
+ meta?.invalidated || (invalidDenormalize && !meta?.error)
423
+ ? ExpiryStatus.Invalid
424
+ : invalidDenormalize || endpoint.invalidIfStale || invalidResults
425
+ ? ExpiryStatus.InvalidIfStale
426
+ : ExpiryStatus.Valid;
427
+
428
+ return { data, expiryStatus, expiresAt };
429
+ };
430
+ }
431
+
432
+ // benchmark: https://www.measurethat.net/Benchmarks/Show/24691/0/min-reducer-vs-imperative-with-paths
433
+ // earliest expiry dictates age
434
+ function entityExpiresAt(
435
+ paths: Path[],
436
+ entityMeta: {
437
+ readonly [entityKey: string]: {
438
+ readonly [pk: string]: {
439
+ readonly date: number;
440
+ readonly expiresAt: number;
441
+ readonly fetchedAt: number; // This is only the value until it is set by the CacheProvider
442
+ };
443
+ };
444
+ },
445
+ ) {
446
+ let expiresAt = Infinity;
447
+ for (const { pk, key } of paths) {
448
+ const entityExpiry = entityMeta[key]?.[pk]?.expiresAt;
449
+ // expiresAt will always resolve to false with any comparison
450
+ if (entityExpiry < expiresAt) expiresAt = entityExpiry;
451
+ }
452
+ return expiresAt;
30
453
  }
31
454
 
32
- export * from './BaseController.js';
455
+ /** Determine whether the schema has any entities.
456
+ *
457
+ * Without entities, denormalization is not needed, and results should not be inferred.
458
+ */
459
+ function schemaHasEntity(schema: Schema): boolean {
460
+ if (isEntity(schema)) return true;
461
+ if (Array.isArray(schema))
462
+ return schema.length !== 0 && schemaHasEntity(schema[0]);
463
+ if (schema && (typeof schema === 'object' || typeof schema === 'function')) {
464
+ const nestedSchema =
465
+ 'schema' in schema ? (schema.schema as Record<string, Schema>) : schema;
466
+ if (typeof nestedSchema === 'function') {
467
+ return schemaHasEntity(nestedSchema);
468
+ }
469
+ return Object.values(nestedSchema).some(x => schemaHasEntity(x));
470
+ }
471
+ return false;
472
+ }
473
+
474
+ export type { ErrorTypes };
475
+
476
+ class Snapshot<T = unknown> implements SnapshotInterface {
477
+ private state: State<T>;
478
+ private controller: Controller;
479
+ readonly fetchedAt: number;
480
+
481
+ constructor(controller: Controller, state: State<T>, fetchedAt = 0) {
482
+ this.state = state;
483
+ this.controller = controller;
484
+ this.fetchedAt = fetchedAt;
485
+ }
486
+
487
+ /*************** Data Access ***************/
488
+ /** @see https://resthooks.io/docs/api/Snapshot#getResponse */
489
+ getResponse = <
490
+ E extends Pick<EndpointInterface, 'key' | 'schema' | 'invalidIfStale'>,
491
+ Args extends readonly [...Parameters<E['key']>],
492
+ >(
493
+ endpoint: E,
494
+ ...args: Args
495
+ ): {
496
+ data: DenormalizeNullable<E['schema']>;
497
+ expiryStatus: ExpiryStatus;
498
+ expiresAt: number;
499
+ } => {
500
+ return this.controller.getResponse(endpoint, ...args, this.state);
501
+ };
502
+
503
+ /** @see https://resthooks.io/docs/api/Snapshot#getError */
504
+ getError = <
505
+ E extends Pick<EndpointInterface, 'key'>,
506
+ Args extends readonly [...Parameters<E['key']>],
507
+ >(
508
+ endpoint: E,
509
+ ...args: Args
510
+ ): ErrorTypes | undefined => {
511
+ return this.controller.getError(endpoint, ...args, this.state);
512
+ };
513
+ }
@@ -2,10 +2,7 @@ import type { EndpointInterface } from '@data-client/normalizr';
2
2
 
3
3
  import { EndpointUpdateFunction } from './types.js';
4
4
  import { FETCH_TYPE } from '../actionTypes.js';
5
- import type {
6
- CompatibleFetchAction,
7
- CompatibleFetchMeta,
8
- } from '../compatibleActions.js';
5
+ import type { FetchAction, FetchMeta } from '../types.js';
9
6
 
10
7
  /**
11
8
  * Requesting a fetch to begin
@@ -15,36 +12,24 @@ export default function createFetch<
15
12
  >(
16
13
  endpoint: E,
17
14
  { args }: { args: readonly [...Parameters<E>] },
18
- ): CompatibleFetchAction<E> {
15
+ ): FetchAction<E> {
19
16
  const key = endpoint.key(...args);
20
17
  let resolve: (value?: any | PromiseLike<any>) => void = 0 as any;
21
18
  let reject: (reason?: any) => void = 0 as any;
22
19
  const promise = new Promise<any>((a, b) => {
23
20
  [resolve, reject] = [a, b];
24
21
  });
25
- const meta: CompatibleFetchMeta = {
26
- schema: endpoint.schema,
27
- type: endpoint.sideEffect ? ('mutate' as const) : ('read' as const),
22
+ const meta: FetchMeta = {
28
23
  args,
29
24
  key,
30
25
  throttle: !endpoint.sideEffect,
31
- options: endpoint,
32
26
  resolve,
33
27
  reject,
34
28
  promise,
35
29
  createdAt: Date.now(),
30
+ nm: false,
36
31
  };
37
32
 
38
- if (endpoint.update) {
39
- meta.update = endpoint.update;
40
- }
41
-
42
- // TODO: Remove once EOL on this deprecated piece
43
- /* istanbul ignore if */
44
- if (endpoint.optimisticUpdate) {
45
- meta.optimisticResponse = endpoint.optimisticUpdate(...args);
46
- }
47
-
48
33
  return {
49
34
  type: FETCH_TYPE,
50
35
  payload: () => endpoint(...args) as any,
@@ -1,7 +1,7 @@
1
1
  import type { EndpointInterface } from '@data-client/normalizr';
2
2
 
3
3
  import { INVALIDATE_TYPE } from '../actionTypes.js';
4
- import type { InvalidateAction } from '../newActions.js';
4
+ import type { InvalidateAction } from '../types.js';
5
5
 
6
6
  export default function createInvalidate<E extends EndpointInterface>(
7
7
  endpoint: E,
@@ -1,5 +1,5 @@
1
1
  import { INVALIDATEALL_TYPE } from '../actionTypes.js';
2
- import type { InvalidateAllAction } from '../newActions.js';
2
+ import type { InvalidateAllAction } from '../types.js';
3
3
 
4
4
  export default function createInvalidateAll(
5
5
  testKey: (key: string) => boolean,
@@ -1,8 +1,8 @@
1
1
  import type { EndpointInterface } from '@data-client/normalizr';
2
2
 
3
- import { EndpointUpdateFunction } from './types.js';
3
+ import type { EndpointUpdateFunction } from './types.js';
4
4
  import { OPTIMISTIC_TYPE } from '../actionTypes.js';
5
- import { OptimisticAction } from '../newActions.js';
5
+ import type { OptimisticAction } from '../types.js';
6
6
 
7
7
  export default function createOptimistic<
8
8
  E extends EndpointInterface & {
@@ -24,19 +24,13 @@ export default function createOptimistic<
24
24
  throw new Error('Negative expiry length are not allowed.');
25
25
  }
26
26
  const now = Date.now();
27
- // TODO: Use correct type once we no longer need backcompat
28
- const meta: any = {
27
+ const meta: OptimisticAction['meta'] = {
29
28
  args,
30
29
  fetchedAt,
31
30
  date: now,
32
31
  expiresAt: now + expiryLength,
33
- // For legacy support; TODO: remove
34
- schema: endpoint.schema,
35
32
  key: endpoint.key(...args),
36
33
  };
37
- // For legacy support; TODO: remove
38
- if (endpoint.update) meta.update = endpoint.update;
39
- if (endpoint.errorPolicy) meta.errorPolicy = endpoint.errorPolicy;
40
34
 
41
35
  const action: OptimisticAction<E> = {
42
36
  type: OPTIMISTIC_TYPE,
@@ -1,5 +1,5 @@
1
1
  import { RESET_TYPE } from '../actionTypes.js';
2
- import type { ResetAction } from '../newActions.js';
2
+ import type { ResetAction } from '../types.js';
3
3
 
4
4
  export default function createReset(): ResetAction {
5
5
  return {
@@ -2,12 +2,9 @@ import type { EndpointInterface, ResolveType } from '@data-client/normalizr';
2
2
 
3
3
  import { EndpointUpdateFunction } from './types.js';
4
4
  import { SET_TYPE } from '../actionTypes.js';
5
- import type {
6
- CompatibleReceiveAction,
7
- CompatibleReceiveMeta,
8
- } from '../compatibleActions.js';
5
+ import type { SetAction, SetMeta } from '../types.js';
9
6
 
10
- export default function createReceive<
7
+ export default function createSet<
11
8
  E extends EndpointInterface & {
12
9
  update?: EndpointUpdateFunction<E>;
13
10
  },
@@ -19,9 +16,9 @@ export default function createReceive<
19
16
  fetchedAt?: number;
20
17
  error: true;
21
18
  },
22
- ): CompatibleReceiveAction<E>;
19
+ ): SetAction<E>;
23
20
 
24
- export default function createReceive<
21
+ export default function createSet<
25
22
  E extends EndpointInterface & {
26
23
  update?: EndpointUpdateFunction<E>;
27
24
  },
@@ -33,9 +30,9 @@ export default function createReceive<
33
30
  fetchedAt?: number;
34
31
  error?: false;
35
32
  },
36
- ): CompatibleReceiveAction<E>;
33
+ ): SetAction<E>;
37
34
 
38
- export default function createReceive<
35
+ export default function createSet<
39
36
  E extends EndpointInterface & {
40
37
  update?: EndpointUpdateFunction<E>;
41
38
  },
@@ -52,7 +49,7 @@ export default function createReceive<
52
49
  fetchedAt?: number;
53
50
  error?: boolean;
54
51
  },
55
- ): CompatibleReceiveAction<E> {
52
+ ): SetAction<E> {
56
53
  const expiryLength: number = error
57
54
  ? endpoint.errorExpiryLength ?? 1000
58
55
  : endpoint.dataExpiryLength ?? 60000;
@@ -61,20 +58,15 @@ export default function createReceive<
61
58
  throw new Error('Negative expiry length are not allowed.');
62
59
  }
63
60
  const now = Date.now();
64
- const meta: CompatibleReceiveMeta = {
61
+ const meta: SetMeta = {
65
62
  args,
66
63
  fetchedAt: fetchedAt ?? now,
67
64
  date: now,
68
65
  expiresAt: now + expiryLength,
69
- // For legacy support; TODO: remove
70
- schema: endpoint.schema,
71
66
  key: endpoint.key(...args),
72
67
  };
73
- // For legacy support; TODO: remove
74
- if (endpoint.update) meta.update = endpoint.update;
75
- if (endpoint.errorPolicy) meta.errorPolicy = endpoint.errorPolicy;
76
68
 
77
- const action: CompatibleReceiveAction<E> = {
69
+ const action: SetAction<E> = {
78
70
  type: SET_TYPE,
79
71
  payload: response,
80
72
  endpoint: endpoint,