@khanacademy/wonder-blocks-data 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/es/index.js +23 -4
- package/dist/index.js +24 -6
- package/package.json +3 -3
- package/src/components/gql-router.js +2 -2
- package/src/hooks/__tests__/use-gql.test.js +1 -0
- package/src/hooks/use-gql.js +39 -29
- package/src/index.js +7 -1
- package/src/util/gql-types.js +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-data
|
|
2
2
|
|
|
3
|
+
## 3.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 6973afa2: useGql method now merges defaultContext and partial context by ignoring values explicitly set to undefined in the partial context. This ensures that that existing default context values are not overridden unless explicitly given a value other than undefined.
|
|
8
|
+
|
|
9
|
+
## 3.1.3
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 9931ae6b: Simplify GQL types
|
|
14
|
+
|
|
15
|
+
## 3.1.2
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- @khanacademy/wonder-blocks-core@4.2.1
|
|
20
|
+
|
|
21
|
+
## 3.1.1
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- 4ff59815: Add GraphQL fetch mock support to wonder-blocks-testing
|
|
26
|
+
|
|
3
27
|
## 3.1.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
package/dist/es/index.js
CHANGED
|
@@ -865,6 +865,10 @@ const getGqlDataFromResponse = async response => {
|
|
|
865
865
|
*
|
|
866
866
|
* The fetch function will resolve null if the request was aborted, otherwise
|
|
867
867
|
* it will resolve the data returned by the GraphQL server.
|
|
868
|
+
*
|
|
869
|
+
* Context is merged with the default context provided to the GqlRouter.
|
|
870
|
+
* Values in the partial context given to the returned fetch function will
|
|
871
|
+
* only be included if they have a value other than undefined.
|
|
868
872
|
*/
|
|
869
873
|
const useGql = () => {
|
|
870
874
|
// This hook only works if the `GqlRouter` has been used to setup context.
|
|
@@ -886,10 +890,22 @@ const useGql = () => {
|
|
|
886
890
|
const gqlFetch = useMemo(() => (operation, options = Object.freeze({})) => {
|
|
887
891
|
const {
|
|
888
892
|
variables,
|
|
889
|
-
context
|
|
890
|
-
} = options; //
|
|
893
|
+
context = {}
|
|
894
|
+
} = options; // Let's merge the partial context of the fetch with the
|
|
895
|
+
// default context. We deliberately don't spread because
|
|
896
|
+
// spreading would overwrite default context values with
|
|
897
|
+
// undefined if the partial context includes a value explicitly
|
|
898
|
+
// set to undefined. Instead, we use a map/reduce of keys.
|
|
899
|
+
|
|
900
|
+
const mergedContext = Object.keys(context).reduce((acc, key) => {
|
|
901
|
+
if (context[key] !== undefined) {
|
|
902
|
+
acc[key] = context[key];
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
return acc;
|
|
906
|
+
}, _extends({}, defaultContext)); // Invoke the fetch and extract the data.
|
|
891
907
|
|
|
892
|
-
return fetch(operation, variables,
|
|
908
|
+
return fetch(operation, variables, mergedContext).then(getGqlDataFromResponse, error => {
|
|
893
909
|
// Return null if the request was aborted.
|
|
894
910
|
// The only way to detect this reliably, it seems, is to
|
|
895
911
|
// check the error name and see if it's "AbortError" (this
|
|
@@ -897,7 +913,10 @@ const useGql = () => {
|
|
|
897
913
|
// Even then, it's reliant on the fetch supporting aborts.
|
|
898
914
|
if (error.name === "AbortError") {
|
|
899
915
|
return null;
|
|
900
|
-
}
|
|
916
|
+
} // Need to make sure we pass other errors along.
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
throw error;
|
|
901
920
|
});
|
|
902
921
|
}, [fetch, defaultContext]);
|
|
903
922
|
return gqlFetch;
|
package/dist/index.js
CHANGED
|
@@ -1032,6 +1032,10 @@ const GqlRouter = ({
|
|
|
1032
1032
|
*
|
|
1033
1033
|
* The fetch function will resolve null if the request was aborted, otherwise
|
|
1034
1034
|
* it will resolve the data returned by the GraphQL server.
|
|
1035
|
+
*
|
|
1036
|
+
* Context is merged with the default context provided to the GqlRouter.
|
|
1037
|
+
* Values in the partial context given to the returned fetch function will
|
|
1038
|
+
* only be included if they have a value other than undefined.
|
|
1035
1039
|
*/
|
|
1036
1040
|
const useGql = () => {
|
|
1037
1041
|
// This hook only works if the `GqlRouter` has been used to setup context.
|
|
@@ -1053,12 +1057,23 @@ const useGql = () => {
|
|
|
1053
1057
|
const gqlFetch = Object(react__WEBPACK_IMPORTED_MODULE_0__["useMemo"])(() => (operation, options = Object.freeze({})) => {
|
|
1054
1058
|
const {
|
|
1055
1059
|
variables,
|
|
1056
|
-
context
|
|
1057
|
-
} = options; //
|
|
1060
|
+
context = {}
|
|
1061
|
+
} = options; // Let's merge the partial context of the fetch with the
|
|
1062
|
+
// default context. We deliberately don't spread because
|
|
1063
|
+
// spreading would overwrite default context values with
|
|
1064
|
+
// undefined if the partial context includes a value explicitly
|
|
1065
|
+
// set to undefined. Instead, we use a map/reduce of keys.
|
|
1066
|
+
|
|
1067
|
+
const mergedContext = Object.keys(context).reduce((acc, key) => {
|
|
1068
|
+
if (context[key] !== undefined) {
|
|
1069
|
+
acc[key] = context[key];
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
return acc;
|
|
1073
|
+
}, { ...defaultContext
|
|
1074
|
+
}); // Invoke the fetch and extract the data.
|
|
1058
1075
|
|
|
1059
|
-
return fetch(operation, variables,
|
|
1060
|
-
...context
|
|
1061
|
-
}).then(_util_get_gql_data_from_response_js__WEBPACK_IMPORTED_MODULE_2__[/* getGqlDataFromResponse */ "a"], error => {
|
|
1076
|
+
return fetch(operation, variables, mergedContext).then(_util_get_gql_data_from_response_js__WEBPACK_IMPORTED_MODULE_2__[/* getGqlDataFromResponse */ "a"], error => {
|
|
1062
1077
|
// Return null if the request was aborted.
|
|
1063
1078
|
// The only way to detect this reliably, it seems, is to
|
|
1064
1079
|
// check the error name and see if it's "AbortError" (this
|
|
@@ -1066,7 +1081,10 @@ const useGql = () => {
|
|
|
1066
1081
|
// Even then, it's reliant on the fetch supporting aborts.
|
|
1067
1082
|
if (error.name === "AbortError") {
|
|
1068
1083
|
return null;
|
|
1069
|
-
}
|
|
1084
|
+
} // Need to make sure we pass other errors along.
|
|
1085
|
+
|
|
1086
|
+
|
|
1087
|
+
throw error;
|
|
1070
1088
|
});
|
|
1071
1089
|
}, [fetch, defaultContext]);
|
|
1072
1090
|
return gqlFetch;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-data",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"design": "v1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@babel/runtime": "^7.16.3",
|
|
17
|
-
"@khanacademy/wonder-blocks-core": "^4.
|
|
17
|
+
"@khanacademy/wonder-blocks-core": "^4.2.1"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"@khanacademy/wonder-stuff-core": "^0.1.2",
|
|
21
21
|
"react": "16.14.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"wb-dev-build-settings": "^0.
|
|
24
|
+
"wb-dev-build-settings": "^0.3.0"
|
|
25
25
|
},
|
|
26
26
|
"author": "",
|
|
27
27
|
"license": "MIT"
|
|
@@ -5,7 +5,7 @@ import {GqlRouterContext} from "../util/gql-router-context.js";
|
|
|
5
5
|
|
|
6
6
|
import type {
|
|
7
7
|
GqlContext,
|
|
8
|
-
|
|
8
|
+
GqlFetchFn,
|
|
9
9
|
GqlRouterConfiguration,
|
|
10
10
|
} from "../util/gql-types.js";
|
|
11
11
|
|
|
@@ -18,7 +18,7 @@ type Props<TContext: GqlContext> = {|
|
|
|
18
18
|
/**
|
|
19
19
|
* The function to use when fetching requests.
|
|
20
20
|
*/
|
|
21
|
-
fetch:
|
|
21
|
+
fetch: GqlFetchFn<any, any, TContext>,
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* The children to be rendered inside the router.
|
package/src/hooks/use-gql.js
CHANGED
|
@@ -9,7 +9,6 @@ import type {
|
|
|
9
9
|
GqlContext,
|
|
10
10
|
GqlOperation,
|
|
11
11
|
GqlFetchOptions,
|
|
12
|
-
GqlOperationType,
|
|
13
12
|
} from "../util/gql-types.js";
|
|
14
13
|
|
|
15
14
|
/**
|
|
@@ -17,14 +16,13 @@ import type {
|
|
|
17
16
|
*
|
|
18
17
|
* The fetch function will resolve null if the request was aborted, otherwise
|
|
19
18
|
* it will resolve the data returned by the GraphQL server.
|
|
19
|
+
*
|
|
20
|
+
* Context is merged with the default context provided to the GqlRouter.
|
|
21
|
+
* Values in the partial context given to the returned fetch function will
|
|
22
|
+
* only be included if they have a value other than undefined.
|
|
20
23
|
*/
|
|
21
|
-
export const useGql = (): (<
|
|
22
|
-
|
|
23
|
-
TData,
|
|
24
|
-
TVariables: {...},
|
|
25
|
-
TContext: GqlContext,
|
|
26
|
-
>(
|
|
27
|
-
operation: GqlOperation<TType, TData, TVariables>,
|
|
24
|
+
export const useGql = (): (<TData, TVariables: {...}, TContext: GqlContext>(
|
|
25
|
+
operation: GqlOperation<TData, TVariables>,
|
|
28
26
|
options?: GqlFetchOptions<TVariables, TContext>,
|
|
29
27
|
) => Promise<?TData>) => {
|
|
30
28
|
// This hook only works if the `GqlRouter` has been used to setup context.
|
|
@@ -41,33 +39,45 @@ export const useGql = (): (<
|
|
|
41
39
|
// in hooks deps without fear of it triggering extra renders.
|
|
42
40
|
const gqlFetch = useMemo(
|
|
43
41
|
() =>
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
TData,
|
|
47
|
-
TVariables: {...},
|
|
48
|
-
TContext: GqlContext,
|
|
49
|
-
>(
|
|
50
|
-
operation: GqlOperation<TType, TData, TVariables>,
|
|
42
|
+
<TData, TVariables: {...}, TContext: GqlContext>(
|
|
43
|
+
operation: GqlOperation<TData, TVariables>,
|
|
51
44
|
options: GqlFetchOptions<TVariables, TContext> = Object.freeze(
|
|
52
45
|
{},
|
|
53
46
|
),
|
|
54
47
|
) => {
|
|
55
|
-
const {variables, context} = options;
|
|
48
|
+
const {variables, context = {}} = options;
|
|
49
|
+
|
|
50
|
+
// Let's merge the partial context of the fetch with the
|
|
51
|
+
// default context. We deliberately don't spread because
|
|
52
|
+
// spreading would overwrite default context values with
|
|
53
|
+
// undefined if the partial context includes a value explicitly
|
|
54
|
+
// set to undefined. Instead, we use a map/reduce of keys.
|
|
55
|
+
const mergedContext = Object.keys(context).reduce(
|
|
56
|
+
(acc, key) => {
|
|
57
|
+
if (context[key] !== undefined) {
|
|
58
|
+
acc[key] = context[key];
|
|
59
|
+
}
|
|
60
|
+
return acc;
|
|
61
|
+
},
|
|
62
|
+
{...defaultContext},
|
|
63
|
+
);
|
|
56
64
|
|
|
57
65
|
// Invoke the fetch and extract the data.
|
|
58
|
-
return fetch(operation, variables,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
return fetch(operation, variables, mergedContext).then(
|
|
67
|
+
getGqlDataFromResponse,
|
|
68
|
+
(error) => {
|
|
69
|
+
// Return null if the request was aborted.
|
|
70
|
+
// The only way to detect this reliably, it seems, is to
|
|
71
|
+
// check the error name and see if it's "AbortError" (this
|
|
72
|
+
// is also what Apollo does).
|
|
73
|
+
// Even then, it's reliant on the fetch supporting aborts.
|
|
74
|
+
if (error.name === "AbortError") {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
// Need to make sure we pass other errors along.
|
|
78
|
+
throw error;
|
|
79
|
+
},
|
|
80
|
+
);
|
|
71
81
|
},
|
|
72
82
|
[fetch, defaultContext],
|
|
73
83
|
);
|
package/src/index.js
CHANGED
|
@@ -60,4 +60,10 @@ export {useData} from "./hooks/use-data.js";
|
|
|
60
60
|
export {GqlRouter} from "./components/gql-router.js";
|
|
61
61
|
export {useGql} from "./hooks/use-gql.js";
|
|
62
62
|
export * from "./util/gql-error.js";
|
|
63
|
-
export type {
|
|
63
|
+
export type {
|
|
64
|
+
GqlContext,
|
|
65
|
+
GqlOperation,
|
|
66
|
+
GqlOperationType,
|
|
67
|
+
GqlFetchOptions,
|
|
68
|
+
GqlFetchFn,
|
|
69
|
+
} from "./util/gql-types.js";
|
package/src/util/gql-types.js
CHANGED
|
@@ -8,7 +8,6 @@ export type GqlOperationType = "mutation" | "query";
|
|
|
8
8
|
* A GraphQL operation.
|
|
9
9
|
*/
|
|
10
10
|
export type GqlOperation<
|
|
11
|
-
TType: GqlOperationType,
|
|
12
11
|
// TData is not used to define a field on this type, but it is used
|
|
13
12
|
// to ensure that calls using this operation will properly return the
|
|
14
13
|
// correct data type.
|
|
@@ -20,13 +19,14 @@ export type GqlOperation<
|
|
|
20
19
|
// eslint-disable-next-line no-unused-vars
|
|
21
20
|
TVariables: {...} = Empty,
|
|
22
21
|
> = {
|
|
23
|
-
type:
|
|
22
|
+
type: GqlOperationType,
|
|
24
23
|
id: string,
|
|
25
24
|
// We allow other things here to be passed along to the fetch function.
|
|
26
25
|
// For example, we might want to pass the full query/mutation definition
|
|
27
26
|
// as a string here to allow that to be sent to an Apollo server that
|
|
28
27
|
// expects it. This is a courtesy to calling code; these additional
|
|
29
28
|
// values are ignored by WB Data, and passed through as-is.
|
|
29
|
+
[key: string]: mixed,
|
|
30
30
|
...
|
|
31
31
|
};
|
|
32
32
|
|
|
@@ -37,8 +37,8 @@ export type GqlContext = {|
|
|
|
37
37
|
/**
|
|
38
38
|
* Functions that make fetches of GQL operations.
|
|
39
39
|
*/
|
|
40
|
-
export type
|
|
41
|
-
operation: GqlOperation<
|
|
40
|
+
export type GqlFetchFn<TData, TVariables: {...}, TContext: GqlContext> = (
|
|
41
|
+
operation: GqlOperation<TData, TVariables>,
|
|
42
42
|
variables: ?TVariables,
|
|
43
43
|
context: TContext,
|
|
44
44
|
) => Promise<Response>;
|
|
@@ -47,7 +47,7 @@ export type FetchFn<TType, TData, TVariables: {...}, TContext: GqlContext> = (
|
|
|
47
47
|
* The configuration stored in the GqlRouterContext context.
|
|
48
48
|
*/
|
|
49
49
|
export type GqlRouterConfiguration<TContext: GqlContext> = {|
|
|
50
|
-
fetch:
|
|
50
|
+
fetch: GqlFetchFn<any, any, any>,
|
|
51
51
|
defaultContext: TContext,
|
|
52
52
|
|};
|
|
53
53
|
|