relay-runtime 10.0.1 → 10.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.
Files changed (70) hide show
  1. package/handlers/RelayDefaultHandlerProvider.js.flow +6 -0
  2. package/handlers/connection/MutationHandlers.js.flow +114 -3
  3. package/index.js +1 -1
  4. package/index.js.flow +16 -1
  5. package/lib/handlers/RelayDefaultHandlerProvider.js +9 -0
  6. package/lib/handlers/connection/MutationHandlers.js +138 -12
  7. package/lib/index.js +7 -0
  8. package/lib/mutations/RelayDeclarativeMutationConfig.js +2 -2
  9. package/lib/mutations/commitMutation.js +1 -4
  10. package/lib/mutations/validateMutation.js +27 -7
  11. package/lib/network/RelayQueryResponseCache.js +2 -2
  12. package/lib/query/GraphQLTag.js +2 -1
  13. package/lib/query/fetchQuery.js +2 -3
  14. package/lib/query/fetchQueryInternal.js +2 -3
  15. package/lib/store/DataChecker.js +82 -5
  16. package/lib/store/RelayModernEnvironment.js +18 -6
  17. package/lib/store/RelayModernFragmentSpecResolver.js +10 -1
  18. package/lib/store/RelayModernOperationDescriptor.js +6 -5
  19. package/lib/store/RelayModernQueryExecutor.js +44 -23
  20. package/lib/store/RelayModernStore.js +25 -14
  21. package/lib/store/RelayOperationTracker.js +2 -2
  22. package/lib/store/RelayPublishQueue.js +1 -1
  23. package/lib/store/RelayReader.js +196 -33
  24. package/lib/store/RelayRecordSourceMapImpl.js +2 -2
  25. package/lib/store/RelayReferenceMarker.js +89 -5
  26. package/lib/store/RelayResponseNormalizer.js +119 -19
  27. package/lib/store/RelayStoreReactFlightUtils.js +47 -0
  28. package/lib/store/defaultRequiredFieldLogger.js +18 -0
  29. package/lib/store/normalizeRelayPayload.js +1 -1
  30. package/lib/subscription/requestSubscription.js +2 -3
  31. package/lib/util/NormalizationNode.js +1 -5
  32. package/lib/util/RelayConcreteNode.js +2 -0
  33. package/lib/util/RelayFeatureFlags.js +5 -2
  34. package/lib/util/getFragmentIdentifier.js +12 -3
  35. package/lib/util/getOperation.js +33 -0
  36. package/lib/util/isEmptyObject.js +25 -0
  37. package/lib/util/recycleNodesInto.js +4 -1
  38. package/lib/util/reportMissingRequiredFields.js +48 -0
  39. package/mutations/commitMutation.js.flow +1 -2
  40. package/mutations/validateMutation.js.flow +34 -5
  41. package/network/RelayNetworkTypes.js.flow +22 -0
  42. package/package.json +2 -2
  43. package/query/GraphQLTag.js.flow +3 -1
  44. package/query/fetchQuery.js.flow +2 -2
  45. package/query/fetchQueryInternal.js.flow +0 -5
  46. package/relay-runtime.js +2 -2
  47. package/relay-runtime.min.js +2 -2
  48. package/store/DataChecker.js.flow +68 -2
  49. package/store/RelayModernEnvironment.js.flow +29 -9
  50. package/store/RelayModernFragmentSpecResolver.js.flow +13 -1
  51. package/store/RelayModernOperationDescriptor.js.flow +5 -1
  52. package/store/RelayModernQueryExecutor.js.flow +47 -23
  53. package/store/RelayModernStore.js.flow +31 -15
  54. package/store/RelayPublishQueue.js.flow +1 -1
  55. package/store/RelayReader.js.flow +180 -15
  56. package/store/RelayReferenceMarker.js.flow +72 -5
  57. package/store/RelayResponseNormalizer.js.flow +130 -19
  58. package/store/RelayStoreReactFlightUtils.js.flow +64 -0
  59. package/store/RelayStoreTypes.js.flow +90 -31
  60. package/store/defaultRequiredFieldLogger.js.flow +23 -0
  61. package/subscription/requestSubscription.js.flow +5 -2
  62. package/util/NormalizationNode.js.flow +17 -2
  63. package/util/ReaderNode.js.flow +20 -1
  64. package/util/RelayConcreteNode.js.flow +6 -0
  65. package/util/RelayFeatureFlags.js.flow +8 -1
  66. package/util/getFragmentIdentifier.js.flow +33 -9
  67. package/util/getOperation.js.flow +40 -0
  68. package/util/isEmptyObject.js.flow +25 -0
  69. package/util/recycleNodesInto.js.flow +11 -0
  70. package/util/reportMissingRequiredFields.js.flow +51 -0
@@ -179,6 +179,14 @@ export type ReaderScalarField = {|
179
179
  +storageKey: ?string,
180
180
  |};
181
181
 
182
+ export type ReaderFlightField = {|
183
+ +kind: 'FlightField',
184
+ +alias: ?string,
185
+ +name: string,
186
+ +args: ?$ReadOnlyArray<ReaderArgument>,
187
+ +storageKey: ?string,
188
+ |};
189
+
182
190
  export type ReaderDefer = {|
183
191
  +kind: 'Defer',
184
192
  +selections: $ReadOnlyArray<ReaderSelection>,
@@ -189,16 +197,27 @@ export type ReaderStream = {|
189
197
  +selections: $ReadOnlyArray<ReaderSelection>,
190
198
  |};
191
199
 
200
+ export type RequiredFieldAction = 'NONE' | 'LOG' | 'THROW';
201
+
202
+ export type ReaderRequiredField = {|
203
+ +kind: 'RequiredField',
204
+ +field: ReaderField,
205
+ +action: RequiredFieldAction,
206
+ +path: string,
207
+ |};
208
+
192
209
  export type ReaderSelection =
193
210
  | ReaderCondition
194
211
  | ReaderClientExtension
195
212
  | ReaderDefer
196
213
  | ReaderField
214
+ | ReaderFlightField
197
215
  | ReaderFragmentSpread
198
216
  | ReaderInlineDataFragmentSpread
199
217
  | ReaderInlineFragment
200
218
  | ReaderModuleImport
201
- | ReaderStream;
219
+ | ReaderStream
220
+ | ReaderRequiredField;
202
221
 
203
222
  export type ReaderVariableArgument = {|
204
223
  +kind: 'Variable',
@@ -31,6 +31,10 @@ export type ConcreteRequest = {|
31
31
  +params: RequestParameters,
32
32
  |};
33
33
 
34
+ export type NormalizationRootNode =
35
+ | ConcreteRequest
36
+ | NormalizationSplitOperation;
37
+
34
38
  /**
35
39
  * Contains the parameters required for executing a GraphQL request.
36
40
  * The operation can either be provided as a persisted `id` or `text`. If given
@@ -67,6 +71,7 @@ const RelayConcreteNode = {
67
71
  CLIENT_EXTENSION: 'ClientExtension',
68
72
  DEFER: 'Defer',
69
73
  CONNECTION: 'Connection',
74
+ FLIGHT_FIELD: 'FlightField',
70
75
  FRAGMENT: 'Fragment',
71
76
  FRAGMENT_SPREAD: 'FragmentSpread',
72
77
  INLINE_DATA_FRAGMENT_SPREAD: 'InlineDataFragmentSpread',
@@ -78,6 +83,7 @@ const RelayConcreteNode = {
78
83
  LIST_VALUE: 'ListValue',
79
84
  LOCAL_ARGUMENT: 'LocalArgument',
80
85
  MODULE_IMPORT: 'ModuleImport',
86
+ REQUIRED_FIELD: 'RequiredField',
81
87
  OBJECT_VALUE: 'ObjectValue',
82
88
  OPERATION: 'Operation',
83
89
  REQUEST: 'Request',
@@ -17,14 +17,21 @@ type FeatureFlags = {|
17
17
  ENABLE_PARTIAL_RENDERING_DEFAULT: boolean,
18
18
  ENABLE_RELAY_CONTAINERS_SUSPENSE: boolean,
19
19
  ENABLE_PRECISE_TYPE_REFINEMENT: boolean,
20
+ ENABLE_REACT_FLIGHT_COMPONENT_FIELD: boolean,
21
+ ENABLE_REQUIRED_DIRECTIVES: boolean | string,
22
+ ENABLE_GETFRAGMENTIDENTIFIER_OPTIMIZATION: boolean,
23
+ ENABLE_FRIENDLY_QUERY_NAME_GQL_URL: boolean,
20
24
  |};
21
25
 
22
26
  const RelayFeatureFlags: FeatureFlags = {
23
- // T45504512: new connection model
24
27
  ENABLE_VARIABLE_CONNECTION_KEY: false,
25
28
  ENABLE_PARTIAL_RENDERING_DEFAULT: false,
26
29
  ENABLE_RELAY_CONTAINERS_SUSPENSE: false,
27
30
  ENABLE_PRECISE_TYPE_REFINEMENT: false,
31
+ ENABLE_REACT_FLIGHT_COMPONENT_FIELD: false,
32
+ ENABLE_REQUIRED_DIRECTIVES: false,
33
+ ENABLE_GETFRAGMENTIDENTIFIER_OPTIMIZATION: false,
34
+ ENABLE_FRIENDLY_QUERY_NAME_GQL_URL: false,
28
35
  };
29
36
 
30
37
  module.exports = RelayFeatureFlags;
@@ -13,6 +13,9 @@
13
13
 
14
14
  'use strict';
15
15
 
16
+ const RelayFeatureFlags = require('./RelayFeatureFlags');
17
+
18
+ const isEmptyObject = require('./isEmptyObject');
16
19
  const stableCopy = require('./stableCopy');
17
20
 
18
21
  const {
@@ -38,15 +41,36 @@ function getFragmentIdentifier(
38
41
  ']';
39
42
  const fragmentVariables = getVariablesFromFragment(fragmentNode, fragmentRef);
40
43
  const dataIDs = getDataIDsFromFragment(fragmentNode, fragmentRef);
41
- return (
42
- fragmentOwnerIdentifier +
43
- '/' +
44
- fragmentNode.name +
45
- '/' +
46
- JSON.stringify(stableCopy(fragmentVariables)) +
47
- '/' +
48
- (JSON.stringify(dataIDs) ?? 'missing')
49
- );
44
+
45
+ if (RelayFeatureFlags.ENABLE_GETFRAGMENTIDENTIFIER_OPTIMIZATION) {
46
+ return (
47
+ fragmentOwnerIdentifier +
48
+ '/' +
49
+ fragmentNode.name +
50
+ '/' +
51
+ (fragmentVariables == null || isEmptyObject(fragmentVariables)
52
+ ? '{}'
53
+ : JSON.stringify(stableCopy(fragmentVariables))) +
54
+ '/' +
55
+ (typeof dataIDs === 'undefined'
56
+ ? 'missing'
57
+ : dataIDs == null
58
+ ? 'null'
59
+ : Array.isArray(dataIDs)
60
+ ? '[' + dataIDs.join(',') + ']'
61
+ : dataIDs)
62
+ );
63
+ } else {
64
+ return (
65
+ fragmentOwnerIdentifier +
66
+ '/' +
67
+ fragmentNode.name +
68
+ '/' +
69
+ JSON.stringify(stableCopy(fragmentVariables)) +
70
+ '/' +
71
+ (JSON.stringify(dataIDs) ?? 'missing')
72
+ );
73
+ }
50
74
  }
51
75
 
52
76
  module.exports = getFragmentIdentifier;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict-local
8
+ * @format
9
+ * @emails oncall+relay
10
+ */
11
+
12
+ // flowlint ambiguous-object-type:error
13
+
14
+ 'use strict';
15
+
16
+ const {REQUEST, SPLIT_OPERATION} = require('./RelayConcreteNode');
17
+
18
+ import type {
19
+ NormalizationOperation,
20
+ NormalizationRootNode,
21
+ NormalizationSplitOperation,
22
+ } from './NormalizationNode';
23
+
24
+ /**
25
+ * OperationLoaders can return either a NormalizationSplitOperation or
26
+ * ConcreteRequest.
27
+ */
28
+ function getOperation(
29
+ node: NormalizationRootNode,
30
+ ): NormalizationSplitOperation | NormalizationOperation {
31
+ switch (node.kind) {
32
+ case REQUEST:
33
+ return node.operation;
34
+ case SPLIT_OPERATION:
35
+ default:
36
+ return node;
37
+ }
38
+ }
39
+
40
+ module.exports = getOperation;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict
8
+ * @format
9
+ * @emails oncall+relay
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ const hasOwnProperty = Object.prototype.hasOwnProperty;
15
+
16
+ function isEmptyObject(obj: {+[key: string]: mixed}): boolean {
17
+ for (const key in obj) {
18
+ if (hasOwnProperty.call(obj, key)) {
19
+ return false;
20
+ }
21
+ }
22
+ return true;
23
+ }
24
+
25
+ module.exports = isEmptyObject;
@@ -12,6 +12,9 @@
12
12
 
13
13
  'use strict';
14
14
 
15
+ const hasWeakSetDefined = typeof WeakSet !== 'undefined';
16
+ const hasWeakMapDefined = typeof WeakMap !== 'undefined';
17
+
15
18
  /**
16
19
  * Recycles subtrees from `prevData` by replacing equal subtrees in `nextData`.
17
20
  */
@@ -19,8 +22,16 @@ function recycleNodesInto<T>(prevData: T, nextData: T): T {
19
22
  if (
20
23
  prevData === nextData ||
21
24
  typeof prevData !== 'object' ||
25
+ prevData instanceof Set ||
26
+ prevData instanceof Map ||
27
+ (hasWeakSetDefined && prevData instanceof WeakSet) ||
28
+ (hasWeakMapDefined && prevData instanceof WeakMap) ||
22
29
  !prevData ||
23
30
  typeof nextData !== 'object' ||
31
+ nextData instanceof Set ||
32
+ nextData instanceof Map ||
33
+ (hasWeakSetDefined && nextData instanceof WeakSet) ||
34
+ (hasWeakMapDefined && nextData instanceof WeakMap) ||
24
35
  !nextData
25
36
  ) {
26
37
  return nextData;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow
8
+ * @emails oncall+relay
9
+ * @format
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ import type {
15
+ IEnvironment,
16
+ MissingRequiredFields,
17
+ } from '../store/RelayStoreTypes';
18
+
19
+ function reportMissingRequiredFields(
20
+ environment: IEnvironment,
21
+ missingRequiredFields: MissingRequiredFields,
22
+ ) {
23
+ switch (missingRequiredFields.action) {
24
+ case 'THROW': {
25
+ const {path, owner} = missingRequiredFields.field;
26
+ // This gives the consumer the chance to throw their own error if they so wish.
27
+ environment.requiredFieldLogger({
28
+ kind: 'missing_field.throw',
29
+ owner,
30
+ fieldPath: path,
31
+ });
32
+ throw new Error(
33
+ `Relay: Missing @required value at path '${path}' in '${owner}'.`,
34
+ );
35
+ }
36
+ case 'LOG':
37
+ missingRequiredFields.fields.forEach(({path, owner}) => {
38
+ environment.requiredFieldLogger({
39
+ kind: 'missing_field.log',
40
+ owner,
41
+ fieldPath: path,
42
+ });
43
+ });
44
+ break;
45
+ default: {
46
+ (missingRequiredFields.action: empty);
47
+ }
48
+ }
49
+ }
50
+
51
+ module.exports = reportMissingRequiredFields;