@data-client/core 0.1.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.
- package/LICENSE +201 -0
- package/README.md +71 -0
- package/dist/index.js +1643 -0
- package/dist/index.umd.min.js +1 -0
- package/dist/next.js +461 -0
- package/dist/package.json +1 -0
- package/legacy/actionTypes.js +12 -0
- package/legacy/compatibleActions.js +2 -0
- package/legacy/controller/BaseController.js +289 -0
- package/legacy/controller/Controller.js +20 -0
- package/legacy/controller/createFetch.js +42 -0
- package/legacy/controller/createInvalidate.js +12 -0
- package/legacy/controller/createInvalidateAll.js +8 -0
- package/legacy/controller/createOptimistic.js +33 -0
- package/legacy/controller/createReceive.js +36 -0
- package/legacy/controller/createReset.js +8 -0
- package/legacy/controller/createSubscription.js +30 -0
- package/legacy/controller/types.js +2 -0
- package/legacy/endpoint/index.js +2 -0
- package/legacy/endpoint/shapes.js +2 -0
- package/legacy/endpoint/types.js +2 -0
- package/legacy/fsa.js +2 -0
- package/legacy/index.js +22 -0
- package/legacy/internal.js +4 -0
- package/legacy/legacyActions.js +2 -0
- package/legacy/manager/ConnectionListener.js +2 -0
- package/legacy/manager/DefaultConnectionListener.js +40 -0
- package/legacy/manager/DevtoolsManager.js +73 -0
- package/legacy/manager/LogoutManager.js +34 -0
- package/legacy/manager/NetworkManager.js +291 -0
- package/legacy/manager/PollingSubscription.js +159 -0
- package/legacy/manager/SubscriptionManager.js +117 -0
- package/legacy/manager/applyManager.js +23 -0
- package/legacy/manager/devtoolsTypes.js +2 -0
- package/legacy/manager/index.js +6 -0
- package/legacy/middlewareTypes.js +2 -0
- package/legacy/newActions.js +2 -0
- package/legacy/next/Controller.js +24 -0
- package/legacy/next/index.js +3 -0
- package/legacy/previousActions.js +2 -0
- package/legacy/state/RIC.js +3 -0
- package/legacy/state/applyUpdatersToResults.js +4 -0
- package/legacy/state/legacy-actions/createFetch.js +62 -0
- package/legacy/state/legacy-actions/createReceive.js +37 -0
- package/legacy/state/legacy-actions/createReceiveError.js +28 -0
- package/legacy/state/legacy-actions/index.js +4 -0
- package/legacy/state/reducer/createReducer.js +54 -0
- package/legacy/state/reducer/fetchReducer.js +32 -0
- package/legacy/state/reducer/invalidateReducer.js +28 -0
- package/legacy/state/reducer/setReducer.js +113 -0
- package/legacy/state/reducerInstance.js +9 -0
- package/legacy/state/selectMeta.js +4 -0
- package/legacy/types.js +8 -0
- package/lib/actionTypes.d.ts +11 -0
- package/lib/actionTypes.d.ts.map +1 -0
- package/lib/actionTypes.js +12 -0
- package/lib/compatibleActions.d.ts +47 -0
- package/lib/compatibleActions.d.ts.map +1 -0
- package/lib/compatibleActions.js +2 -0
- package/lib/controller/BaseController.d.ts +128 -0
- package/lib/controller/BaseController.d.ts.map +1 -0
- package/lib/controller/BaseController.js +289 -0
- package/lib/controller/Controller.d.ts +14 -0
- package/lib/controller/Controller.d.ts.map +1 -0
- package/lib/controller/Controller.js +20 -0
- package/lib/controller/createFetch.d.ts +12 -0
- package/lib/controller/createFetch.d.ts.map +1 -0
- package/lib/controller/createFetch.js +42 -0
- package/lib/controller/createInvalidate.d.ts +6 -0
- package/lib/controller/createInvalidate.d.ts.map +1 -0
- package/lib/controller/createInvalidate.js +12 -0
- package/lib/controller/createInvalidateAll.d.ts +3 -0
- package/lib/controller/createInvalidateAll.d.ts.map +1 -0
- package/lib/controller/createInvalidateAll.js +8 -0
- package/lib/controller/createOptimistic.d.ts +10 -0
- package/lib/controller/createOptimistic.d.ts.map +1 -0
- package/lib/controller/createOptimistic.js +33 -0
- package/lib/controller/createReceive.d.ts +20 -0
- package/lib/controller/createReceive.d.ts.map +1 -0
- package/lib/controller/createReceive.js +36 -0
- package/lib/controller/createReset.d.ts +3 -0
- package/lib/controller/createReset.d.ts.map +1 -0
- package/lib/controller/createReset.js +8 -0
- package/lib/controller/createSubscription.d.ts +9 -0
- package/lib/controller/createSubscription.d.ts.map +1 -0
- package/lib/controller/createSubscription.js +30 -0
- package/lib/controller/types.d.ts +6 -0
- package/lib/controller/types.d.ts.map +1 -0
- package/lib/controller/types.js +2 -0
- package/lib/endpoint/index.d.ts +3 -0
- package/lib/endpoint/index.d.ts.map +1 -0
- package/lib/endpoint/index.js +2 -0
- package/lib/endpoint/shapes.d.ts +25 -0
- package/lib/endpoint/shapes.d.ts.map +1 -0
- package/lib/endpoint/shapes.js +2 -0
- package/lib/endpoint/types.d.ts +45 -0
- package/lib/endpoint/types.d.ts.map +1 -0
- package/lib/endpoint/types.js +2 -0
- package/lib/fsa.d.ts +41 -0
- package/lib/fsa.d.ts.map +1 -0
- package/lib/fsa.js +2 -0
- package/lib/index.d.ts +19 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +22 -0
- package/lib/internal.d.ts +4 -0
- package/lib/internal.d.ts.map +1 -0
- package/lib/internal.js +4 -0
- package/lib/legacyActions.d.ts +92 -0
- package/lib/legacyActions.d.ts.map +1 -0
- package/lib/legacyActions.js +2 -0
- package/lib/manager/ConnectionListener.d.ts +8 -0
- package/lib/manager/ConnectionListener.d.ts.map +1 -0
- package/lib/manager/ConnectionListener.js +2 -0
- package/lib/manager/DefaultConnectionListener.d.ts +20 -0
- package/lib/manager/DefaultConnectionListener.d.ts.map +1 -0
- package/lib/manager/DefaultConnectionListener.js +40 -0
- package/lib/manager/DevtoolsManager.d.ts +24 -0
- package/lib/manager/DevtoolsManager.d.ts.map +1 -0
- package/lib/manager/DevtoolsManager.js +74 -0
- package/lib/manager/LogoutManager.d.ts +25 -0
- package/lib/manager/LogoutManager.d.ts.map +1 -0
- package/lib/manager/LogoutManager.js +34 -0
- package/lib/manager/NetworkManager.d.ts +82 -0
- package/lib/manager/NetworkManager.d.ts.map +1 -0
- package/lib/manager/NetworkManager.js +295 -0
- package/lib/manager/PollingSubscription.d.ts +45 -0
- package/lib/manager/PollingSubscription.d.ts.map +1 -0
- package/lib/manager/PollingSubscription.js +159 -0
- package/lib/manager/SubscriptionManager.d.ts +55 -0
- package/lib/manager/SubscriptionManager.d.ts.map +1 -0
- package/lib/manager/SubscriptionManager.js +117 -0
- package/lib/manager/applyManager.d.ts +10 -0
- package/lib/manager/applyManager.d.ts.map +1 -0
- package/lib/manager/applyManager.js +23 -0
- package/lib/manager/devtoolsTypes.d.ts +205 -0
- package/lib/manager/devtoolsTypes.d.ts.map +1 -0
- package/lib/manager/devtoolsTypes.js +2 -0
- package/lib/manager/index.d.ts +8 -0
- package/lib/manager/index.d.ts.map +1 -0
- package/lib/manager/index.js +6 -0
- package/lib/middlewareTypes.d.ts +18 -0
- package/lib/middlewareTypes.d.ts.map +1 -0
- package/lib/middlewareTypes.js +2 -0
- package/lib/newActions.d.ts +85 -0
- package/lib/newActions.d.ts.map +1 -0
- package/lib/newActions.js +2 -0
- package/lib/next/Controller.d.ts +14 -0
- package/lib/next/Controller.d.ts.map +1 -0
- package/lib/next/Controller.js +24 -0
- package/lib/next/index.d.ts +3 -0
- package/lib/next/index.d.ts.map +1 -0
- package/lib/next/index.js +3 -0
- package/lib/previousActions.d.ts +91 -0
- package/lib/previousActions.d.ts.map +1 -0
- package/lib/previousActions.js +2 -0
- package/lib/state/RIC.d.ts +2 -0
- package/lib/state/RIC.js +3 -0
- package/lib/state/applyUpdatersToResults.d.ts +13 -0
- package/lib/state/applyUpdatersToResults.d.ts.map +1 -0
- package/lib/state/applyUpdatersToResults.js +7 -0
- package/lib/state/legacy-actions/createFetch.d.ts +19 -0
- package/lib/state/legacy-actions/createFetch.d.ts.map +1 -0
- package/lib/state/legacy-actions/createFetch.js +62 -0
- package/lib/state/legacy-actions/createReceive.d.ts +14 -0
- package/lib/state/legacy-actions/createReceive.d.ts.map +1 -0
- package/lib/state/legacy-actions/createReceive.js +37 -0
- package/lib/state/legacy-actions/createReceiveError.d.ts +9 -0
- package/lib/state/legacy-actions/createReceiveError.d.ts.map +1 -0
- package/lib/state/legacy-actions/createReceiveError.js +28 -0
- package/lib/state/legacy-actions/index.d.ts +4 -0
- package/lib/state/legacy-actions/index.d.ts.map +1 -0
- package/lib/state/legacy-actions/index.js +4 -0
- package/lib/state/reducer/createReducer.d.ts +7 -0
- package/lib/state/reducer/createReducer.d.ts.map +1 -0
- package/lib/state/reducer/createReducer.js +55 -0
- package/lib/state/reducer/fetchReducer.d.ts +4 -0
- package/lib/state/reducer/fetchReducer.d.ts.map +1 -0
- package/lib/state/reducer/fetchReducer.js +34 -0
- package/lib/state/reducer/invalidateReducer.d.ts +37 -0
- package/lib/state/reducer/invalidateReducer.d.ts.map +1 -0
- package/lib/state/reducer/invalidateReducer.js +34 -0
- package/lib/state/reducer/setReducer.d.ts +40 -0
- package/lib/state/reducer/setReducer.d.ts.map +1 -0
- package/lib/state/reducer/setReducer.js +119 -0
- package/lib/state/reducerInstance.d.ts +7 -0
- package/lib/state/reducerInstance.d.ts.map +1 -0
- package/lib/state/reducerInstance.js +9 -0
- package/lib/state/selectMeta.d.ts +3 -0
- package/lib/state/selectMeta.d.ts.map +1 -0
- package/lib/state/selectMeta.js +4 -0
- package/lib/types.d.ts +71 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +8 -0
- package/node.mjs +1 -0
- package/package.json +127 -0
- package/src/actionTypes.ts +11 -0
- package/src/compatibleActions.ts +96 -0
- package/src/controller/BaseController.ts +508 -0
- package/src/controller/Controller.ts +32 -0
- package/src/controller/__tests__/Controller.ts +29 -0
- package/src/controller/__tests__/__snapshots__/getResponse.ts.snap +35 -0
- package/src/controller/__tests__/getResponse.ts +182 -0
- package/src/controller/createFetch.ts +54 -0
- package/src/controller/createInvalidate.ts +16 -0
- package/src/controller/createInvalidateAll.ts +11 -0
- package/src/controller/createOptimistic.ts +47 -0
- package/src/controller/createReceive.ts +85 -0
- package/src/controller/createReset.ts +9 -0
- package/src/controller/createSubscription.ts +39 -0
- package/src/controller/types.ts +22 -0
- package/src/endpoint/index.ts +14 -0
- package/src/endpoint/shapes.ts +53 -0
- package/src/endpoint/types.ts +72 -0
- package/src/fsa.ts +99 -0
- package/src/index.ts +61 -0
- package/src/internal.ts +3 -0
- package/src/legacyActions.ts +163 -0
- package/src/manager/ConnectionListener.ts +7 -0
- package/src/manager/DefaultConnectionListener.ts +54 -0
- package/src/manager/DevtoolsManager.ts +99 -0
- package/src/manager/LogoutManager.ts +57 -0
- package/src/manager/NetworkManager.ts +346 -0
- package/src/manager/PollingSubscription.ts +190 -0
- package/src/manager/SubscriptionManager.ts +156 -0
- package/src/manager/__tests__/__snapshots__/pollingSubscription-endpoint.ts.snap +49 -0
- package/src/manager/__tests__/__snapshots__/pollingSubscription.ts.snap +43 -0
- package/src/manager/__tests__/logoutManager.ts +112 -0
- package/src/manager/__tests__/manager.ts +44 -0
- package/src/manager/__tests__/networkManager-legacy.ts +394 -0
- package/src/manager/__tests__/networkManager.ts +426 -0
- package/src/manager/__tests__/pollingSubscription-endpoint.ts +423 -0
- package/src/manager/__tests__/pollingSubscription.ts +313 -0
- package/src/manager/__tests__/subscriptionManager.ts +208 -0
- package/src/manager/applyManager.ts +33 -0
- package/src/manager/devtoolsTypes.ts +210 -0
- package/src/manager/index.ts +7 -0
- package/src/middlewareTypes.ts +49 -0
- package/src/newActions.ts +140 -0
- package/src/next/Controller.ts +39 -0
- package/src/next/index.ts +2 -0
- package/src/package.json +1 -0
- package/src/previousActions.ts +159 -0
- package/src/state/RIC.d.ts +2 -0
- package/src/state/RIC.js +5 -0
- package/src/state/__tests__/RIC.web.ts +16 -0
- package/src/state/__tests__/__snapshots__/reducer.ts.snap +56 -0
- package/src/state/__tests__/applyUpdatersToResults.ts +40 -0
- package/src/state/__tests__/reducer.ts +868 -0
- package/src/state/applyUpdatersToResults.ts +29 -0
- package/src/state/legacy-actions/createFetch.ts +95 -0
- package/src/state/legacy-actions/createReceive.ts +68 -0
- package/src/state/legacy-actions/createReceiveError.ts +43 -0
- package/src/state/legacy-actions/index.ts +3 -0
- package/src/state/reducer/createReducer.ts +80 -0
- package/src/state/reducer/fetchReducer.ts +48 -0
- package/src/state/reducer/invalidateReducer.ts +39 -0
- package/src/state/reducer/setReducer.ts +157 -0
- package/src/state/reducerInstance.ts +14 -0
- package/src/state/selectMeta.ts +8 -0
- package/src/types.ts +125 -0
- package/ts3.4/actionTypes.d.ts +11 -0
- package/ts3.4/compatibleActions.d.ts +47 -0
- package/ts3.4/controller/BaseController.d.ts +170 -0
- package/ts3.4/controller/Controller.d.ts +14 -0
- package/ts3.4/controller/createFetch.d.ts +14 -0
- package/ts3.4/controller/createInvalidate.d.ts +8 -0
- package/ts3.4/controller/createInvalidateAll.d.ts +3 -0
- package/ts3.4/controller/createOptimistic.d.ts +12 -0
- package/ts3.4/controller/createReceive.d.ts +24 -0
- package/ts3.4/controller/createReset.d.ts +3 -0
- package/ts3.4/controller/createSubscription.d.ts +13 -0
- package/ts3.4/controller/types.d.ts +6 -0
- package/ts3.4/endpoint/index.d.ts +3 -0
- package/ts3.4/endpoint/shapes.d.ts +25 -0
- package/ts3.4/endpoint/types.d.ts +45 -0
- package/ts3.4/fsa.d.ts +41 -0
- package/ts3.4/index.d.ts +22 -0
- package/ts3.4/internal.d.ts +4 -0
- package/ts3.4/legacyActions.d.ts +95 -0
- package/ts3.4/manager/ConnectionListener.d.ts +8 -0
- package/ts3.4/manager/DefaultConnectionListener.d.ts +20 -0
- package/ts3.4/manager/DevtoolsManager.d.ts +24 -0
- package/ts3.4/manager/LogoutManager.d.ts +25 -0
- package/ts3.4/manager/NetworkManager.d.ts +82 -0
- package/ts3.4/manager/PollingSubscription.d.ts +45 -0
- package/ts3.4/manager/SubscriptionManager.d.ts +55 -0
- package/ts3.4/manager/applyManager.d.ts +10 -0
- package/ts3.4/manager/devtoolsTypes.d.ts +205 -0
- package/ts3.4/manager/index.d.ts +8 -0
- package/ts3.4/middlewareTypes.d.ts +18 -0
- package/ts3.4/newActions.d.ts +88 -0
- package/ts3.4/next/Controller.d.ts +14 -0
- package/ts3.4/next/index.d.ts +3 -0
- package/ts3.4/previousActions.d.ts +94 -0
- package/ts3.4/state/RIC.d.ts +2 -0
- package/ts3.4/state/applyUpdatersToResults.d.ts +13 -0
- package/ts3.4/state/legacy-actions/createFetch.d.ts +19 -0
- package/ts3.4/state/legacy-actions/createReceive.d.ts +14 -0
- package/ts3.4/state/legacy-actions/createReceiveError.d.ts +9 -0
- package/ts3.4/state/legacy-actions/index.d.ts +4 -0
- package/ts3.4/state/reducer/createReducer.d.ts +7 -0
- package/ts3.4/state/reducer/fetchReducer.d.ts +4 -0
- package/ts3.4/state/reducer/invalidateReducer.d.ts +37 -0
- package/ts3.4/state/reducer/setReducer.d.ts +40 -0
- package/ts3.4/state/reducerInstance.d.ts +7 -0
- package/ts3.4/state/selectMeta.d.ts +3 -0
- package/ts3.4/types.d.ts +73 -0
- package/typescript.svg +8 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1643 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var normalizr = require('@data-client/normalizr');
|
|
6
|
+
|
|
7
|
+
const RIC = typeof requestIdleCallback === 'function' ? requestIdleCallback : cb => setTimeout(cb, 0);
|
|
8
|
+
var RIC$1 = RIC;
|
|
9
|
+
|
|
10
|
+
const FETCH_TYPE = 'rest-hooks/fetch';
|
|
11
|
+
// TODO(breaking): deprecate this
|
|
12
|
+
const RECEIVE_TYPE = 'rest-hooks/receive';
|
|
13
|
+
const SET_TYPE = RECEIVE_TYPE;
|
|
14
|
+
const OPTIMISTIC_TYPE = 'rest-hooks/optimistic';
|
|
15
|
+
const RESET_TYPE = 'rest-hooks/reset';
|
|
16
|
+
const SUBSCRIBE_TYPE = 'rest-hooks/subscribe';
|
|
17
|
+
const UNSUBSCRIBE_TYPE = 'rest-hook/unsubscribe';
|
|
18
|
+
const INVALIDATE_TYPE = 'rest-hooks/invalidate';
|
|
19
|
+
const INVALIDATEALL_TYPE = 'rest-hooks/invalidateall';
|
|
20
|
+
const GC_TYPE = 'rest-hooks/gc';
|
|
21
|
+
|
|
22
|
+
var actionTypes = /*#__PURE__*/Object.freeze({
|
|
23
|
+
__proto__: null,
|
|
24
|
+
FETCH_TYPE: FETCH_TYPE,
|
|
25
|
+
RECEIVE_TYPE: RECEIVE_TYPE,
|
|
26
|
+
SET_TYPE: SET_TYPE,
|
|
27
|
+
OPTIMISTIC_TYPE: OPTIMISTIC_TYPE,
|
|
28
|
+
RESET_TYPE: RESET_TYPE,
|
|
29
|
+
SUBSCRIBE_TYPE: SUBSCRIBE_TYPE,
|
|
30
|
+
UNSUBSCRIBE_TYPE: UNSUBSCRIBE_TYPE,
|
|
31
|
+
INVALIDATE_TYPE: INVALIDATE_TYPE,
|
|
32
|
+
INVALIDATEALL_TYPE: INVALIDATEALL_TYPE,
|
|
33
|
+
GC_TYPE: GC_TYPE
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
function createOptimistic(endpoint, {
|
|
37
|
+
args,
|
|
38
|
+
fetchedAt
|
|
39
|
+
}) {
|
|
40
|
+
var _endpoint$dataExpiryL;
|
|
41
|
+
const expiryLength = (_endpoint$dataExpiryL = endpoint.dataExpiryLength) != null ? _endpoint$dataExpiryL : 60000;
|
|
42
|
+
/* istanbul ignore next */
|
|
43
|
+
if (process.env.NODE_ENV === 'development' && expiryLength < 0) {
|
|
44
|
+
throw new Error('Negative expiry length are not allowed.');
|
|
45
|
+
}
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
// TODO: Use correct type once we no longer need backcompat
|
|
48
|
+
const meta = {
|
|
49
|
+
args,
|
|
50
|
+
fetchedAt,
|
|
51
|
+
date: now,
|
|
52
|
+
expiresAt: now + expiryLength,
|
|
53
|
+
// For legacy support; TODO: remove
|
|
54
|
+
schema: endpoint.schema,
|
|
55
|
+
key: endpoint.key(...args)
|
|
56
|
+
};
|
|
57
|
+
// For legacy support; TODO: remove
|
|
58
|
+
if (endpoint.update) meta.update = endpoint.update;
|
|
59
|
+
if (endpoint.errorPolicy) meta.errorPolicy = endpoint.errorPolicy;
|
|
60
|
+
const action = {
|
|
61
|
+
type: OPTIMISTIC_TYPE,
|
|
62
|
+
endpoint,
|
|
63
|
+
meta
|
|
64
|
+
};
|
|
65
|
+
return action;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// TODO(breaking): remove file - not used
|
|
69
|
+
/** Requesting a fetch to begin
|
|
70
|
+
*
|
|
71
|
+
* @param fetchShape
|
|
72
|
+
* @param param1 { params, body, throttle, updateParams }
|
|
73
|
+
*/
|
|
74
|
+
function createFetch$1(fetchShape, {
|
|
75
|
+
params,
|
|
76
|
+
body,
|
|
77
|
+
throttle,
|
|
78
|
+
updateParams
|
|
79
|
+
}) {
|
|
80
|
+
const {
|
|
81
|
+
schema,
|
|
82
|
+
type,
|
|
83
|
+
getFetchKey,
|
|
84
|
+
options
|
|
85
|
+
} = fetchShape;
|
|
86
|
+
const key = getFetchKey(params);
|
|
87
|
+
let resolve = 0;
|
|
88
|
+
let reject = 0;
|
|
89
|
+
const promise = new Promise((a, b) => {
|
|
90
|
+
[resolve, reject] = [a, b];
|
|
91
|
+
});
|
|
92
|
+
const meta = {
|
|
93
|
+
schema,
|
|
94
|
+
type,
|
|
95
|
+
args: [params, body],
|
|
96
|
+
key,
|
|
97
|
+
throttle,
|
|
98
|
+
options,
|
|
99
|
+
resolve,
|
|
100
|
+
reject,
|
|
101
|
+
promise,
|
|
102
|
+
createdAt: Date.now()
|
|
103
|
+
};
|
|
104
|
+
if (fetchShape.update) {
|
|
105
|
+
meta.update = fetchShape.update;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// for simplicity we simply override if updateParams are defined - usage together is silly to support as we are migrating
|
|
109
|
+
if (updateParams) {
|
|
110
|
+
meta.update = newresult => {
|
|
111
|
+
const updateMap = {};
|
|
112
|
+
updateParams.forEach(([toShape, toParams, updateFn]) => {
|
|
113
|
+
updateMap[toShape.getFetchKey(toParams)] = existing => updateFn(newresult, existing);
|
|
114
|
+
});
|
|
115
|
+
return updateMap;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (options != null && options.optimisticUpdate) {
|
|
119
|
+
meta.optimisticResponse = options.optimisticUpdate(params, body);
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
type: FETCH_TYPE,
|
|
123
|
+
payload: () => fetchShape.fetch(params, body),
|
|
124
|
+
meta
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Update state with data
|
|
129
|
+
*
|
|
130
|
+
* @param data
|
|
131
|
+
* @param param1 { schema, key, type, updaters, dataExpiryLength }
|
|
132
|
+
*/
|
|
133
|
+
function createReceive$1(data, {
|
|
134
|
+
schema,
|
|
135
|
+
key,
|
|
136
|
+
args,
|
|
137
|
+
updaters,
|
|
138
|
+
fetchedAt = 0,
|
|
139
|
+
update,
|
|
140
|
+
dataExpiryLength
|
|
141
|
+
}) {
|
|
142
|
+
/* istanbul ignore next */
|
|
143
|
+
if (process.env.NODE_ENV === 'development' && dataExpiryLength < 0) {
|
|
144
|
+
throw new Error('Negative dataExpiryLength are not allowed.');
|
|
145
|
+
}
|
|
146
|
+
const now = Date.now();
|
|
147
|
+
const meta = {
|
|
148
|
+
schema,
|
|
149
|
+
key,
|
|
150
|
+
args,
|
|
151
|
+
date: now,
|
|
152
|
+
fetchedAt,
|
|
153
|
+
expiresAt: now + dataExpiryLength
|
|
154
|
+
};
|
|
155
|
+
meta.updaters = updaters;
|
|
156
|
+
meta.update = update;
|
|
157
|
+
return {
|
|
158
|
+
type: RECEIVE_TYPE,
|
|
159
|
+
payload: data,
|
|
160
|
+
meta
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function createReceiveError(error, {
|
|
165
|
+
schema,
|
|
166
|
+
key,
|
|
167
|
+
options,
|
|
168
|
+
errorExpiryLength = 60000,
|
|
169
|
+
fetchedAt = 0
|
|
170
|
+
}) {
|
|
171
|
+
/* istanbul ignore next */
|
|
172
|
+
if (process.env.NODE_ENV === 'development' && errorExpiryLength < 0) {
|
|
173
|
+
throw new Error('Negative errorExpiryLength are not allowed.');
|
|
174
|
+
}
|
|
175
|
+
const now = Date.now();
|
|
176
|
+
return {
|
|
177
|
+
type: RECEIVE_TYPE,
|
|
178
|
+
payload: error,
|
|
179
|
+
meta: {
|
|
180
|
+
schema,
|
|
181
|
+
key,
|
|
182
|
+
date: now,
|
|
183
|
+
fetchedAt,
|
|
184
|
+
expiresAt: now + errorExpiryLength,
|
|
185
|
+
errorPolicy: options == null ? void 0 : options.errorPolicy
|
|
186
|
+
},
|
|
187
|
+
error: true
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
var index = /*#__PURE__*/Object.freeze({
|
|
192
|
+
__proto__: null,
|
|
193
|
+
createFetch: createFetch$1,
|
|
194
|
+
createReceive: createReceive$1,
|
|
195
|
+
createReceiveError: createReceiveError
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
function fetchReducer(state, action) {
|
|
199
|
+
var _action$endpoint;
|
|
200
|
+
const optimisticResponse = action.meta.optimisticResponse;
|
|
201
|
+
const getOptimisticResponse = (_action$endpoint = action.endpoint) == null ? void 0 : _action$endpoint.getOptimisticResponse;
|
|
202
|
+
let receiveAction;
|
|
203
|
+
if (getOptimisticResponse && action.endpoint && action.endpoint.sideEffect) {
|
|
204
|
+
receiveAction = createOptimistic(action.endpoint, {
|
|
205
|
+
args: action.meta.args,
|
|
206
|
+
fetchedAt: typeof action.meta.createdAt !== 'number' ? action.meta.createdAt.getTime() : action.meta.createdAt
|
|
207
|
+
});
|
|
208
|
+
} /* istanbul ignore if */else if (optimisticResponse) {
|
|
209
|
+
// TODO(breaking): this is no longer used, remove this branch
|
|
210
|
+
/* istanbul ignore next */
|
|
211
|
+
receiveAction = createReceive$1(optimisticResponse, {
|
|
212
|
+
...action.meta,
|
|
213
|
+
dataExpiryLength: Infinity
|
|
214
|
+
});
|
|
215
|
+
} else {
|
|
216
|
+
// If 'fetch' action reaches the reducer there are no middlewares installed to handle it
|
|
217
|
+
/* istanbul ignore next */
|
|
218
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
219
|
+
console.warn('Fetch appears unhandled - you are likely missing the NetworkManager middleware');
|
|
220
|
+
console.warn('See https://resthooks.io/docs/guides/redux#indextsx for hooking up redux');
|
|
221
|
+
}
|
|
222
|
+
return state;
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
...state,
|
|
226
|
+
optimistic: [...state.optimistic, receiveAction]
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function invalidateReducer(state, action) {
|
|
231
|
+
const results = {
|
|
232
|
+
...state.results
|
|
233
|
+
};
|
|
234
|
+
const meta = {
|
|
235
|
+
...state.meta
|
|
236
|
+
};
|
|
237
|
+
const invalidateKey = key => {
|
|
238
|
+
delete results[key];
|
|
239
|
+
const itemMeta = {
|
|
240
|
+
...meta[key],
|
|
241
|
+
expiresAt: 0,
|
|
242
|
+
invalidated: true
|
|
243
|
+
};
|
|
244
|
+
delete itemMeta.error;
|
|
245
|
+
meta[key] = itemMeta;
|
|
246
|
+
};
|
|
247
|
+
if (action.type === INVALIDATE_TYPE) {
|
|
248
|
+
invalidateKey(action.meta.key);
|
|
249
|
+
} else {
|
|
250
|
+
Object.keys(results).forEach(key => {
|
|
251
|
+
if (action.testKey(key)) {
|
|
252
|
+
invalidateKey(key);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
...state,
|
|
258
|
+
results,
|
|
259
|
+
meta
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function applyUpdatersToResults(results, result, updaters) {
|
|
264
|
+
return {
|
|
265
|
+
...results,
|
|
266
|
+
...Object.fromEntries(Object.entries(updaters).map(([fetchKey, updater]) => [fetchKey, updater(result, results[fetchKey])]))
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function setReducer(state, action, controller) {
|
|
271
|
+
if (action.error) {
|
|
272
|
+
return reduceError(state, action, action.payload);
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
var _state$meta$action$me;
|
|
276
|
+
let payload;
|
|
277
|
+
// for true receives payload is contained in action
|
|
278
|
+
if (action.type === OPTIMISTIC_TYPE) {
|
|
279
|
+
if (!action.endpoint.getOptimisticResponse) return state;
|
|
280
|
+
try {
|
|
281
|
+
// compute optimistic response based on current state
|
|
282
|
+
payload = action.endpoint.getOptimisticResponse.call(action.endpoint, controller.snapshot(state, action.meta.fetchedAt),
|
|
283
|
+
// if endpoint exists, so must args; TODO: fix typing
|
|
284
|
+
...action.meta.args);
|
|
285
|
+
} catch (e) {
|
|
286
|
+
var _e$constructor;
|
|
287
|
+
// AbortOptimistic means 'do nothing', otherwise we count the exception as endpoint failure
|
|
288
|
+
if (((_e$constructor = e.constructor) == null ? void 0 : _e$constructor.name) === 'AbortOptimistic') {
|
|
289
|
+
return state;
|
|
290
|
+
}
|
|
291
|
+
throw e;
|
|
292
|
+
}
|
|
293
|
+
} else {
|
|
294
|
+
payload = action.payload;
|
|
295
|
+
}
|
|
296
|
+
const {
|
|
297
|
+
result,
|
|
298
|
+
entities,
|
|
299
|
+
indexes,
|
|
300
|
+
entityMeta
|
|
301
|
+
} = normalizr.normalize(payload, action.meta.schema, action.meta.args, state.entities, state.indexes, state.entityMeta, {
|
|
302
|
+
fetchedAt: action.meta.date,
|
|
303
|
+
...action.meta
|
|
304
|
+
});
|
|
305
|
+
let results = {
|
|
306
|
+
...state.results,
|
|
307
|
+
[action.meta.key]: result
|
|
308
|
+
};
|
|
309
|
+
try {
|
|
310
|
+
if ('updaters' in action.meta && action.meta.updaters) {
|
|
311
|
+
results = applyUpdatersToResults(results, result, action.meta.updaters);
|
|
312
|
+
}
|
|
313
|
+
if (action.meta.update) {
|
|
314
|
+
const updaters = action.meta.update(result, ...(action.meta.args || []));
|
|
315
|
+
Object.keys(updaters).forEach(key => {
|
|
316
|
+
results[key] = updaters[key](results[key]);
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
// no reason to completely fail because of user-code error
|
|
320
|
+
// integrity of this state update is still guaranteed
|
|
321
|
+
} catch (error) {
|
|
322
|
+
console.error(`The following error occured during Endpoint.update() for ${action.meta.key}`);
|
|
323
|
+
console.error(error);
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
entities,
|
|
327
|
+
indexes,
|
|
328
|
+
results,
|
|
329
|
+
entityMeta,
|
|
330
|
+
meta: {
|
|
331
|
+
...state.meta,
|
|
332
|
+
[action.meta.key]: {
|
|
333
|
+
date: action.meta.date,
|
|
334
|
+
expiresAt: action.meta.expiresAt,
|
|
335
|
+
prevExpiresAt: (_state$meta$action$me = state.meta[action.meta.key]) == null ? void 0 : _state$meta$action$me.expiresAt
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
optimistic: filterOptimistic(state, action),
|
|
339
|
+
lastReset: state.lastReset
|
|
340
|
+
};
|
|
341
|
+
// reducer must update the state, so in case of processing errors we simply compute the results inline
|
|
342
|
+
} catch (error) {
|
|
343
|
+
if (typeof error === 'object') {
|
|
344
|
+
error.message = `Error processing ${action.meta.key}\n\nFull Schema: ${JSON.stringify(action.meta.schema, undefined, 2)}\n\nError:\n${error.message}`;
|
|
345
|
+
if ('payload' in action) error.payload = action.payload;
|
|
346
|
+
error.status = 400;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// this is not always bubbled up, so let's double sure this doesn't fail silently
|
|
350
|
+
/* istanbul ignore else */
|
|
351
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
352
|
+
console.error(error);
|
|
353
|
+
}
|
|
354
|
+
return reduceError(state, action, error);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function reduceError(state, action, error) {
|
|
358
|
+
if (error.name === 'AbortError') {
|
|
359
|
+
// In case we abort simply undo the optimistic update and act like no fetch even occured
|
|
360
|
+
// We still want those watching promises from fetch directly to observed the abort, but we don't want to
|
|
361
|
+
// Trigger errors in this case. This means theoretically improperly built abortes useResource() could suspend forever.
|
|
362
|
+
return {
|
|
363
|
+
...state,
|
|
364
|
+
optimistic: filterOptimistic(state, action)
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
return {
|
|
368
|
+
...state,
|
|
369
|
+
meta: {
|
|
370
|
+
...state.meta,
|
|
371
|
+
[action.meta.key]: {
|
|
372
|
+
date: action.meta.date,
|
|
373
|
+
error,
|
|
374
|
+
expiresAt: action.meta.expiresAt,
|
|
375
|
+
errorPolicy: action.meta.errorPolicy == null ? void 0 : action.meta.errorPolicy(error)
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
optimistic: filterOptimistic(state, action)
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
/** Filter all requests with same serialization that did not start after the resolving request */
|
|
382
|
+
function filterOptimistic(state, resolvingAction) {
|
|
383
|
+
return state.optimistic.filter(optimisticAction => optimisticAction.meta.key !== resolvingAction.meta.key || (optimisticAction.type === OPTIMISTIC_TYPE ? optimisticAction.meta.fetchedAt !== resolvingAction.meta.fetchedAt : optimisticAction.meta.date > resolvingAction.meta.date));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function createReducer(controller) {
|
|
387
|
+
return function reducer(state, action) {
|
|
388
|
+
var _action$date;
|
|
389
|
+
if (!state) state = initialState;
|
|
390
|
+
switch (action.type) {
|
|
391
|
+
case GC_TYPE:
|
|
392
|
+
// inline deletes are fine as these should have 0 refcounts
|
|
393
|
+
action.entities.forEach(([key, pk]) => {
|
|
394
|
+
var _entities$key, _entityMeta$key;
|
|
395
|
+
(_entities$key = state.entities[key]) == null ? true : delete _entities$key[pk];
|
|
396
|
+
(_entityMeta$key = state.entityMeta[key]) == null ? true : delete _entityMeta$key[pk];
|
|
397
|
+
});
|
|
398
|
+
action.results.forEach(fetchKey => {
|
|
399
|
+
delete state.results[fetchKey];
|
|
400
|
+
delete state.meta[fetchKey];
|
|
401
|
+
});
|
|
402
|
+
return state;
|
|
403
|
+
case FETCH_TYPE:
|
|
404
|
+
return fetchReducer(state, action);
|
|
405
|
+
case OPTIMISTIC_TYPE:
|
|
406
|
+
// eslint-disable-next-line no-fallthrough
|
|
407
|
+
case SET_TYPE:
|
|
408
|
+
return setReducer(state, action, controller);
|
|
409
|
+
case INVALIDATEALL_TYPE:
|
|
410
|
+
case INVALIDATE_TYPE:
|
|
411
|
+
return invalidateReducer(state, action);
|
|
412
|
+
case RESET_TYPE:
|
|
413
|
+
if (process.env.NODE_ENV !== 'production' && action.date === undefined) {
|
|
414
|
+
console.warn(`${RESET_TYPE} sent without 'date' member. This is deprecated. Please use createReset() action creator to ensure correct action shape.`);
|
|
415
|
+
}
|
|
416
|
+
return {
|
|
417
|
+
...initialState,
|
|
418
|
+
lastReset: (_action$date = action.date) != null ? _action$date : Date.now()
|
|
419
|
+
};
|
|
420
|
+
default:
|
|
421
|
+
// A reducer must always return a valid state.
|
|
422
|
+
// Alternatively you can throw an error if an invalid action is dispatched.
|
|
423
|
+
return state;
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
const initialState = {
|
|
428
|
+
entities: {},
|
|
429
|
+
indexes: {},
|
|
430
|
+
results: {},
|
|
431
|
+
meta: {},
|
|
432
|
+
entityMeta: {},
|
|
433
|
+
optimistic: [],
|
|
434
|
+
lastReset: 0
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
var internal = /*#__PURE__*/Object.freeze({
|
|
438
|
+
__proto__: null,
|
|
439
|
+
inferResults: normalizr.inferResults,
|
|
440
|
+
DELETED: normalizr.DELETED,
|
|
441
|
+
RIC: RIC$1,
|
|
442
|
+
initialState: initialState
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
function createInvalidate(endpoint, {
|
|
446
|
+
args
|
|
447
|
+
}) {
|
|
448
|
+
return {
|
|
449
|
+
type: INVALIDATE_TYPE,
|
|
450
|
+
meta: {
|
|
451
|
+
key: endpoint.key(...args)
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function createInvalidateAll(testKey) {
|
|
457
|
+
return {
|
|
458
|
+
type: INVALIDATEALL_TYPE,
|
|
459
|
+
testKey
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function createReceive(endpoint, {
|
|
464
|
+
args,
|
|
465
|
+
fetchedAt,
|
|
466
|
+
response,
|
|
467
|
+
error = false
|
|
468
|
+
}) {
|
|
469
|
+
var _endpoint$errorExpiry, _endpoint$dataExpiryL;
|
|
470
|
+
const expiryLength = error ? (_endpoint$errorExpiry = endpoint.errorExpiryLength) != null ? _endpoint$errorExpiry : 1000 : (_endpoint$dataExpiryL = endpoint.dataExpiryLength) != null ? _endpoint$dataExpiryL : 60000;
|
|
471
|
+
/* istanbul ignore next */
|
|
472
|
+
if (process.env.NODE_ENV === 'development' && expiryLength < 0) {
|
|
473
|
+
throw new Error('Negative expiry length are not allowed.');
|
|
474
|
+
}
|
|
475
|
+
const now = Date.now();
|
|
476
|
+
const meta = {
|
|
477
|
+
args,
|
|
478
|
+
fetchedAt: fetchedAt != null ? fetchedAt : now,
|
|
479
|
+
date: now,
|
|
480
|
+
expiresAt: now + expiryLength,
|
|
481
|
+
// For legacy support; TODO: remove
|
|
482
|
+
schema: endpoint.schema,
|
|
483
|
+
key: endpoint.key(...args)
|
|
484
|
+
};
|
|
485
|
+
// For legacy support; TODO: remove
|
|
486
|
+
if (endpoint.update) meta.update = endpoint.update;
|
|
487
|
+
if (endpoint.errorPolicy) meta.errorPolicy = endpoint.errorPolicy;
|
|
488
|
+
const action = {
|
|
489
|
+
type: SET_TYPE,
|
|
490
|
+
payload: response,
|
|
491
|
+
endpoint: endpoint,
|
|
492
|
+
meta
|
|
493
|
+
};
|
|
494
|
+
if (error) action.error = true;
|
|
495
|
+
return action;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function createReset() {
|
|
499
|
+
return {
|
|
500
|
+
type: RESET_TYPE,
|
|
501
|
+
date: Date.now()
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function createSubscription(endpoint, {
|
|
506
|
+
args
|
|
507
|
+
}) {
|
|
508
|
+
return {
|
|
509
|
+
type: SUBSCRIBE_TYPE,
|
|
510
|
+
endpoint,
|
|
511
|
+
meta: {
|
|
512
|
+
args,
|
|
513
|
+
key: endpoint.key(...args),
|
|
514
|
+
fetch: () => endpoint(...args),
|
|
515
|
+
schema: endpoint.schema,
|
|
516
|
+
options: endpoint
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
function createUnsubscription(endpoint, {
|
|
521
|
+
args
|
|
522
|
+
}) {
|
|
523
|
+
return {
|
|
524
|
+
type: UNSUBSCRIBE_TYPE,
|
|
525
|
+
endpoint,
|
|
526
|
+
meta: {
|
|
527
|
+
args,
|
|
528
|
+
key: endpoint.key(...args),
|
|
529
|
+
options: endpoint
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function selectMeta(state, fetchKey) {
|
|
535
|
+
return state.meta[fetchKey];
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const unsetDispatch = action => {
|
|
539
|
+
throw new Error(`Dispatching while constructing your middleware is not allowed. ` + `Other middleware would not be applied to this dispatch.`);
|
|
540
|
+
};
|
|
541
|
+
const unsetState = () => {
|
|
542
|
+
// This is only the value until it is set by the CacheProvider
|
|
543
|
+
/* istanbul ignore next */
|
|
544
|
+
return initialState;
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Imperative control of Rest Hooks store
|
|
549
|
+
* @see https://resthooks.io/docs/api/Controller
|
|
550
|
+
*/
|
|
551
|
+
class Controller$1 {
|
|
552
|
+
/**
|
|
553
|
+
* Dispatches an action to Rest Hooks reducer.
|
|
554
|
+
*
|
|
555
|
+
* @see https://resthooks.io/docs/api/Controller#dispatch
|
|
556
|
+
*/
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Gets the latest state snapshot that is fully committed.
|
|
560
|
+
*
|
|
561
|
+
* This can be useful for imperative use-cases like event handlers.
|
|
562
|
+
* This should *not* be used to render; instead useSuspense() or useCache()
|
|
563
|
+
* @see https://resthooks.io/docs/api/Controller#getState
|
|
564
|
+
*/
|
|
565
|
+
|
|
566
|
+
constructor({
|
|
567
|
+
dispatch = unsetDispatch,
|
|
568
|
+
getState = unsetState,
|
|
569
|
+
globalCache = {
|
|
570
|
+
entities: {},
|
|
571
|
+
results: {}
|
|
572
|
+
}
|
|
573
|
+
} = {}) {
|
|
574
|
+
/*************** Action Dispatchers ***************/
|
|
575
|
+
/**
|
|
576
|
+
* Forces refetching and suspense on useSuspense with the same Endpoint and parameters.
|
|
577
|
+
* @see https://resthooks.io/docs/api/Controller#invalidate
|
|
578
|
+
*/
|
|
579
|
+
this.invalidate = (endpoint, ...args) => args[0] !== null ? this.dispatch(createInvalidate(endpoint, {
|
|
580
|
+
args: args
|
|
581
|
+
})) : Promise.resolve();
|
|
582
|
+
/**
|
|
583
|
+
* Forces refetching and suspense on useSuspense on all matching endpoint result keys.
|
|
584
|
+
* @see https://resthooks.io/docs/api/Controller#invalidateAll
|
|
585
|
+
*/
|
|
586
|
+
this.invalidateAll = options => this.dispatch(createInvalidateAll(key => options.testKey(key)));
|
|
587
|
+
/**
|
|
588
|
+
* Resets the entire Rest Hooks cache. All inflight requests will not resolve.
|
|
589
|
+
* @see https://resthooks.io/docs/api/Controller#resetEntireStore
|
|
590
|
+
*/
|
|
591
|
+
this.resetEntireStore = () => this.dispatch(createReset());
|
|
592
|
+
/**
|
|
593
|
+
* Stores response in cache for given Endpoint and args.
|
|
594
|
+
* @see https://resthooks.io/docs/api/Controller#set
|
|
595
|
+
*/
|
|
596
|
+
this.setResponse = (endpoint, ...rest) => {
|
|
597
|
+
const response = rest[rest.length - 1];
|
|
598
|
+
const action = createReceive(endpoint, {
|
|
599
|
+
args: rest.slice(0, rest.length - 1),
|
|
600
|
+
response
|
|
601
|
+
});
|
|
602
|
+
return this.dispatch(action);
|
|
603
|
+
};
|
|
604
|
+
// TODO: deprecate
|
|
605
|
+
/**
|
|
606
|
+
* Another name for setResponse
|
|
607
|
+
* @see https://resthooks.io/docs/api/Controller#setResponse
|
|
608
|
+
*/
|
|
609
|
+
/* istanbul ignore next */
|
|
610
|
+
this.receive = (endpoint, ...rest) => {
|
|
611
|
+
/* istanbul ignore next */
|
|
612
|
+
return this.setResponse(endpoint, ...rest);
|
|
613
|
+
};
|
|
614
|
+
/**
|
|
615
|
+
* Stores the result of Endpoint and args as the error provided.
|
|
616
|
+
* @see https://resthooks.io/docs/api/Controller#setError
|
|
617
|
+
*/
|
|
618
|
+
this.setError = (endpoint, ...rest) => {
|
|
619
|
+
const response = rest[rest.length - 1];
|
|
620
|
+
const action = createReceive(endpoint, {
|
|
621
|
+
args: rest.slice(0, rest.length - 1),
|
|
622
|
+
response,
|
|
623
|
+
error: true
|
|
624
|
+
});
|
|
625
|
+
return this.dispatch(action);
|
|
626
|
+
};
|
|
627
|
+
// TODO: deprecate
|
|
628
|
+
/**
|
|
629
|
+
* Another name for setError
|
|
630
|
+
* @see https://resthooks.io/docs/api/Controller#setError
|
|
631
|
+
*/
|
|
632
|
+
/* istanbul ignore next */
|
|
633
|
+
this.receiveError = (endpoint, ...rest) => {
|
|
634
|
+
/* istanbul ignore next */
|
|
635
|
+
return this.setError(endpoint, ...rest);
|
|
636
|
+
};
|
|
637
|
+
/**
|
|
638
|
+
* Resolves an inflight fetch. `fetchedAt` should `fetch`'s `createdAt`
|
|
639
|
+
* @see https://resthooks.io/docs/api/Controller#resolve
|
|
640
|
+
*/
|
|
641
|
+
this.resolve = (endpoint, meta) => {
|
|
642
|
+
return this.dispatch(createReceive(endpoint, meta));
|
|
643
|
+
};
|
|
644
|
+
/**
|
|
645
|
+
* Marks a new subscription to a given Endpoint.
|
|
646
|
+
* @see https://resthooks.io/docs/api/Controller#subscribe
|
|
647
|
+
*/
|
|
648
|
+
this.subscribe = (endpoint, ...args) => args[0] !== null ? this.dispatch(createSubscription(endpoint, {
|
|
649
|
+
args: args
|
|
650
|
+
})) : Promise.resolve();
|
|
651
|
+
/**
|
|
652
|
+
* Marks completion of subscription to a given Endpoint.
|
|
653
|
+
* @see https://resthooks.io/docs/api/Controller#unsubscribe
|
|
654
|
+
*/
|
|
655
|
+
this.unsubscribe = (endpoint, ...args) => args[0] !== null ? this.dispatch(createUnsubscription(endpoint, {
|
|
656
|
+
args: args
|
|
657
|
+
})) : Promise.resolve();
|
|
658
|
+
/*************** More ***************/
|
|
659
|
+
/* TODO:
|
|
660
|
+
abort = <E extends EndpointInterface>(
|
|
661
|
+
endpoint: E,
|
|
662
|
+
...args: readonly [...Parameters<E>]
|
|
663
|
+
): Promise<void>
|
|
664
|
+
*/
|
|
665
|
+
/**
|
|
666
|
+
* Gets a snapshot (https://resthooks.io/docs/api/Snapshot)
|
|
667
|
+
* @see https://resthooks.io/docs/api/Controller#snapshot
|
|
668
|
+
*/
|
|
669
|
+
this.snapshot = (state, fetchedAt) => {
|
|
670
|
+
return new Snapshot(this, state, fetchedAt);
|
|
671
|
+
};
|
|
672
|
+
/**
|
|
673
|
+
* Gets the error, if any, for a given endpoint. Returns undefined for no errors.
|
|
674
|
+
* @see https://resthooks.io/docs/api/Controller#getError
|
|
675
|
+
*/
|
|
676
|
+
this.getError = (endpoint, ...rest) => {
|
|
677
|
+
if (rest[0] === null) return;
|
|
678
|
+
const state = rest[rest.length - 1];
|
|
679
|
+
// this is typescript generics breaking
|
|
680
|
+
const args = rest.slice(0, rest.length - 1);
|
|
681
|
+
const key = endpoint.key(...args);
|
|
682
|
+
const meta = selectMeta(state, key);
|
|
683
|
+
const results = state.results[key];
|
|
684
|
+
if (results !== undefined && (meta == null ? void 0 : meta.errorPolicy) === 'soft') return;
|
|
685
|
+
return meta == null ? void 0 : meta.error;
|
|
686
|
+
};
|
|
687
|
+
/**
|
|
688
|
+
* Gets the (globally referentially stable) response for a given endpoint/args pair from state given.
|
|
689
|
+
* @see https://resthooks.io/docs/api/Controller#getResponse
|
|
690
|
+
*/
|
|
691
|
+
this.getResponse = (endpoint, ...rest) => {
|
|
692
|
+
const state = rest[rest.length - 1];
|
|
693
|
+
// this is typescript generics breaking
|
|
694
|
+
const args = rest.slice(0, rest.length - 1);
|
|
695
|
+
const isActive = args.length !== 1 || args[0] !== null;
|
|
696
|
+
const key = isActive ? endpoint.key(...args) : '';
|
|
697
|
+
const cacheResults = isActive ? state.results[key] : undefined;
|
|
698
|
+
const schema = endpoint.schema;
|
|
699
|
+
const meta = selectMeta(state, key);
|
|
700
|
+
let expiresAt = meta == null ? void 0 : meta.expiresAt;
|
|
701
|
+
let invalidResults = false;
|
|
702
|
+
let results;
|
|
703
|
+
if (cacheResults === undefined && endpoint.schema !== undefined) {
|
|
704
|
+
results = normalizr.inferResults(endpoint.schema, args, state.indexes, state.entities);
|
|
705
|
+
invalidResults = !normalizr.validateInference(results);
|
|
706
|
+
if (!expiresAt && invalidResults) expiresAt = 1;
|
|
707
|
+
} else {
|
|
708
|
+
results = cacheResults;
|
|
709
|
+
}
|
|
710
|
+
if (!isActive) {
|
|
711
|
+
return {
|
|
712
|
+
data: results,
|
|
713
|
+
expiryStatus: normalizr.ExpiryStatus.Valid,
|
|
714
|
+
expiresAt: Infinity
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
if (!endpoint.schema || !schemaHasEntity(endpoint.schema)) {
|
|
718
|
+
return {
|
|
719
|
+
data: results,
|
|
720
|
+
expiryStatus: meta != null && meta.invalidated ? normalizr.ExpiryStatus.Invalid : cacheResults && !endpoint.invalidIfStale ? normalizr.ExpiryStatus.Valid : normalizr.ExpiryStatus.InvalidIfStale,
|
|
721
|
+
expiresAt: expiresAt || 0
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// Warn users with bad configurations
|
|
726
|
+
/* istanbul ignore next */
|
|
727
|
+
if (process.env.NODE_ENV !== 'production' && schema && normalizr.isEntity(schema)) {
|
|
728
|
+
if (Array.isArray(results)) {
|
|
729
|
+
throw new Error(`fetch key ${key} has list results when single result is expected`);
|
|
730
|
+
}
|
|
731
|
+
if (typeof results === 'object') {
|
|
732
|
+
throw new Error(`fetch key ${key} has object results when entity's primary key (string) result is expected`);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
if (!this.globalCache.results[key]) this.globalCache.results[key] = new normalizr.WeakEntityMap();
|
|
736
|
+
|
|
737
|
+
// second argument is false if any entities are missing
|
|
738
|
+
// eslint-disable-next-line prefer-const
|
|
739
|
+
const {
|
|
740
|
+
data,
|
|
741
|
+
paths
|
|
742
|
+
} = normalizr.denormalizeCached(results, schema, state.entities, this.globalCache.entities, this.globalCache.results[key], args);
|
|
743
|
+
const invalidDenormalize = typeof data === 'symbol';
|
|
744
|
+
|
|
745
|
+
// fallback to entity expiry time
|
|
746
|
+
if (!expiresAt) {
|
|
747
|
+
expiresAt = entityExpiresAt(paths, state.entityMeta);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// https://resthooks.io/docs/concepts/expiry-policy#expiry-status
|
|
751
|
+
// we don't track the difference between stale or fresh because that is tied to triggering
|
|
752
|
+
// conditions
|
|
753
|
+
const expiryStatus = meta != null && meta.invalidated || invalidDenormalize && !(meta != null && meta.error) ? normalizr.ExpiryStatus.Invalid : invalidDenormalize || endpoint.invalidIfStale || invalidResults ? normalizr.ExpiryStatus.InvalidIfStale : normalizr.ExpiryStatus.Valid;
|
|
754
|
+
return {
|
|
755
|
+
data,
|
|
756
|
+
expiryStatus,
|
|
757
|
+
expiresAt
|
|
758
|
+
};
|
|
759
|
+
};
|
|
760
|
+
this.dispatch = dispatch;
|
|
761
|
+
this.getState = getState;
|
|
762
|
+
this.globalCache = globalCache;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// benchmark: https://www.measurethat.net/Benchmarks/Show/24691/0/min-reducer-vs-imperative-with-paths
|
|
767
|
+
// earliest expiry dictates age
|
|
768
|
+
function entityExpiresAt(paths, entityMeta) {
|
|
769
|
+
let expiresAt = Infinity;
|
|
770
|
+
for (const {
|
|
771
|
+
pk,
|
|
772
|
+
key
|
|
773
|
+
} of paths) {
|
|
774
|
+
var _entityMeta$key, _entityMeta$key$pk;
|
|
775
|
+
const entityExpiry = (_entityMeta$key = entityMeta[key]) == null ? void 0 : (_entityMeta$key$pk = _entityMeta$key[pk]) == null ? void 0 : _entityMeta$key$pk.expiresAt;
|
|
776
|
+
// expiresAt will always resolve to false with any comparison
|
|
777
|
+
if (entityExpiry < expiresAt) expiresAt = entityExpiry;
|
|
778
|
+
}
|
|
779
|
+
return expiresAt;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/** Determine whether the schema has any entities.
|
|
783
|
+
*
|
|
784
|
+
* Without entities, denormalization is not needed, and results should not be inferred.
|
|
785
|
+
*/
|
|
786
|
+
function schemaHasEntity(schema) {
|
|
787
|
+
if (normalizr.isEntity(schema)) return true;
|
|
788
|
+
if (Array.isArray(schema)) return schema.length !== 0 && schemaHasEntity(schema[0]);
|
|
789
|
+
if (schema && (typeof schema === 'object' || typeof schema === 'function')) {
|
|
790
|
+
const nestedSchema = 'schema' in schema ? schema.schema : schema;
|
|
791
|
+
if (typeof nestedSchema === 'function') {
|
|
792
|
+
return schemaHasEntity(nestedSchema);
|
|
793
|
+
}
|
|
794
|
+
return Object.values(nestedSchema).some(x => schemaHasEntity(x));
|
|
795
|
+
}
|
|
796
|
+
return false;
|
|
797
|
+
}
|
|
798
|
+
class Snapshot {
|
|
799
|
+
constructor(controller, state, fetchedAt = 0) {
|
|
800
|
+
this.state = void 0;
|
|
801
|
+
this.controller = void 0;
|
|
802
|
+
this.fetchedAt = void 0;
|
|
803
|
+
/*************** Data Access ***************/
|
|
804
|
+
/** @see https://resthooks.io/docs/api/Snapshot#getResponse */
|
|
805
|
+
this.getResponse = (endpoint, ...args) => {
|
|
806
|
+
return this.controller.getResponse(endpoint, ...args, this.state);
|
|
807
|
+
};
|
|
808
|
+
/** @see https://resthooks.io/docs/api/Snapshot#getError */
|
|
809
|
+
this.getError = (endpoint, ...args) => {
|
|
810
|
+
return this.controller.getError(endpoint, ...args, this.state);
|
|
811
|
+
};
|
|
812
|
+
this.state = state;
|
|
813
|
+
this.controller = controller;
|
|
814
|
+
this.fetchedAt = fetchedAt;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* Requesting a fetch to begin
|
|
820
|
+
*/
|
|
821
|
+
function createFetch(endpoint, {
|
|
822
|
+
args
|
|
823
|
+
}) {
|
|
824
|
+
const key = endpoint.key(...args);
|
|
825
|
+
let resolve = 0;
|
|
826
|
+
let reject = 0;
|
|
827
|
+
const promise = new Promise((a, b) => {
|
|
828
|
+
[resolve, reject] = [a, b];
|
|
829
|
+
});
|
|
830
|
+
const meta = {
|
|
831
|
+
schema: endpoint.schema,
|
|
832
|
+
type: endpoint.sideEffect ? 'mutate' : 'read',
|
|
833
|
+
args,
|
|
834
|
+
key,
|
|
835
|
+
throttle: !endpoint.sideEffect,
|
|
836
|
+
options: endpoint,
|
|
837
|
+
resolve,
|
|
838
|
+
reject,
|
|
839
|
+
promise,
|
|
840
|
+
createdAt: Date.now()
|
|
841
|
+
};
|
|
842
|
+
if (endpoint.update) {
|
|
843
|
+
meta.update = endpoint.update;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// TODO: Remove once EOL on this deprecated piece
|
|
847
|
+
/* istanbul ignore if */
|
|
848
|
+
if (endpoint.optimisticUpdate) {
|
|
849
|
+
meta.optimisticResponse = endpoint.optimisticUpdate(...args);
|
|
850
|
+
}
|
|
851
|
+
return {
|
|
852
|
+
type: FETCH_TYPE,
|
|
853
|
+
payload: () => endpoint(...args),
|
|
854
|
+
meta,
|
|
855
|
+
endpoint
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
class Controller extends Controller$1 {
|
|
860
|
+
constructor(..._args) {
|
|
861
|
+
super(..._args);
|
|
862
|
+
/**
|
|
863
|
+
* Fetches the endpoint with given args, updating the Rest Hooks cache with the response or error upon completion.
|
|
864
|
+
* @see https://resthooks.io/docs/api/Controller#fetch
|
|
865
|
+
*/
|
|
866
|
+
this.fetch = (endpoint, ...args) => {
|
|
867
|
+
const action = createFetch(endpoint, {
|
|
868
|
+
args
|
|
869
|
+
});
|
|
870
|
+
this.dispatch(action);
|
|
871
|
+
return action.meta.promise;
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
class ResetError extends Error {
|
|
877
|
+
constructor() {
|
|
878
|
+
super('Aborted due to RESET');
|
|
879
|
+
this.name = 'ResetError';
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/** Handles all async network dispatches
|
|
884
|
+
*
|
|
885
|
+
* Dedupes concurrent requests by keeping track of all fetches in flight
|
|
886
|
+
* and returning existing promises for requests already in flight.
|
|
887
|
+
*
|
|
888
|
+
* Interfaces with store via a redux-compatible middleware.
|
|
889
|
+
*
|
|
890
|
+
* @see https://resthooks.io/docs/api/NetworkManager
|
|
891
|
+
*/
|
|
892
|
+
class NetworkManager {
|
|
893
|
+
constructor(dataExpiryLength = 60000, errorExpiryLength = 1000) {
|
|
894
|
+
this.fetched = Object.create(null);
|
|
895
|
+
this.resolvers = {};
|
|
896
|
+
this.rejectors = {};
|
|
897
|
+
this.fetchedAt = {};
|
|
898
|
+
this.getState = () => initialState;
|
|
899
|
+
this.controller = new Controller();
|
|
900
|
+
this.dataExpiryLength = dataExpiryLength;
|
|
901
|
+
this.errorExpiryLength = errorExpiryLength;
|
|
902
|
+
this.middleware = ({
|
|
903
|
+
dispatch,
|
|
904
|
+
getState,
|
|
905
|
+
controller
|
|
906
|
+
}) => {
|
|
907
|
+
this.getState = getState;
|
|
908
|
+
this.controller = controller;
|
|
909
|
+
return next => action => {
|
|
910
|
+
var _action$endpoint;
|
|
911
|
+
switch (action.type) {
|
|
912
|
+
case FETCH_TYPE:
|
|
913
|
+
this.handleFetch(action, dispatch, controller);
|
|
914
|
+
// This is the only case that causes any state change
|
|
915
|
+
// It's important to intercept other fetches as we don't want to trigger reducers during
|
|
916
|
+
// render - so we need to stop 'readonly' fetches which can be triggered in render
|
|
917
|
+
if (action.meta.optimisticResponse !== undefined || ((_action$endpoint = action.endpoint) == null ? void 0 : _action$endpoint.getOptimisticResponse) !== undefined && action.endpoint.sideEffect) {
|
|
918
|
+
return next(action);
|
|
919
|
+
}
|
|
920
|
+
return Promise.resolve();
|
|
921
|
+
case SET_TYPE:
|
|
922
|
+
// only receive after new state is computed
|
|
923
|
+
return next(action).then(() => {
|
|
924
|
+
if (action.meta.key in this.fetched) {
|
|
925
|
+
var _controller$getState$;
|
|
926
|
+
// Note: meta *must* be set by reducer so this should be safe
|
|
927
|
+
const error = (_controller$getState$ = controller.getState().meta[action.meta.key]) == null ? void 0 : _controller$getState$.error;
|
|
928
|
+
// processing errors result in state meta having error, so we should reject the promise
|
|
929
|
+
if (error) {
|
|
930
|
+
// TODO: use only new action types
|
|
931
|
+
this.handleReceive(createReceiveError(error, action.meta));
|
|
932
|
+
} else {
|
|
933
|
+
this.handleReceive(action);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
});
|
|
937
|
+
case RESET_TYPE:
|
|
938
|
+
{
|
|
939
|
+
const rejectors = {
|
|
940
|
+
...this.rejectors
|
|
941
|
+
};
|
|
942
|
+
this.clearAll();
|
|
943
|
+
return next(action).then(() => {
|
|
944
|
+
// there could be external listeners to the promise
|
|
945
|
+
// this must happen after commit so our own rejector knows not to dispatch an error based on this
|
|
946
|
+
for (const k in rejectors) {
|
|
947
|
+
rejectors[k](new ResetError());
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
default:
|
|
952
|
+
return next(action);
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
/** Used by DevtoolsManager to determine whether to log an action */
|
|
959
|
+
skipLogging(action) {
|
|
960
|
+
/* istanbul ignore next */
|
|
961
|
+
return action.type === FETCH_TYPE && action.meta.key in this.fetched;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/** On mount */
|
|
965
|
+
init() {
|
|
966
|
+
delete this.cleanupDate;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
/** Ensures all promises are completed by rejecting remaining. */
|
|
970
|
+
cleanup() {
|
|
971
|
+
// ensure no dispatches after unmount
|
|
972
|
+
// this must be reversible (done in init) so useEffect() remains symmetric
|
|
973
|
+
this.cleanupDate = Date.now();
|
|
974
|
+
}
|
|
975
|
+
allSettled() {
|
|
976
|
+
const fetches = Object.values(this.fetched);
|
|
977
|
+
if (fetches.length) return Promise.allSettled(fetches);
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/** Clear all promise state */
|
|
981
|
+
clearAll() {
|
|
982
|
+
for (const k in this.rejectors) {
|
|
983
|
+
this.clear(k);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/** Clear promise state for a given key */
|
|
988
|
+
clear(key) {
|
|
989
|
+
this.fetched[key].catch(() => {});
|
|
990
|
+
delete this.resolvers[key];
|
|
991
|
+
delete this.rejectors[key];
|
|
992
|
+
delete this.fetched[key];
|
|
993
|
+
delete this.fetchedAt[key];
|
|
994
|
+
}
|
|
995
|
+
getLastReset() {
|
|
996
|
+
if (this.cleanupDate) return this.cleanupDate;
|
|
997
|
+
const lastReset = this.controller.getState().lastReset;
|
|
998
|
+
if (lastReset instanceof Date) return lastReset.valueOf();
|
|
999
|
+
if (typeof lastReset !== 'number') return -Infinity;
|
|
1000
|
+
return lastReset;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/** Called when middleware intercepts 'rest-hooks/fetch' action.
|
|
1004
|
+
*
|
|
1005
|
+
* Will then start a promise for a key and potentially start the network
|
|
1006
|
+
* fetch.
|
|
1007
|
+
*
|
|
1008
|
+
* Uses throttle only when instructed by action meta. This is valuable
|
|
1009
|
+
* for ensures mutation requests always go through.
|
|
1010
|
+
*/
|
|
1011
|
+
handleFetch(action, dispatch, controller) {
|
|
1012
|
+
const fetch = action.payload;
|
|
1013
|
+
const {
|
|
1014
|
+
key,
|
|
1015
|
+
throttle,
|
|
1016
|
+
resolve,
|
|
1017
|
+
reject
|
|
1018
|
+
} = action.meta;
|
|
1019
|
+
// TODO(breaking): remove support for Date type in 'Receive' action
|
|
1020
|
+
const createdAt = typeof action.meta.createdAt !== 'number' ? action.meta.createdAt.getTime() : action.meta.createdAt;
|
|
1021
|
+
const deferedFetch = () => {
|
|
1022
|
+
let promise = fetch();
|
|
1023
|
+
const resolvePromise = promise => promise.then(data => {
|
|
1024
|
+
resolve(data);
|
|
1025
|
+
return data;
|
|
1026
|
+
}).catch(error => {
|
|
1027
|
+
reject(error);
|
|
1028
|
+
throw error;
|
|
1029
|
+
});
|
|
1030
|
+
// schedule non-throttled resolutions in a microtask before receive
|
|
1031
|
+
// this enables users awaiting their fetch to trigger any react updates needed to deal
|
|
1032
|
+
// with upcoming changes because of the fetch (for instance avoiding suspense if something is deleted)
|
|
1033
|
+
if (!throttle && action.endpoint) {
|
|
1034
|
+
promise = resolvePromise(promise);
|
|
1035
|
+
}
|
|
1036
|
+
promise = promise.then(data => {
|
|
1037
|
+
let lastReset = this.getLastReset();
|
|
1038
|
+
|
|
1039
|
+
/* istanbul ignore else */
|
|
1040
|
+
if (process.env.NODE_ENV !== 'production' && isNaN(lastReset)) {
|
|
1041
|
+
console.error('state.lastReset is NaN. Only positive timestamps are valid.');
|
|
1042
|
+
lastReset = 0;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// don't update state with promises started before last clear
|
|
1046
|
+
if (createdAt >= lastReset) {
|
|
1047
|
+
// we still check for controller in case someone didn't have type protection since this didn't always exist
|
|
1048
|
+
if (action.endpoint && this.controller) {
|
|
1049
|
+
this.controller.resolve(action.endpoint, {
|
|
1050
|
+
args: action.meta.args,
|
|
1051
|
+
response: data,
|
|
1052
|
+
fetchedAt: createdAt
|
|
1053
|
+
});
|
|
1054
|
+
} else {
|
|
1055
|
+
var _action$meta$options$, _action$meta$options;
|
|
1056
|
+
// TODO(breaking): is this branch still possible? remove in next major update
|
|
1057
|
+
// does this throw if the reducer fails? - no because reducer is wrapped in try/catch
|
|
1058
|
+
this.controller.dispatch(createReceive$1(data, {
|
|
1059
|
+
...action.meta,
|
|
1060
|
+
fetchedAt: createdAt,
|
|
1061
|
+
dataExpiryLength: (_action$meta$options$ = (_action$meta$options = action.meta.options) == null ? void 0 : _action$meta$options.dataExpiryLength) != null ? _action$meta$options$ : this.dataExpiryLength
|
|
1062
|
+
}));
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
return data;
|
|
1066
|
+
}).catch(error => {
|
|
1067
|
+
const lastReset = this.getLastReset();
|
|
1068
|
+
// don't update state with promises started before last clear
|
|
1069
|
+
if (createdAt >= lastReset) {
|
|
1070
|
+
if (action.endpoint && this.controller) {
|
|
1071
|
+
this.controller.resolve(action.endpoint, {
|
|
1072
|
+
args: action.meta.args,
|
|
1073
|
+
response: error,
|
|
1074
|
+
fetchedAt: createdAt,
|
|
1075
|
+
error: true
|
|
1076
|
+
});
|
|
1077
|
+
} else {
|
|
1078
|
+
var _action$meta$options$2, _action$meta$options2;
|
|
1079
|
+
this.controller.dispatch(createReceiveError(error, {
|
|
1080
|
+
...action.meta,
|
|
1081
|
+
errorExpiryLength: (_action$meta$options$2 = (_action$meta$options2 = action.meta.options) == null ? void 0 : _action$meta$options2.errorExpiryLength) != null ? _action$meta$options$2 : this.errorExpiryLength,
|
|
1082
|
+
fetchedAt: createdAt
|
|
1083
|
+
}));
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
throw error;
|
|
1087
|
+
});
|
|
1088
|
+
// legacy behavior schedules resolution after dispatch
|
|
1089
|
+
if (!throttle && !action.endpoint) {
|
|
1090
|
+
promise = resolvePromise(promise);
|
|
1091
|
+
}
|
|
1092
|
+
return promise;
|
|
1093
|
+
};
|
|
1094
|
+
if (throttle) {
|
|
1095
|
+
return this.throttle(key, deferedFetch, createdAt).then(data => resolve(data)).catch(error => reject(error));
|
|
1096
|
+
} else {
|
|
1097
|
+
return deferedFetch().catch(() => {});
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
/** Called when middleware intercepts a receive action.
|
|
1102
|
+
*
|
|
1103
|
+
* Will resolve the promise associated with receive key.
|
|
1104
|
+
*/
|
|
1105
|
+
handleReceive(action) {
|
|
1106
|
+
// this can still turn out to be untrue since this is async
|
|
1107
|
+
if (action.meta.key in this.fetched) {
|
|
1108
|
+
let promiseHandler;
|
|
1109
|
+
if (action.error) {
|
|
1110
|
+
promiseHandler = this.rejectors[action.meta.key];
|
|
1111
|
+
} else {
|
|
1112
|
+
promiseHandler = this.resolvers[action.meta.key];
|
|
1113
|
+
}
|
|
1114
|
+
promiseHandler(action.payload);
|
|
1115
|
+
// since we're resolved we no longer need to keep track of this promise
|
|
1116
|
+
this.clear(action.meta.key);
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
/** Attaches NetworkManager to store
|
|
1121
|
+
*
|
|
1122
|
+
* Intercepts 'rest-hooks/fetch' actions to start requests.
|
|
1123
|
+
*
|
|
1124
|
+
* Resolve/rejects a request when matching 'rest-hooks/receive' event
|
|
1125
|
+
* is seen.
|
|
1126
|
+
*/
|
|
1127
|
+
getMiddleware() {
|
|
1128
|
+
return this.middleware;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
/** Ensures only one request for a given key is in flight at any time
|
|
1132
|
+
*
|
|
1133
|
+
* Uses key to either retrieve in-flight promise, or if not
|
|
1134
|
+
* create a new promise and call fetch.
|
|
1135
|
+
*
|
|
1136
|
+
* Note: The new promise is not actually tied to fetch at all,
|
|
1137
|
+
* but is resolved when the expected 'recieve' action is processed.
|
|
1138
|
+
* This ensures promises are resolved only once their data is processed
|
|
1139
|
+
* by the reducer.
|
|
1140
|
+
*/
|
|
1141
|
+
throttle(key, fetch, createdAt) {
|
|
1142
|
+
const lastReset = this.getLastReset();
|
|
1143
|
+
// we're already fetching so reuse the promise
|
|
1144
|
+
// fetches after reset do not count
|
|
1145
|
+
if (key in this.fetched && this.fetchedAt[key] > lastReset) {
|
|
1146
|
+
return this.fetched[key];
|
|
1147
|
+
}
|
|
1148
|
+
this.fetched[key] = new Promise((resolve, reject) => {
|
|
1149
|
+
this.resolvers[key] = resolve;
|
|
1150
|
+
this.rejectors[key] = reject;
|
|
1151
|
+
});
|
|
1152
|
+
this.fetchedAt[key] = createdAt;
|
|
1153
|
+
|
|
1154
|
+
// since our real promise is resolved via the wrapReducer(),
|
|
1155
|
+
// we should just stop all errors here.
|
|
1156
|
+
// TODO: decouple this from useFetcher() (that's what's dispatching the error the resolves in here)
|
|
1157
|
+
RIC$1(() => {
|
|
1158
|
+
fetch().catch(() => null);
|
|
1159
|
+
}, {
|
|
1160
|
+
timeout: 500
|
|
1161
|
+
});
|
|
1162
|
+
return this.fetched[key];
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
/* istanbul ignore file */
|
|
1167
|
+
/**
|
|
1168
|
+
* @deprecated use createReducer instead
|
|
1169
|
+
*/
|
|
1170
|
+
const reducer = createReducer(new Controller());
|
|
1171
|
+
var reducer$1 = reducer;
|
|
1172
|
+
|
|
1173
|
+
function applyManager(managers, controller) {
|
|
1174
|
+
return managers.map(manager => {
|
|
1175
|
+
const middleware = manager.getMiddleware();
|
|
1176
|
+
return ({
|
|
1177
|
+
dispatch,
|
|
1178
|
+
getState
|
|
1179
|
+
}) => {
|
|
1180
|
+
controller.dispatch = dispatch;
|
|
1181
|
+
controller.getState = getState;
|
|
1182
|
+
// this is needed for backwards compatibility as we added 'controller' prop previously
|
|
1183
|
+
const API = Object.create(controller, {
|
|
1184
|
+
controller: {
|
|
1185
|
+
value: controller
|
|
1186
|
+
}
|
|
1187
|
+
});
|
|
1188
|
+
// controller is a superset of the middleware API
|
|
1189
|
+
return middleware(API);
|
|
1190
|
+
};
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
/* These should be compatible with redux */
|
|
1195
|
+
|
|
1196
|
+
var newActions = /*#__PURE__*/Object.freeze({
|
|
1197
|
+
__proto__: null
|
|
1198
|
+
});
|
|
1199
|
+
|
|
1200
|
+
class BrowserConnectionListener {
|
|
1201
|
+
isOnline() {
|
|
1202
|
+
if (navigator.onLine !== undefined) {
|
|
1203
|
+
return navigator.onLine;
|
|
1204
|
+
}
|
|
1205
|
+
return true;
|
|
1206
|
+
}
|
|
1207
|
+
addOnlineListener(handler) {
|
|
1208
|
+
addEventListener('online', handler);
|
|
1209
|
+
}
|
|
1210
|
+
removeOnlineListener(handler) {
|
|
1211
|
+
removeEventListener('online', handler);
|
|
1212
|
+
}
|
|
1213
|
+
addOfflineListener(handler) {
|
|
1214
|
+
addEventListener('offline', handler);
|
|
1215
|
+
}
|
|
1216
|
+
removeOfflineListener(handler) {
|
|
1217
|
+
removeEventListener('offline', handler);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
class AlwaysOnlineConnectionListener {
|
|
1221
|
+
isOnline() {
|
|
1222
|
+
/* istanbul ignore next */
|
|
1223
|
+
return true;
|
|
1224
|
+
}
|
|
1225
|
+
addOnlineListener() {}
|
|
1226
|
+
removeOnlineListener() {}
|
|
1227
|
+
addOfflineListener() {}
|
|
1228
|
+
removeOfflineListener() {}
|
|
1229
|
+
}
|
|
1230
|
+
let DefaultConnectionListener;
|
|
1231
|
+
/* istanbul ignore if */
|
|
1232
|
+
if (typeof navigator !== 'undefined' && typeof addEventListener === 'function') {
|
|
1233
|
+
DefaultConnectionListener = BrowserConnectionListener;
|
|
1234
|
+
} else {
|
|
1235
|
+
/* istanbul ignore next */
|
|
1236
|
+
DefaultConnectionListener = AlwaysOnlineConnectionListener;
|
|
1237
|
+
}
|
|
1238
|
+
var DefaultConnectionListener$1 = DefaultConnectionListener;
|
|
1239
|
+
|
|
1240
|
+
/**
|
|
1241
|
+
* PollingSubscription keeps a given resource updated by
|
|
1242
|
+
* dispatching a fetch at a rate equal to the minimum update
|
|
1243
|
+
* interval requested.
|
|
1244
|
+
*
|
|
1245
|
+
* @see https://resthooks.io/docs/api/PollingSubscription
|
|
1246
|
+
*/
|
|
1247
|
+
class PollingSubscription {
|
|
1248
|
+
constructor({
|
|
1249
|
+
key,
|
|
1250
|
+
schema,
|
|
1251
|
+
fetch,
|
|
1252
|
+
frequency,
|
|
1253
|
+
getState
|
|
1254
|
+
}, dispatch, connectionListener) {
|
|
1255
|
+
this.frequencyHistogram = new Map();
|
|
1256
|
+
/** What happens when browser goes offline */
|
|
1257
|
+
this.offlineListener = () => {
|
|
1258
|
+
// this clears existing listeners, so no need to clear offline listener
|
|
1259
|
+
this.cleanup();
|
|
1260
|
+
this.connectionListener.addOnlineListener(this.onlineListener);
|
|
1261
|
+
};
|
|
1262
|
+
/** What happens when browser comes online */
|
|
1263
|
+
this.onlineListener = () => {
|
|
1264
|
+
this.connectionListener.removeOnlineListener(this.onlineListener);
|
|
1265
|
+
const now = Date.now();
|
|
1266
|
+
this.startId = setTimeout(() => {
|
|
1267
|
+
if (this.startId) {
|
|
1268
|
+
delete this.startId;
|
|
1269
|
+
this.update();
|
|
1270
|
+
this.run();
|
|
1271
|
+
} else if (process.env.NODE_ENV !== 'production') {
|
|
1272
|
+
console.warn(`Poll setTimeout for ${this.key} still running, but timeoutId deleted`);
|
|
1273
|
+
}
|
|
1274
|
+
}, Math.max(0, this.lastFetchTime() - now + this.frequency));
|
|
1275
|
+
this.connectionListener.addOfflineListener(this.offlineListener);
|
|
1276
|
+
};
|
|
1277
|
+
if (frequency === undefined) throw new Error('frequency needed for polling subscription');
|
|
1278
|
+
this.schema = schema;
|
|
1279
|
+
this.fetch = fetch;
|
|
1280
|
+
this.frequency = frequency;
|
|
1281
|
+
this.key = key;
|
|
1282
|
+
this.frequencyHistogram.set(this.frequency, 1);
|
|
1283
|
+
this.dispatch = dispatch;
|
|
1284
|
+
this.getState = getState;
|
|
1285
|
+
this.connectionListener = connectionListener || new DefaultConnectionListener$1();
|
|
1286
|
+
|
|
1287
|
+
// Kickstart running since this is initialized after the online notif is sent
|
|
1288
|
+
if (this.connectionListener.isOnline()) {
|
|
1289
|
+
this.onlineListener();
|
|
1290
|
+
} else {
|
|
1291
|
+
this.offlineListener();
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
/** Subscribe to a frequency */
|
|
1296
|
+
add(frequency) {
|
|
1297
|
+
if (frequency === undefined) return;
|
|
1298
|
+
if (this.frequencyHistogram.has(frequency)) {
|
|
1299
|
+
this.frequencyHistogram.set(frequency, this.frequencyHistogram.get(frequency) + 1);
|
|
1300
|
+
} else {
|
|
1301
|
+
this.frequencyHistogram.set(frequency, 1);
|
|
1302
|
+
|
|
1303
|
+
// new min so restart service
|
|
1304
|
+
if (frequency < this.frequency) {
|
|
1305
|
+
this.frequency = frequency;
|
|
1306
|
+
this.run();
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
/** Unsubscribe from a frequency */
|
|
1312
|
+
remove(frequency) {
|
|
1313
|
+
if (frequency === undefined) return false;
|
|
1314
|
+
if (this.frequencyHistogram.has(frequency)) {
|
|
1315
|
+
this.frequencyHistogram.set(frequency, this.frequencyHistogram.get(frequency) - 1);
|
|
1316
|
+
if (this.frequencyHistogram.get(frequency) < 1) {
|
|
1317
|
+
this.frequencyHistogram.delete(frequency);
|
|
1318
|
+
|
|
1319
|
+
// nothing subscribed to this anymore...it is invalid
|
|
1320
|
+
if (this.frequencyHistogram.size === 0) {
|
|
1321
|
+
this.cleanup();
|
|
1322
|
+
return true;
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
// this was the min, so find the next size
|
|
1326
|
+
if (frequency <= this.frequency) {
|
|
1327
|
+
this.frequency = Math.min(...this.frequencyHistogram.keys());
|
|
1328
|
+
this.run();
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
} /* istanbul ignore next */else if (process.env.NODE_ENV !== 'production') {
|
|
1332
|
+
console.error(`Mismatched remove: ${frequency} is not subscribed for ${this.key}`);
|
|
1333
|
+
}
|
|
1334
|
+
return false;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
/** Cleanup means clearing out background interval. */
|
|
1338
|
+
cleanup() {
|
|
1339
|
+
if (this.intervalId) {
|
|
1340
|
+
clearInterval(this.intervalId);
|
|
1341
|
+
delete this.intervalId;
|
|
1342
|
+
}
|
|
1343
|
+
if (this.lastIntervalId) {
|
|
1344
|
+
clearInterval(this.lastIntervalId);
|
|
1345
|
+
delete this.lastIntervalId;
|
|
1346
|
+
}
|
|
1347
|
+
if (this.startId) {
|
|
1348
|
+
clearTimeout(this.startId);
|
|
1349
|
+
delete this.startId;
|
|
1350
|
+
}
|
|
1351
|
+
this.connectionListener.removeOnlineListener(this.onlineListener);
|
|
1352
|
+
this.connectionListener.removeOfflineListener(this.offlineListener);
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
/** Trigger request for latest resource */
|
|
1356
|
+
update() {
|
|
1357
|
+
const endpoint = () => this.fetch();
|
|
1358
|
+
endpoint.schema = this.schema;
|
|
1359
|
+
endpoint.key = () => this.key;
|
|
1360
|
+
endpoint.dataExpiryLength = this.frequency / 2;
|
|
1361
|
+
endpoint.errorExpiryLength = this.frequency / 10;
|
|
1362
|
+
endpoint.errorPolicy = () => 'soft';
|
|
1363
|
+
const action = createFetch(endpoint, {
|
|
1364
|
+
args: []
|
|
1365
|
+
});
|
|
1366
|
+
// stop any errors here from bubbling
|
|
1367
|
+
action.meta.promise.catch(e => null);
|
|
1368
|
+
this.dispatch(action);
|
|
1369
|
+
}
|
|
1370
|
+
/** Run polling process with current frequency
|
|
1371
|
+
*
|
|
1372
|
+
* Will clean up old poll interval on next run
|
|
1373
|
+
*/
|
|
1374
|
+
run() {
|
|
1375
|
+
if (this.startId) return;
|
|
1376
|
+
if (this.intervalId) this.lastIntervalId = this.intervalId;
|
|
1377
|
+
this.intervalId = setInterval(() => {
|
|
1378
|
+
// since we don't know how long into the last poll it was before resetting
|
|
1379
|
+
// we wait til the next fetch to clear old intervals
|
|
1380
|
+
if (this.lastIntervalId) {
|
|
1381
|
+
clearInterval(this.lastIntervalId);
|
|
1382
|
+
delete this.lastIntervalId;
|
|
1383
|
+
}
|
|
1384
|
+
if (this.intervalId) this.update();else if (process.env.NODE_ENV !== 'production') {
|
|
1385
|
+
console.warn(`Poll intervalId for ${this.key} still running, but intervalId deleted`);
|
|
1386
|
+
}
|
|
1387
|
+
}, this.frequency);
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
/** Last fetch time */
|
|
1391
|
+
lastFetchTime() {
|
|
1392
|
+
var _this$getState$meta$t, _this$getState$meta$t2;
|
|
1393
|
+
return (_this$getState$meta$t = (_this$getState$meta$t2 = this.getState().meta[this.key]) == null ? void 0 : _this$getState$meta$t2.date) != null ? _this$getState$meta$t : 0;
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
/** Properties sent to Subscription constructor */
|
|
1398
|
+
|
|
1399
|
+
/** Interface handling a single resource subscription */
|
|
1400
|
+
|
|
1401
|
+
/** The static class that constructs Subscription */
|
|
1402
|
+
|
|
1403
|
+
/** Handles subscription actions -> fetch or receive actions
|
|
1404
|
+
*
|
|
1405
|
+
* Constructor takes a SubscriptionConstructable class to control how
|
|
1406
|
+
* subscriptions are handled. (e.g., polling, websockets)
|
|
1407
|
+
*
|
|
1408
|
+
* @see https://resthooks.io/docs/api/SubscriptionManager
|
|
1409
|
+
*/
|
|
1410
|
+
class SubscriptionManager {
|
|
1411
|
+
constructor(Subscription) {
|
|
1412
|
+
this.subscriptions = {};
|
|
1413
|
+
this.Subscription = Subscription;
|
|
1414
|
+
this.middleware = ({
|
|
1415
|
+
dispatch,
|
|
1416
|
+
getState
|
|
1417
|
+
}) => {
|
|
1418
|
+
return next => action => {
|
|
1419
|
+
switch (action.type) {
|
|
1420
|
+
case SUBSCRIBE_TYPE:
|
|
1421
|
+
try {
|
|
1422
|
+
this.handleSubscribe(action, dispatch, getState);
|
|
1423
|
+
} catch (e) {
|
|
1424
|
+
console.error(e);
|
|
1425
|
+
}
|
|
1426
|
+
return Promise.resolve();
|
|
1427
|
+
case UNSUBSCRIBE_TYPE:
|
|
1428
|
+
this.handleUnsubscribe(action, dispatch);
|
|
1429
|
+
return Promise.resolve();
|
|
1430
|
+
default:
|
|
1431
|
+
return next(action);
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
/** Ensures all subscriptions are cleaned up. */
|
|
1438
|
+
cleanup() {
|
|
1439
|
+
for (const key in this.subscriptions) {
|
|
1440
|
+
this.subscriptions[key].cleanup();
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
/** Called when middleware intercepts 'rest-hooks/subscribe' action.
|
|
1445
|
+
*
|
|
1446
|
+
*/
|
|
1447
|
+
handleSubscribe(action, dispatch, getState) {
|
|
1448
|
+
let options;
|
|
1449
|
+
if (action.endpoint) {
|
|
1450
|
+
const {
|
|
1451
|
+
endpoint
|
|
1452
|
+
} = action;
|
|
1453
|
+
const {
|
|
1454
|
+
args
|
|
1455
|
+
} = action.meta;
|
|
1456
|
+
options = {
|
|
1457
|
+
schema: endpoint.schema,
|
|
1458
|
+
fetch: () => endpoint(...args),
|
|
1459
|
+
frequency: endpoint.pollFrequency,
|
|
1460
|
+
key: endpoint.key(...args),
|
|
1461
|
+
getState
|
|
1462
|
+
};
|
|
1463
|
+
} else {
|
|
1464
|
+
var _action$meta$options;
|
|
1465
|
+
options = {
|
|
1466
|
+
key: action.meta.key,
|
|
1467
|
+
frequency: (_action$meta$options = action.meta.options) == null ? void 0 : _action$meta$options.pollFrequency,
|
|
1468
|
+
schema: action.meta.schema,
|
|
1469
|
+
fetch: action.meta.fetch,
|
|
1470
|
+
getState
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1473
|
+
if (options.key in this.subscriptions) {
|
|
1474
|
+
this.subscriptions[options.key].add(options.frequency);
|
|
1475
|
+
} else {
|
|
1476
|
+
this.subscriptions[options.key] = new this.Subscription(options, dispatch);
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
/** Called when middleware intercepts 'rest-hooks/unsubscribe' action.
|
|
1481
|
+
*
|
|
1482
|
+
*/
|
|
1483
|
+
handleUnsubscribe(action, dispatch) {
|
|
1484
|
+
var _action$meta$options2;
|
|
1485
|
+
const key = action.meta.key;
|
|
1486
|
+
const frequency = (_action$meta$options2 = action.meta.options) == null ? void 0 : _action$meta$options2.pollFrequency;
|
|
1487
|
+
|
|
1488
|
+
/* istanbul ignore else */
|
|
1489
|
+
if (key in this.subscriptions) {
|
|
1490
|
+
const empty = this.subscriptions[key].remove(frequency);
|
|
1491
|
+
if (empty) {
|
|
1492
|
+
delete this.subscriptions[key];
|
|
1493
|
+
}
|
|
1494
|
+
} else if (process.env.NODE_ENV !== 'production') {
|
|
1495
|
+
console.error(`Mismatched unsubscribe: ${key} is not subscribed`);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
/** Attaches Manager to store
|
|
1500
|
+
*
|
|
1501
|
+
* Intercepts 'rest-hooks/subscribe'/'rest-hooks/unsubscribe' to register resources that
|
|
1502
|
+
* need to be kept up to date.
|
|
1503
|
+
*
|
|
1504
|
+
* Will possibly dispatch 'rest-hooks/fetch' or 'rest-hooks/receive' to keep resources fresh
|
|
1505
|
+
*
|
|
1506
|
+
*/
|
|
1507
|
+
getMiddleware() {
|
|
1508
|
+
return this.middleware;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
var _globalThis$document;
|
|
1513
|
+
const HASINTL = typeof Intl !== 'undefined';
|
|
1514
|
+
const DEFAULT_CONFIG = {
|
|
1515
|
+
name: `Rest Hooks: ${(_globalThis$document = globalThis.document) == null ? void 0 : _globalThis$document.title}`,
|
|
1516
|
+
autoPause: true,
|
|
1517
|
+
serialize: {
|
|
1518
|
+
options: undefined,
|
|
1519
|
+
/* istanbul ignore next */
|
|
1520
|
+
replacer: HASINTL ? (key, value) => {
|
|
1521
|
+
if (typeof value === 'number' && typeof key === 'string' && isFinite(value) && (key === 'date' || key.endsWith('At'))) {
|
|
1522
|
+
return Intl.DateTimeFormat('en-US', {
|
|
1523
|
+
hour: 'numeric',
|
|
1524
|
+
minute: 'numeric',
|
|
1525
|
+
second: 'numeric',
|
|
1526
|
+
fractionalSecondDigits: 3
|
|
1527
|
+
}).format(value);
|
|
1528
|
+
}
|
|
1529
|
+
return value;
|
|
1530
|
+
} : undefined
|
|
1531
|
+
}
|
|
1532
|
+
};
|
|
1533
|
+
|
|
1534
|
+
/** Integrates with https://github.com/reduxjs/redux-devtools
|
|
1535
|
+
*
|
|
1536
|
+
* Options: https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/API/Arguments.md
|
|
1537
|
+
*
|
|
1538
|
+
* @see https://resthooks.io/docs/api/DevToolsManager
|
|
1539
|
+
*/
|
|
1540
|
+
class DevToolsManager {
|
|
1541
|
+
constructor(config, skipLogging) {
|
|
1542
|
+
/* istanbul ignore next */
|
|
1543
|
+
this.devTools = typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__.connect({
|
|
1544
|
+
...DEFAULT_CONFIG,
|
|
1545
|
+
config
|
|
1546
|
+
});
|
|
1547
|
+
|
|
1548
|
+
/* istanbul ignore if */
|
|
1549
|
+
/* istanbul ignore next */
|
|
1550
|
+
if (this.devTools) {
|
|
1551
|
+
this.middleware = controller => {
|
|
1552
|
+
const reducer = createReducer(controller);
|
|
1553
|
+
return next => action => {
|
|
1554
|
+
const ret = next(action);
|
|
1555
|
+
ret.then(() => {
|
|
1556
|
+
if (skipLogging != null && skipLogging(action)) return;
|
|
1557
|
+
const state = controller.getState();
|
|
1558
|
+
this.devTools.send(action, state.optimistic.reduce(reducer, state), undefined, 'REST_HOOKS');
|
|
1559
|
+
});
|
|
1560
|
+
return ret;
|
|
1561
|
+
};
|
|
1562
|
+
};
|
|
1563
|
+
} else {
|
|
1564
|
+
this.middleware = () => next => action => next(action);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
/** Called when initial state is ready */
|
|
1569
|
+
init(state) {
|
|
1570
|
+
/* istanbul ignore if */
|
|
1571
|
+
if (this.devTools) this.devTools.init(state);
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
/** Ensures all subscriptions are cleaned up. */
|
|
1575
|
+
cleanup() {}
|
|
1576
|
+
|
|
1577
|
+
/** Attaches Manager to store
|
|
1578
|
+
*
|
|
1579
|
+
*/
|
|
1580
|
+
getMiddleware() {
|
|
1581
|
+
return this.middleware;
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
/** Handling network unauthorized indicators like HTTP 401
|
|
1586
|
+
*
|
|
1587
|
+
* @see https://resthooks.io/docs/api/LogoutManager
|
|
1588
|
+
*/
|
|
1589
|
+
class LogoutManager {
|
|
1590
|
+
constructor({
|
|
1591
|
+
handleLogout,
|
|
1592
|
+
shouldLogout
|
|
1593
|
+
} = {}) {
|
|
1594
|
+
if (handleLogout) this.handleLogout = handleLogout;
|
|
1595
|
+
if (shouldLogout) this.shouldLogout = shouldLogout;
|
|
1596
|
+
this.middleware = controller => next => async action => {
|
|
1597
|
+
await next(action);
|
|
1598
|
+
if (action.type === SET_TYPE && action.error && this.shouldLogout(action.payload)) {
|
|
1599
|
+
this.handleLogout(controller);
|
|
1600
|
+
}
|
|
1601
|
+
};
|
|
1602
|
+
}
|
|
1603
|
+
cleanup() {}
|
|
1604
|
+
getMiddleware() {
|
|
1605
|
+
return this.middleware;
|
|
1606
|
+
}
|
|
1607
|
+
shouldLogout(error) {
|
|
1608
|
+
// 401 indicates reauthorization is needed
|
|
1609
|
+
return error.status === 401;
|
|
1610
|
+
}
|
|
1611
|
+
handleLogout(controller) {
|
|
1612
|
+
controller.resetEntireStore();
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
// this further restricts the types to be future compatible
|
|
1617
|
+
|
|
1618
|
+
Object.hasOwn = Object.hasOwn || /* istanbul ignore next */function hasOwn(it, key) {
|
|
1619
|
+
return Object.prototype.hasOwnProperty.call(it, key);
|
|
1620
|
+
};
|
|
1621
|
+
|
|
1622
|
+
Object.defineProperty(exports, 'ExpiryStatus', {
|
|
1623
|
+
enumerable: true,
|
|
1624
|
+
get: function () { return normalizr.ExpiryStatus; }
|
|
1625
|
+
});
|
|
1626
|
+
exports.Controller = Controller;
|
|
1627
|
+
exports.DefaultConnectionListener = DefaultConnectionListener$1;
|
|
1628
|
+
exports.DevToolsManager = DevToolsManager;
|
|
1629
|
+
exports.LogoutManager = LogoutManager;
|
|
1630
|
+
exports.NetworkManager = NetworkManager;
|
|
1631
|
+
exports.PollingSubscription = PollingSubscription;
|
|
1632
|
+
exports.ResetError = ResetError;
|
|
1633
|
+
exports.SubscriptionManager = SubscriptionManager;
|
|
1634
|
+
exports.__INTERNAL__ = internal;
|
|
1635
|
+
exports.actionTypes = actionTypes;
|
|
1636
|
+
exports.applyManager = applyManager;
|
|
1637
|
+
exports.createFetch = createFetch;
|
|
1638
|
+
exports.createReceive = createReceive;
|
|
1639
|
+
exports.createReducer = createReducer;
|
|
1640
|
+
exports.initialState = initialState;
|
|
1641
|
+
exports.legacyActions = index;
|
|
1642
|
+
exports.newActions = newActions;
|
|
1643
|
+
exports.reducer = reducer$1;
|