relay-runtime 10.0.1 → 10.1.3

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 (82) hide show
  1. package/handlers/RelayDefaultHandlerProvider.js.flow +6 -0
  2. package/handlers/connection/MutationHandlers.js.flow +152 -20
  3. package/index.js +1 -1
  4. package/index.js.flow +17 -1
  5. package/lib/handlers/RelayDefaultHandlerProvider.js +9 -0
  6. package/lib/handlers/connection/MutationHandlers.js +185 -21
  7. package/lib/index.js +7 -0
  8. package/lib/mutations/RelayDeclarativeMutationConfig.js +5 -7
  9. package/lib/mutations/commitMutation.js +1 -4
  10. package/lib/mutations/validateMutation.js +28 -12
  11. package/lib/network/RelayQueryResponseCache.js +3 -7
  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 +85 -10
  16. package/lib/store/RelayConcreteVariables.js +2 -6
  17. package/lib/store/RelayModernEnvironment.js +81 -72
  18. package/lib/store/RelayModernFragmentSpecResolver.js +14 -7
  19. package/lib/store/RelayModernOperationDescriptor.js +6 -5
  20. package/lib/store/RelayModernQueryExecutor.js +46 -33
  21. package/lib/store/RelayModernRecord.js +3 -7
  22. package/lib/store/RelayModernStore.js +39 -137
  23. package/lib/store/RelayOperationTracker.js +7 -9
  24. package/lib/store/RelayOptimisticRecordSource.js +2 -6
  25. package/lib/store/RelayPublishQueue.js +1 -1
  26. package/lib/store/RelayReader.js +196 -33
  27. package/lib/store/RelayRecordSourceMapImpl.js +3 -5
  28. package/lib/store/RelayReferenceMarker.js +87 -5
  29. package/lib/store/RelayResponseNormalizer.js +115 -19
  30. package/lib/store/RelayStoreReactFlightUtils.js +47 -0
  31. package/lib/store/RelayStoreSubscriptions.js +162 -0
  32. package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +258 -0
  33. package/lib/store/StoreInspector.js +2 -6
  34. package/lib/store/createRelayContext.js +5 -0
  35. package/lib/store/defaultRequiredFieldLogger.js +18 -0
  36. package/lib/store/normalizeRelayPayload.js +2 -6
  37. package/lib/subscription/requestSubscription.js +2 -3
  38. package/lib/util/NormalizationNode.js +1 -5
  39. package/lib/util/RelayConcreteNode.js +2 -0
  40. package/lib/util/RelayFeatureFlags.js +7 -2
  41. package/lib/util/createPayloadFor3DField.js +2 -7
  42. package/lib/util/getFragmentIdentifier.js +12 -3
  43. package/lib/util/getOperation.js +33 -0
  44. package/lib/util/isEmptyObject.js +25 -0
  45. package/lib/util/recycleNodesInto.js +4 -1
  46. package/lib/util/reportMissingRequiredFields.js +48 -0
  47. package/mutations/commitMutation.js.flow +1 -2
  48. package/mutations/validateMutation.js.flow +34 -5
  49. package/network/RelayNetworkTypes.js.flow +22 -0
  50. package/package.json +2 -2
  51. package/query/GraphQLTag.js.flow +3 -1
  52. package/query/fetchQuery.js.flow +2 -2
  53. package/query/fetchQueryInternal.js.flow +0 -5
  54. package/relay-runtime.js +2 -2
  55. package/relay-runtime.min.js +2 -2
  56. package/store/DataChecker.js.flow +68 -2
  57. package/store/RelayModernEnvironment.js.flow +107 -87
  58. package/store/RelayModernFragmentSpecResolver.js.flow +13 -1
  59. package/store/RelayModernOperationDescriptor.js.flow +5 -1
  60. package/store/RelayModernQueryExecutor.js.flow +47 -23
  61. package/store/RelayModernStore.js.flow +33 -107
  62. package/store/RelayPublishQueue.js.flow +1 -1
  63. package/store/RelayReader.js.flow +180 -15
  64. package/store/RelayReferenceMarker.js.flow +72 -5
  65. package/store/RelayResponseNormalizer.js.flow +130 -19
  66. package/store/RelayStoreReactFlightUtils.js.flow +64 -0
  67. package/store/RelayStoreSubscriptions.js.flow +168 -0
  68. package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +259 -0
  69. package/store/RelayStoreTypes.js.flow +130 -37
  70. package/store/createRelayContext.js.flow +3 -0
  71. package/store/defaultRequiredFieldLogger.js.flow +23 -0
  72. package/subscription/requestSubscription.js.flow +5 -2
  73. package/util/NormalizationNode.js.flow +17 -2
  74. package/util/ReaderNode.js.flow +20 -1
  75. package/util/RelayConcreteNode.js.flow +6 -0
  76. package/util/RelayFeatureFlags.js.flow +12 -1
  77. package/util/getFragmentIdentifier.js.flow +33 -9
  78. package/util/getOperation.js.flow +40 -0
  79. package/util/getRequestIdentifier.js.flow +1 -1
  80. package/util/isEmptyObject.js.flow +25 -0
  81. package/util/recycleNodesInto.js.flow +11 -0
  82. package/util/reportMissingRequiredFields.js.flow +51 -0
@@ -12,6 +12,8 @@
12
12
 
13
13
  'use strict';
14
14
 
15
+ import type {ConcreteRequest} from './RelayConcreteNode';
16
+
15
17
  /**
16
18
  * Represents a single operation used to processing and normalize runtime
17
19
  * request results.
@@ -34,7 +36,6 @@ export type NormalizationLinkedHandle = {|
34
36
  +args: ?$ReadOnlyArray<NormalizationArgument>,
35
37
  +handle: string,
36
38
  +key: string,
37
- // T45504512: new connection model
38
39
  // NOTE: this property is optional because it's expected to be rarely used
39
40
  +dynamicKey?: ?NormalizationArgument,
40
41
  +filters: ?$ReadOnlyArray<string>,
@@ -48,10 +49,10 @@ export type NormalizationScalarHandle = {|
48
49
  +args: ?$ReadOnlyArray<NormalizationArgument>,
49
50
  +handle: string,
50
51
  +key: string,
51
- // T45504512: new connection model
52
52
  // NOTE: this property is optional because it's expected to be rarely used
53
53
  +dynamicKey?: ?NormalizationArgument,
54
54
  +filters: ?$ReadOnlyArray<string>,
55
+ +handleArgs?: $ReadOnlyArray<NormalizationArgument>,
55
56
  |};
56
57
 
57
58
  export type NormalizationArgument =
@@ -73,6 +74,7 @@ export type NormalizationClientExtension = {|
73
74
  |};
74
75
 
75
76
  export type NormalizationField =
77
+ | NormalizationFlightField
76
78
  | NormalizationScalarField
77
79
  | NormalizationLinkedField;
78
80
 
@@ -138,6 +140,14 @@ export type NormalizationScalarField = {|
138
140
  +storageKey: ?string,
139
141
  |};
140
142
 
143
+ export type NormalizationFlightField = {|
144
+ +kind: 'FlightField',
145
+ +alias: ?string,
146
+ +name: string,
147
+ +args: ?$ReadOnlyArray<NormalizationArgument>,
148
+ +storageKey: ?string,
149
+ |};
150
+
141
151
  export type NormalizationTypeDiscriminator = {|
142
152
  +kind: 'TypeDiscriminator',
143
153
  +abstractKey: string,
@@ -148,6 +158,7 @@ export type NormalizationSelection =
148
158
  | NormalizationClientExtension
149
159
  | NormalizationDefer
150
160
  | NormalizationField
161
+ | NormalizationFlightField
151
162
  | NormalizationHandle
152
163
  | NormalizationInlineFragment
153
164
  | NormalizationModuleImport
@@ -196,3 +207,7 @@ export type NormalizationSelectableNode =
196
207
  | NormalizationOperation
197
208
  | NormalizationSplitOperation
198
209
  | NormalizationStream;
210
+
211
+ export type NormalizationRootNode =
212
+ | ConcreteRequest
213
+ | NormalizationSplitOperation;
@@ -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,25 @@ 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,
24
+ ENABLE_STORE_SUBSCRIPTIONS_REFACTOR: boolean,
25
+ ENABLE_LOAD_QUERY_REQUEST_DEDUPING: boolean,
20
26
  |};
21
27
 
22
28
  const RelayFeatureFlags: FeatureFlags = {
23
- // T45504512: new connection model
24
29
  ENABLE_VARIABLE_CONNECTION_KEY: false,
25
30
  ENABLE_PARTIAL_RENDERING_DEFAULT: false,
26
31
  ENABLE_RELAY_CONTAINERS_SUSPENSE: false,
27
32
  ENABLE_PRECISE_TYPE_REFINEMENT: false,
33
+ ENABLE_REACT_FLIGHT_COMPONENT_FIELD: false,
34
+ ENABLE_REQUIRED_DIRECTIVES: false,
35
+ ENABLE_GETFRAGMENTIDENTIFIER_OPTIMIZATION: false,
36
+ ENABLE_FRIENDLY_QUERY_NAME_GQL_URL: false,
37
+ ENABLE_STORE_SUBSCRIPTIONS_REFACTOR: false,
38
+ ENABLE_LOAD_QUERY_REQUEST_DEDUPING: true,
28
39
  };
29
40
 
30
41
  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;
@@ -18,7 +18,7 @@ const stableCopy = require('./stableCopy');
18
18
  import type {RequestParameters} from './RelayConcreteNode';
19
19
  import type {Variables} from './RelayRuntimeTypes';
20
20
 
21
- export opaque type RequestIdentifier: string = string;
21
+ export type RequestIdentifier = string;
22
22
 
23
23
  /**
24
24
  * Returns a stable identifier for the given pair of `RequestParameters` +
@@ -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;