@khanacademy/wonder-blocks-data 11.0.16 → 13.0.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/CHANGELOG.md +24 -0
- package/dist/components/data.d.ts +2 -2
- package/dist/es/index.js +24 -18
- package/dist/hooks/use-gql.d.ts +5 -1
- package/dist/hooks/use-hydratable-effect.d.ts +6 -6
- package/dist/index.js +24 -18
- package/dist/util/status.d.ts +4 -3
- package/dist/util/types.d.ts +8 -6
- package/package.json +3 -3
- package/src/components/__tests__/data.test.tsx +6 -13
- package/src/components/data.ts +2 -4
- package/src/hooks/__tests__/use-cached-effect.test.tsx +79 -40
- package/src/hooks/__tests__/use-gql-router-context.test.tsx +1 -2
- package/src/hooks/__tests__/use-hydratable-effect.test.ts +1 -2
- package/src/hooks/__tests__/use-request-interception.test.tsx +2 -5
- package/src/hooks/__tests__/use-server-effect.test.ts +3 -6
- package/src/hooks/__tests__/use-shared-cache.test.ts +17 -13
- package/src/hooks/use-cached-effect.ts +24 -20
- package/src/hooks/use-gql.ts +12 -9
- package/src/hooks/use-hydratable-effect.ts +6 -7
- package/src/hooks/use-request-interception.ts +13 -11
- package/src/hooks/use-shared-cache.ts +4 -2
- package/src/util/__tests__/request-api.test.ts +2 -1
- package/src/util/__tests__/request-tracking.test.tsx +5 -9
- package/src/util/__tests__/result-from-cache-response.test.ts +2 -2
- package/src/util/__tests__/serializable-in-memory-cache.test.ts +1 -2
- package/src/util/__tests__/ssr-cache.test.ts +2 -4
- package/src/util/__tests__/to-gql-operation.test.ts +2 -4
- package/src/util/graphql-document-node-parser.ts +6 -6
- package/src/util/merge-gql-context.ts +2 -1
- package/src/util/request-tracking.ts +6 -2
- package/src/util/ssr-cache.ts +11 -8
- package/src/util/status.ts +6 -0
- package/src/util/types.ts +9 -7
- package/tsconfig-build.tsbuildinfo +1 -1
- package/dist/components/data.js.flow +0 -63
- package/dist/components/gql-router.js.flow +0 -33
- package/dist/components/intercept-context.js.flow +0 -18
- package/dist/components/intercept-requests.js.flow +0 -51
- package/dist/components/track-data.js.flow +0 -16
- package/dist/hooks/use-cached-effect.js.flow +0 -83
- package/dist/hooks/use-gql-router-context.js.flow +0 -14
- package/dist/hooks/use-gql.js.flow +0 -28
- package/dist/hooks/use-hydratable-effect.js.flow +0 -122
- package/dist/hooks/use-request-interception.js.flow +0 -24
- package/dist/hooks/use-server-effect.js.flow +0 -49
- package/dist/hooks/use-shared-cache.js.flow +0 -42
- package/dist/index.js.flow +0 -47
- package/dist/util/data-error.js.flow +0 -62
- package/dist/util/get-gql-data-from-response.js.flow +0 -12
- package/dist/util/get-gql-request-id.js.flow +0 -16
- package/dist/util/gql-error.js.flow +0 -41
- package/dist/util/gql-router-context.js.flow +0 -10
- package/dist/util/gql-types.js.flow +0 -50
- package/dist/util/graphql-document-node-parser.js.flow +0 -29
- package/dist/util/graphql-types.js.flow +0 -30
- package/dist/util/hydration-cache-api.js.flow +0 -29
- package/dist/util/merge-gql-context.js.flow +0 -18
- package/dist/util/purge-caches.js.flow +0 -14
- package/dist/util/request-api.js.flow +0 -33
- package/dist/util/request-fulfillment.js.flow +0 -48
- package/dist/util/request-tracking.js.flow +0 -81
- package/dist/util/result-from-cache-response.js.flow +0 -14
- package/dist/util/scoped-in-memory-cache.js.flow +0 -56
- package/dist/util/serializable-in-memory-cache.js.flow +0 -25
- package/dist/util/ssr-cache.js.flow +0 -86
- package/dist/util/status.js.flow +0 -17
- package/dist/util/to-gql-operation.js.flow +0 -41
- package/dist/util/types.js.flow +0 -142
- package/src/util/graphql-types.js.flow +0 -30
|
@@ -10,8 +10,7 @@ import type {Result, ValidCacheData} from "../util/types";
|
|
|
10
10
|
/**
|
|
11
11
|
* Policies to define how a hydratable effect should behave client-side.
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
|
-
export const WhenClientSide = {
|
|
13
|
+
export enum WhenClientSide {
|
|
15
14
|
/**
|
|
16
15
|
* The result from executing the effect server-side will not be hydrated.
|
|
17
16
|
* The effect will always be executed client-side.
|
|
@@ -20,7 +19,7 @@ export const WhenClientSide = {
|
|
|
20
19
|
* for properly hydrating this component (for example, the action invokes
|
|
21
20
|
* Apollo which manages its own cache to ensure things render properly).
|
|
22
21
|
*/
|
|
23
|
-
DoNotHydrate
|
|
22
|
+
DoNotHydrate = "DoNotHydrate",
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
25
|
* The result from executing the effect server-side will be hydrated.
|
|
@@ -28,7 +27,7 @@ export const WhenClientSide = {
|
|
|
28
27
|
* be hydrated (i.e. both error and success hydration results prevent the
|
|
29
28
|
* effect running client-side).
|
|
30
29
|
*/
|
|
31
|
-
ExecuteWhenNoResult
|
|
30
|
+
ExecuteWhenNoResult = "ExecuteWhenNoResult",
|
|
32
31
|
|
|
33
32
|
/**
|
|
34
33
|
* The result from executing the effect server-side will be hydrated.
|
|
@@ -37,15 +36,15 @@ export const WhenClientSide = {
|
|
|
37
36
|
* If the hydrated result was not a success result, or there was no
|
|
38
37
|
* hydrated result, the effect will not be executed.
|
|
39
38
|
*/
|
|
40
|
-
ExecuteWhenNoSuccessResult
|
|
39
|
+
ExecuteWhenNoSuccessResult = "ExecuteWhenNoSuccessResult",
|
|
41
40
|
|
|
42
41
|
/**
|
|
43
42
|
* The result from executing the effect server-side will be hydrated.
|
|
44
43
|
* The effect will always be executed client-side, regardless of the
|
|
45
44
|
* hydrated result status.
|
|
46
45
|
*/
|
|
47
|
-
AlwaysExecute
|
|
48
|
-
}
|
|
46
|
+
AlwaysExecute = "AlwaysExecute",
|
|
47
|
+
}
|
|
49
48
|
|
|
50
49
|
type HydratableEffectOptions<TData extends ValidCacheData> = {
|
|
51
50
|
/**
|
|
@@ -30,20 +30,22 @@ export const useRequestInterception = <TData extends ValidCacheData>(
|
|
|
30
30
|
const interceptedHandler = React.useCallback((): Promise<TData> => {
|
|
31
31
|
// Call the interceptors from closest to furthest.
|
|
32
32
|
// If one returns a non-null result, then we keep that.
|
|
33
|
-
const interceptResponse =
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
const interceptResponse: Promise<TData> | null | undefined =
|
|
34
|
+
interceptors.reduceRight(
|
|
35
|
+
(prev: Promise<TData> | null | undefined, interceptor) => {
|
|
36
|
+
if (prev != null) {
|
|
37
|
+
return prev;
|
|
38
|
+
}
|
|
39
|
+
return interceptor(requestId) as
|
|
40
|
+
| Promise<TData>
|
|
41
|
+
| null
|
|
42
|
+
| undefined;
|
|
43
|
+
},
|
|
44
|
+
null,
|
|
45
|
+
);
|
|
43
46
|
// If nothing intercepted this request, invoke the original handler.
|
|
44
47
|
// NOTE: We can't guarantee all interceptors return the same type
|
|
45
48
|
// as our handler, so how can TypeScript know? Let's just suppress that.
|
|
46
|
-
// @ts-expect-error [FEI-5019] - TS2739 - Type '(requestId: string) => Promise<ValidCacheData | null | undefined> | null | undefined' is missing the following properties from type 'Promise<TData>': then, catch, finally, [Symbol.toStringTag]
|
|
47
49
|
return interceptResponse ?? handler();
|
|
48
50
|
}, [handler, interceptors, requestId]);
|
|
49
51
|
|
|
@@ -81,8 +81,10 @@ export const useSharedCache = <TValue extends ValidCacheData>(
|
|
|
81
81
|
// since our last run through. Also, our cache does not know what type it
|
|
82
82
|
// stores, so we have to cast it to the type we're exporting. This is a
|
|
83
83
|
// dev time courtesy, rather than a runtime thing.
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
let currentValue: TValue | null | undefined = cache.get(scope, id) as
|
|
85
|
+
| TValue
|
|
86
|
+
| null
|
|
87
|
+
| undefined;
|
|
86
88
|
|
|
87
89
|
// If we have an initial value, we need to add it to the cache
|
|
88
90
|
// and use it as our current value.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-unassigned-import
|
|
2
|
+
import "jest-extended";
|
|
1
3
|
import {Server} from "@khanacademy/wonder-blocks-core";
|
|
2
4
|
import {RequestFulfillment} from "../request-fulfillment";
|
|
3
5
|
import {RequestTracker} from "../request-tracking";
|
|
@@ -123,7 +125,6 @@ describe("#hasTrackedRequestsToBeFetched", () => {
|
|
|
123
125
|
const result = hasTrackedRequestsToBeFetched();
|
|
124
126
|
|
|
125
127
|
// Assert
|
|
126
|
-
// @ts-expect-error [FEI-5019] - TS2339 - Property 'toBeTrue' does not exist on type 'JestMatchers<boolean>'.
|
|
127
128
|
expect(result).toBeTrue();
|
|
128
129
|
});
|
|
129
130
|
});
|
|
@@ -162,13 +162,12 @@ describe("../request-tracking.js", () => {
|
|
|
162
162
|
it("should cache errors occurring in promises", async () => {
|
|
163
163
|
// Arrange
|
|
164
164
|
const requestTracker = createRequestTracker();
|
|
165
|
-
const fakeBadRequestHandler = () =>
|
|
165
|
+
const fakeBadRequestHandler = (): Promise<any> =>
|
|
166
166
|
new Promise((resolve: any, reject: any) =>
|
|
167
167
|
reject("OH NO!"),
|
|
168
168
|
);
|
|
169
169
|
requestTracker.trackDataRequest(
|
|
170
170
|
"ID",
|
|
171
|
-
// @ts-expect-error [FEI-5019] - TS2345 - Argument of type '() => Promise<unknown>' is not assignable to parameter of type '() => Promise<ValidCacheData>'.
|
|
172
171
|
fakeBadRequestHandler,
|
|
173
172
|
true,
|
|
174
173
|
);
|
|
@@ -192,23 +191,22 @@ describe("../request-tracking.js", () => {
|
|
|
192
191
|
* - Handlers that reject the promise
|
|
193
192
|
* - Handlers that resolve
|
|
194
193
|
*/
|
|
195
|
-
const fakeBadRequestHandler = () =>
|
|
194
|
+
const fakeBadRequestHandler = (): Promise<any> =>
|
|
196
195
|
new Promise((resolve: any, reject: any) =>
|
|
197
196
|
reject("OH NO!"),
|
|
198
197
|
);
|
|
199
|
-
const fakeBadHandler = () => {
|
|
198
|
+
const fakeBadHandler = (): Promise<any> => {
|
|
200
199
|
throw new Error("OH NO!");
|
|
201
200
|
};
|
|
202
|
-
const fakeValidHandler = (() => {
|
|
201
|
+
const fakeValidHandler = ((): (() => Promise<any>) => {
|
|
203
202
|
let counter = 0;
|
|
204
|
-
return (
|
|
203
|
+
return () => {
|
|
205
204
|
counter++;
|
|
206
205
|
return Promise.resolve(`DATA:${counter}`);
|
|
207
206
|
};
|
|
208
207
|
})();
|
|
209
208
|
requestTracker.trackDataRequest(
|
|
210
209
|
"BAD_REQUEST",
|
|
211
|
-
// @ts-expect-error [FEI-5019] - TS2345 - Argument of type '() => Promise<unknown>' is not assignable to parameter of type '() => Promise<ValidCacheData>'.
|
|
212
210
|
fakeBadRequestHandler,
|
|
213
211
|
true,
|
|
214
212
|
);
|
|
@@ -219,13 +217,11 @@ describe("../request-tracking.js", () => {
|
|
|
219
217
|
);
|
|
220
218
|
requestTracker.trackDataRequest(
|
|
221
219
|
"VALID_HANDLER1",
|
|
222
|
-
// @ts-expect-error [FEI-5019] - TS2345 - Argument of type '(o: any) => Promise<string>' is not assignable to parameter of type '() => Promise<string>'.
|
|
223
220
|
fakeValidHandler,
|
|
224
221
|
true,
|
|
225
222
|
);
|
|
226
223
|
requestTracker.trackDataRequest(
|
|
227
224
|
"VALID_HANDLER2",
|
|
228
|
-
// @ts-expect-error [FEI-5019] - TS2345 - Argument of type '(o: any) => Promise<string>' is not assignable to parameter of type '() => Promise<string>'.
|
|
229
225
|
fakeValidHandler,
|
|
230
226
|
true,
|
|
231
227
|
);
|
|
@@ -70,8 +70,8 @@ describe("#resultFromCachedResponse", () => {
|
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
// Act
|
|
73
|
-
|
|
74
|
-
const
|
|
73
|
+
const cacheResult = resultFromCachedResponse(cacheEntry);
|
|
74
|
+
const error = cacheResult?.status === "error" && cacheResult.error;
|
|
75
75
|
|
|
76
76
|
// Assert
|
|
77
77
|
expect(error).toMatchInlineSnapshot(`[HydratedDataError: ERROR]`);
|
|
@@ -9,12 +9,11 @@ describe("SerializableInMemoryCache", () => {
|
|
|
9
9
|
scope: {
|
|
10
10
|
key: "value",
|
|
11
11
|
},
|
|
12
|
-
}
|
|
12
|
+
};
|
|
13
13
|
|
|
14
14
|
// Act
|
|
15
15
|
const cache = new SerializableInMemoryCache(sourceData);
|
|
16
16
|
// Try to mutate the cache.
|
|
17
|
-
// @ts-expect-error [FEI-5019] - TS2540 - Cannot assign to 'scope' because it is a read-only property.
|
|
18
17
|
sourceData["scope"] = {key: "SOME_NEW_DATA"};
|
|
19
18
|
const result = cache.get("scope", "key");
|
|
20
19
|
|
|
@@ -125,12 +125,11 @@ describe("../ssr-cache.js", () => {
|
|
|
125
125
|
const cache = new SsrCache();
|
|
126
126
|
const sourceData = {
|
|
127
127
|
MY_KEY: {data: "THE_DATA"},
|
|
128
|
-
}
|
|
128
|
+
};
|
|
129
129
|
|
|
130
130
|
// Act
|
|
131
131
|
cache.initialize(sourceData);
|
|
132
132
|
// Try to mutate the cache.
|
|
133
|
-
// @ts-expect-error [FEI-5019] - TS2540 - Cannot assign to 'MY_KEY' because it is a read-only property.
|
|
134
133
|
sourceData["MY_KEY"] = {data: "SOME_NEW_DATA"};
|
|
135
134
|
const result = cache.getEntry("MY_KEY");
|
|
136
135
|
|
|
@@ -448,8 +447,7 @@ describe("../ssr-cache.js", () => {
|
|
|
448
447
|
const cloneSpy = jest
|
|
449
448
|
.spyOn(hydrationCache, "clone")
|
|
450
449
|
.mockReturnValue({
|
|
451
|
-
|
|
452
|
-
default: "CLONE!",
|
|
450
|
+
default: "CLONE!" as any,
|
|
453
451
|
});
|
|
454
452
|
const cache = new SsrCache(hydrationCache);
|
|
455
453
|
// Let's add to the initialized state to check that everything
|
|
@@ -9,11 +9,10 @@ describe("#toGqlOperation", () => {
|
|
|
9
9
|
const documentNode: any = {};
|
|
10
10
|
const parserSpy = jest
|
|
11
11
|
.spyOn(GDNP, "graphQLDocumentNodeParser")
|
|
12
|
-
// @ts-expect-error [FEI-5019] - TS2345 - Argument of type '{ name: string; type: string; }' is not assignable to parameter of type 'IDocumentDefinition'.
|
|
13
12
|
.mockReturnValue({
|
|
14
13
|
name: "operationName",
|
|
15
14
|
type: "query",
|
|
16
|
-
});
|
|
15
|
+
} as any);
|
|
17
16
|
|
|
18
17
|
// Act
|
|
19
18
|
toGqlOperation(documentNode);
|
|
@@ -25,11 +24,10 @@ describe("#toGqlOperation", () => {
|
|
|
25
24
|
it("should return the Wonder Blocks Data representation of the given document node", () => {
|
|
26
25
|
// Arrange
|
|
27
26
|
const documentNode: any = {};
|
|
28
|
-
// @ts-expect-error [FEI-5019] - TS2345 - Argument of type '{ name: string; type: string; }' is not assignable to parameter of type 'IDocumentDefinition'.
|
|
29
27
|
jest.spyOn(GDNP, "graphQLDocumentNodeParser").mockReturnValue({
|
|
30
28
|
name: "operationName",
|
|
31
29
|
type: "mutation",
|
|
32
|
-
});
|
|
30
|
+
} as any);
|
|
33
31
|
|
|
34
32
|
// Act
|
|
35
33
|
const result = toGqlOperation(documentNode);
|
|
@@ -59,20 +59,20 @@ export function graphQLDocumentNodeParser(
|
|
|
59
59
|
|
|
60
60
|
const queries = document.definitions.filter(
|
|
61
61
|
(x: DefinitionNode) =>
|
|
62
|
-
|
|
63
|
-
x
|
|
62
|
+
x.kind === "OperationDefinition" &&
|
|
63
|
+
(x as OperationDefinitionNode).operation === "query",
|
|
64
64
|
);
|
|
65
65
|
|
|
66
66
|
const mutations = document.definitions.filter(
|
|
67
67
|
(x: DefinitionNode) =>
|
|
68
|
-
|
|
69
|
-
x
|
|
68
|
+
x.kind === "OperationDefinition" &&
|
|
69
|
+
(x as OperationDefinitionNode).operation === "mutation",
|
|
70
70
|
);
|
|
71
71
|
|
|
72
72
|
const subscriptions = document.definitions.filter(
|
|
73
73
|
(x: DefinitionNode) =>
|
|
74
|
-
|
|
75
|
-
x
|
|
74
|
+
x.kind === "OperationDefinition" &&
|
|
75
|
+
(x as OperationDefinitionNode).operation === "subscription",
|
|
76
76
|
);
|
|
77
77
|
|
|
78
78
|
if (fragments.length && !queries.length && !mutations.length) {
|
|
@@ -23,7 +23,8 @@ export const mergeGqlContext = <TContext extends GqlContext>(
|
|
|
23
23
|
delete acc[key];
|
|
24
24
|
} else {
|
|
25
25
|
// Otherwise, we set it.
|
|
26
|
-
// @ts-expect-error
|
|
26
|
+
// @ts-expect-error TypeScript doesn't seem to see that
|
|
27
|
+
// TContext can have string keys.
|
|
27
28
|
acc[key] = overrides[key];
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -53,8 +53,7 @@ export class RequestTracker {
|
|
|
53
53
|
_responseCache: SsrCache;
|
|
54
54
|
_requestFulfillment: RequestFulfillment;
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
constructor(responseCache: SsrCache | null = undefined) {
|
|
56
|
+
constructor(responseCache?: SsrCache | null) {
|
|
58
57
|
this._responseCache = responseCache || SsrCache.Default;
|
|
59
58
|
this._requestFulfillment = new RequestFulfillment();
|
|
60
59
|
}
|
|
@@ -160,6 +159,11 @@ export class RequestTracker {
|
|
|
160
159
|
// the code wrong. Rather than bloat
|
|
161
160
|
// code with useless error, just ignore.
|
|
162
161
|
|
|
162
|
+
// For status === "no-data":
|
|
163
|
+
// Could never get here unless we wrote
|
|
164
|
+
// the code wrong. Rather than bloat
|
|
165
|
+
// code with useless error, just ignore.
|
|
166
|
+
|
|
163
167
|
// For status === "aborted":
|
|
164
168
|
// We won't cache this.
|
|
165
169
|
// We don't hydrate aborted requests,
|
package/src/util/ssr-cache.ts
CHANGED
|
@@ -124,7 +124,7 @@ export class SsrCache {
|
|
|
124
124
|
: null;
|
|
125
125
|
|
|
126
126
|
// Now we defer to the SSR value, and fallback to the hydration cache.
|
|
127
|
-
const internalEntry =
|
|
127
|
+
const internalEntry: ValidCacheData | null | undefined =
|
|
128
128
|
ssrEntry ?? this._hydrationCache.get(DefaultScope, id);
|
|
129
129
|
|
|
130
130
|
// If we are not server-side and we hydrated something, let's clear
|
|
@@ -140,8 +140,10 @@ export class SsrCache {
|
|
|
140
140
|
}
|
|
141
141
|
// Getting the typing right between the in-memory cache and this
|
|
142
142
|
// is hard. Just telling TypeScript it's OK.
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
return internalEntry as
|
|
144
|
+
| Readonly<CachedResponse<TData>>
|
|
145
|
+
| null
|
|
146
|
+
| undefined;
|
|
145
147
|
};
|
|
146
148
|
|
|
147
149
|
/**
|
|
@@ -161,9 +163,11 @@ export class SsrCache {
|
|
|
161
163
|
const realPredicate = predicate
|
|
162
164
|
? // We know what we're putting into the cache so let's assume it
|
|
163
165
|
// conforms.
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
166
|
+
(_: string, key: string, cachedEntry: ValidCacheData) =>
|
|
167
|
+
predicate(
|
|
168
|
+
key,
|
|
169
|
+
cachedEntry as Readonly<CachedResponse<ValidCacheData>>,
|
|
170
|
+
)
|
|
167
171
|
: undefined;
|
|
168
172
|
|
|
169
173
|
// Apply the predicate to what we have in our caches.
|
|
@@ -184,7 +188,6 @@ export class SsrCache {
|
|
|
184
188
|
// to an empty object.
|
|
185
189
|
// We only need the default scope out of our scoped in-memory cache.
|
|
186
190
|
// We know that it conforms to our expectations.
|
|
187
|
-
|
|
188
|
-
return cache[DefaultScope] ?? {};
|
|
191
|
+
return (cache[DefaultScope] as ResponseCache) ?? {};
|
|
189
192
|
};
|
|
190
193
|
}
|
package/src/util/status.ts
CHANGED
|
@@ -4,6 +4,10 @@ const loadingStatus = Object.freeze({
|
|
|
4
4
|
status: "loading",
|
|
5
5
|
});
|
|
6
6
|
|
|
7
|
+
const noDataStatus = Object.freeze({
|
|
8
|
+
status: "no-data",
|
|
9
|
+
});
|
|
10
|
+
|
|
7
11
|
const abortedStatus = Object.freeze({
|
|
8
12
|
status: "aborted",
|
|
9
13
|
});
|
|
@@ -14,6 +18,8 @@ const abortedStatus = Object.freeze({
|
|
|
14
18
|
export const Status = Object.freeze({
|
|
15
19
|
loading: <TData extends ValidCacheData = ValidCacheData>(): Result<TData> =>
|
|
16
20
|
loadingStatus,
|
|
21
|
+
noData: <TData extends ValidCacheData = ValidCacheData>(): Result<TData> =>
|
|
22
|
+
noDataStatus,
|
|
17
23
|
aborted: <TData extends ValidCacheData = ValidCacheData>(): Result<TData> =>
|
|
18
24
|
abortedStatus,
|
|
19
25
|
success: <TData extends ValidCacheData>(data: TData): Result<TData> => ({
|
package/src/util/types.ts
CHANGED
|
@@ -3,30 +3,29 @@ import type {Metadata} from "@khanacademy/wonder-stuff-core";
|
|
|
3
3
|
/**
|
|
4
4
|
* Defines the various fetch policies that can be applied to requests.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
export const FetchPolicy = {
|
|
6
|
+
export enum FetchPolicy {
|
|
8
7
|
/**
|
|
9
8
|
* If the data is in the cache, return that; otherwise, fetch from the
|
|
10
9
|
* server.
|
|
11
10
|
*/
|
|
12
|
-
CacheBeforeNetwork
|
|
11
|
+
CacheBeforeNetwork = "CacheBeforeNetwork",
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* If the data is in the cache, return that; always fetch from the server
|
|
16
15
|
* regardless of cache.
|
|
17
16
|
*/
|
|
18
|
-
CacheAndNetwork
|
|
17
|
+
CacheAndNetwork = "CacheAndNetwork",
|
|
19
18
|
|
|
20
19
|
/**
|
|
21
20
|
* If the data is in the cache, return that; otherwise, do nothing.
|
|
22
21
|
*/
|
|
23
|
-
CacheOnly
|
|
22
|
+
CacheOnly = "CacheOnly",
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
25
|
* Ignore any existing cached result; always fetch from the server.
|
|
27
26
|
*/
|
|
28
|
-
NetworkOnly
|
|
29
|
-
}
|
|
27
|
+
NetworkOnly = "NetworkOnly",
|
|
28
|
+
}
|
|
30
29
|
|
|
31
30
|
/**
|
|
32
31
|
* Define what can be cached.
|
|
@@ -48,6 +47,9 @@ export type Result<TData extends ValidCacheData> =
|
|
|
48
47
|
| {
|
|
49
48
|
status: "loading";
|
|
50
49
|
}
|
|
50
|
+
| {
|
|
51
|
+
status: "no-data";
|
|
52
|
+
}
|
|
51
53
|
| {
|
|
52
54
|
status: "success";
|
|
53
55
|
data: TData;
|