relay-runtime 11.0.2 → 12.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.
Files changed (100) hide show
  1. package/index.js +1 -1
  2. package/index.js.flow +16 -1
  3. package/lib/index.js +15 -0
  4. package/lib/multi-actor-environment/ActorIdentifier.js +11 -1
  5. package/lib/multi-actor-environment/ActorSpecificEnvironment.js +59 -19
  6. package/lib/multi-actor-environment/ActorUtils.js +27 -0
  7. package/lib/multi-actor-environment/MultiActorEnvironment.js +305 -55
  8. package/lib/multi-actor-environment/index.js +5 -1
  9. package/lib/mutations/RelayRecordSourceSelectorProxy.js +6 -1
  10. package/lib/mutations/commitMutation.js +4 -1
  11. package/lib/mutations/validateMutation.js +6 -1
  12. package/lib/network/RelayObservable.js +3 -1
  13. package/lib/network/RelayQueryResponseCache.js +19 -3
  14. package/lib/network/wrapNetworkWithLogObserver.js +78 -0
  15. package/lib/store/DataChecker.js +110 -40
  16. package/lib/store/OperationExecutor.js +478 -204
  17. package/lib/store/RelayConcreteVariables.js +21 -0
  18. package/lib/store/RelayModernEnvironment.js +41 -85
  19. package/lib/store/RelayModernFragmentSpecResolver.js +48 -22
  20. package/lib/store/RelayModernRecord.js +35 -1
  21. package/lib/store/RelayModernStore.js +48 -14
  22. package/lib/store/RelayOperationTracker.js +33 -23
  23. package/lib/store/RelayPublishQueue.js +23 -5
  24. package/lib/store/RelayReader.js +138 -44
  25. package/lib/store/RelayRecordSource.js +87 -3
  26. package/lib/store/RelayReferenceMarker.js +28 -15
  27. package/lib/store/RelayResponseNormalizer.js +164 -91
  28. package/lib/store/RelayStoreReactFlightUtils.js +1 -7
  29. package/lib/store/RelayStoreSubscriptions.js +8 -5
  30. package/lib/store/RelayStoreUtils.js +7 -2
  31. package/lib/store/ResolverCache.js +213 -0
  32. package/lib/store/ResolverFragments.js +1 -1
  33. package/lib/store/createRelayContext.js +1 -1
  34. package/lib/subscription/requestSubscription.js +27 -29
  35. package/lib/util/RelayConcreteNode.js +1 -0
  36. package/lib/util/RelayFeatureFlags.js +3 -5
  37. package/lib/util/RelayReplaySubject.js +21 -6
  38. package/lib/util/getPaginationMetadata.js +41 -0
  39. package/lib/util/getPaginationVariables.js +67 -0
  40. package/lib/util/getPendingOperationsForFragment.js +55 -0
  41. package/lib/util/getRefetchMetadata.js +36 -0
  42. package/lib/util/getValueAtPath.js +51 -0
  43. package/lib/util/isEmptyObject.js +1 -1
  44. package/lib/util/registerEnvironmentWithDevTools.js +26 -0
  45. package/lib/util/withDuration.js +31 -0
  46. package/multi-actor-environment/ActorIdentifier.js.flow +17 -1
  47. package/multi-actor-environment/ActorSpecificEnvironment.js.flow +72 -44
  48. package/multi-actor-environment/ActorUtils.js.flow +33 -0
  49. package/multi-actor-environment/MultiActorEnvironment.js.flow +332 -80
  50. package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +61 -12
  51. package/multi-actor-environment/index.js.flow +3 -0
  52. package/mutations/RelayRecordSourceSelectorProxy.js.flow +7 -2
  53. package/mutations/commitMutation.js.flow +2 -0
  54. package/mutations/validateMutation.js.flow +8 -0
  55. package/network/RelayObservable.js.flow +2 -0
  56. package/network/RelayQueryResponseCache.js.flow +31 -18
  57. package/network/wrapNetworkWithLogObserver.js.flow +99 -0
  58. package/package.json +1 -1
  59. package/relay-runtime.js +2 -2
  60. package/relay-runtime.min.js +2 -2
  61. package/store/ClientID.js.flow +5 -1
  62. package/store/DataChecker.js.flow +126 -35
  63. package/store/OperationExecutor.js.flow +528 -265
  64. package/store/RelayConcreteVariables.js.flow +26 -1
  65. package/store/RelayModernEnvironment.js.flow +41 -94
  66. package/store/RelayModernFragmentSpecResolver.js.flow +40 -14
  67. package/store/RelayModernOperationDescriptor.js.flow +9 -3
  68. package/store/RelayModernRecord.js.flow +49 -0
  69. package/store/RelayModernStore.js.flow +50 -12
  70. package/store/RelayOperationTracker.js.flow +56 -34
  71. package/store/RelayPublishQueue.js.flow +31 -8
  72. package/store/RelayReader.js.flow +148 -42
  73. package/store/RelayRecordSource.js.flow +72 -6
  74. package/store/RelayReferenceMarker.js.flow +29 -12
  75. package/store/RelayResponseNormalizer.js.flow +164 -48
  76. package/store/RelayStoreReactFlightUtils.js.flow +1 -7
  77. package/store/RelayStoreSubscriptions.js.flow +10 -3
  78. package/store/RelayStoreTypes.js.flow +128 -12
  79. package/store/RelayStoreUtils.js.flow +17 -3
  80. package/store/ResolverCache.js.flow +247 -0
  81. package/store/ResolverFragments.js.flow +6 -3
  82. package/store/createRelayContext.js.flow +1 -1
  83. package/subscription/requestSubscription.js.flow +41 -29
  84. package/util/NormalizationNode.js.flow +10 -3
  85. package/util/ReaderNode.js.flow +15 -1
  86. package/util/RelayConcreteNode.js.flow +1 -0
  87. package/util/RelayFeatureFlags.js.flow +8 -10
  88. package/util/RelayReplaySubject.js.flow +7 -6
  89. package/util/getPaginationMetadata.js.flow +74 -0
  90. package/util/getPaginationVariables.js.flow +112 -0
  91. package/util/getPendingOperationsForFragment.js.flow +62 -0
  92. package/util/getRefetchMetadata.js.flow +80 -0
  93. package/util/getValueAtPath.js.flow +46 -0
  94. package/util/isEmptyObject.js.flow +1 -0
  95. package/util/registerEnvironmentWithDevTools.js.flow +33 -0
  96. package/util/withDuration.js.flow +32 -0
  97. package/lib/store/RelayRecordSourceMapImpl.js +0 -107
  98. package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +0 -318
  99. package/store/RelayRecordSourceMapImpl.js.flow +0 -91
  100. package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +0 -283
@@ -40,4 +40,8 @@ function generateUniqueClientID(): DataID {
40
40
  return `${PREFIX}local:${localID++}`;
41
41
  }
42
42
 
43
- module.exports = {generateClientID, generateUniqueClientID, isClientID};
43
+ module.exports = {
44
+ generateClientID,
45
+ generateUniqueClientID,
46
+ isClientID,
47
+ };
@@ -27,9 +27,11 @@ const getOperation = require('../util/getOperation');
27
27
  const invariant = require('invariant');
28
28
 
29
29
  const {isClientID} = require('./ClientID');
30
+ const {getLocalVariables} = require('./RelayConcreteVariables');
30
31
  const {EXISTENT, UNKNOWN} = require('./RelayRecordState');
31
32
  const {generateTypeID} = require('./TypeID');
32
33
 
34
+ import type {ActorIdentifier} from '../multi-actor-environment/ActorIdentifier';
33
35
  import type {
34
36
  NormalizationField,
35
37
  NormalizationFlightField,
@@ -57,6 +59,7 @@ export type Availability = {|
57
59
  |};
58
60
 
59
61
  const {
62
+ ACTOR_CHANGE,
60
63
  CONDITION,
61
64
  CLIENT_COMPONENT,
62
65
  CLIENT_EXTENSION,
@@ -90,8 +93,9 @@ const {
90
93
  * If all records are present, returns `true`, otherwise `false`.
91
94
  */
92
95
  function check(
93
- source: RecordSource,
94
- target: MutableRecordSource,
96
+ getSourceForActor: (actorIdentifier: ActorIdentifier) => RecordSource,
97
+ getTargetForActor: (actorIdentifier: ActorIdentifier) => MutableRecordSource,
98
+ defaultActorIdentifier: ActorIdentifier,
95
99
  selector: NormalizationSelector,
96
100
  handlers: $ReadOnlyArray<MissingFieldHandler>,
97
101
  operationLoader: ?OperationLoader,
@@ -100,8 +104,9 @@ function check(
100
104
  ): Availability {
101
105
  const {dataID, node, variables} = selector;
102
106
  const checker = new DataChecker(
103
- source,
104
- target,
107
+ getSourceForActor,
108
+ getTargetForActor,
109
+ defaultActorIdentifier,
105
110
  variables,
106
111
  handlers,
107
112
  operationLoader,
@@ -125,28 +130,67 @@ class DataChecker {
125
130
  _source: RecordSource;
126
131
  _variables: Variables;
127
132
  _shouldProcessClientComponents: ?boolean;
133
+ +_getSourceForActor: (actorIdentifier: ActorIdentifier) => RecordSource;
134
+ +_getTargetForActor: (
135
+ actorIdentifier: ActorIdentifier,
136
+ ) => MutableRecordSource;
137
+ +_getDataID: GetDataID;
138
+ +_mutatorRecordSourceProxyCache: Map<
139
+ ActorIdentifier,
140
+ [RelayRecordSourceMutator, RelayRecordSourceProxy],
141
+ >;
128
142
 
129
143
  constructor(
130
- source: RecordSource,
131
- target: MutableRecordSource,
144
+ getSourceForActor: (actorIdentifier: ActorIdentifier) => RecordSource,
145
+ getTargetForActor: (
146
+ actorIdentifier: ActorIdentifier,
147
+ ) => MutableRecordSource,
148
+ defaultActorIdentifier: ActorIdentifier,
132
149
  variables: Variables,
133
150
  handlers: $ReadOnlyArray<MissingFieldHandler>,
134
151
  operationLoader: ?OperationLoader,
135
152
  getDataID: GetDataID,
136
153
  shouldProcessClientComponents: ?boolean,
137
154
  ) {
138
- const mutator = new RelayRecordSourceMutator(source, target);
155
+ this._getSourceForActor = getSourceForActor;
156
+ this._getTargetForActor = getTargetForActor;
157
+ this._getDataID = getDataID;
158
+ this._source = getSourceForActor(defaultActorIdentifier);
159
+ this._mutatorRecordSourceProxyCache = new Map();
160
+ const [mutator, recordSourceProxy] = this._getMutatorAndRecordProxyForActor(
161
+ defaultActorIdentifier,
162
+ );
139
163
  this._mostRecentlyInvalidatedAt = null;
140
164
  this._handlers = handlers;
141
165
  this._mutator = mutator;
142
166
  this._operationLoader = operationLoader ?? null;
143
- this._recordSourceProxy = new RelayRecordSourceProxy(mutator, getDataID);
167
+ this._recordSourceProxy = recordSourceProxy;
144
168
  this._recordWasMissing = false;
145
- this._source = source;
146
169
  this._variables = variables;
147
170
  this._shouldProcessClientComponents = shouldProcessClientComponents;
148
171
  }
149
172
 
173
+ _getMutatorAndRecordProxyForActor(
174
+ actorIdentifier: ActorIdentifier,
175
+ ): [RelayRecordSourceMutator, RelayRecordSourceProxy] {
176
+ let tuple = this._mutatorRecordSourceProxyCache.get(actorIdentifier);
177
+ if (tuple == null) {
178
+ const target = this._getTargetForActor(actorIdentifier);
179
+
180
+ const mutator = new RelayRecordSourceMutator(
181
+ this._getSourceForActor(actorIdentifier),
182
+ target,
183
+ );
184
+ const recordSourceProxy = new RelayRecordSourceProxy(
185
+ mutator,
186
+ this._getDataID,
187
+ );
188
+ tuple = [mutator, recordSourceProxy];
189
+ this._mutatorRecordSourceProxyCache.set(actorIdentifier, tuple);
190
+ }
191
+ return tuple;
192
+ }
193
+
150
194
  check(node: NormalizationNode, dataID: DataID): Availability {
151
195
  this._traverse(node, dataID);
152
196
 
@@ -184,6 +228,8 @@ class DataChecker {
184
228
  ...
185
229
  } {
186
230
  return {
231
+ /* $FlowFixMe[class-object-subtyping] added when improving typing for
232
+ * this parameters */
187
233
  args: field.args ? getArgumentValues(field.args, this._variables) : {},
188
234
  // Getting a snapshot of the record state is potentially expensive since
189
235
  // we will need to merge the sink and source records. Since we do not create
@@ -309,8 +355,13 @@ class DataChecker {
309
355
  this._checkLink(selection, dataID);
310
356
  }
311
357
  break;
358
+ case ACTOR_CHANGE:
359
+ this._checkActorChange(selection.linkedField, dataID);
360
+ break;
312
361
  case CONDITION:
313
- const conditionValue = this._getVariableValue(selection.condition);
362
+ const conditionValue = Boolean(
363
+ this._getVariableValue(selection.condition),
364
+ );
314
365
  if (conditionValue === selection.passingValue) {
315
366
  this._traverseSelections(selection.selections, dataID);
316
367
  }
@@ -323,7 +374,7 @@ class DataChecker {
323
374
  if (typeName === selection.type) {
324
375
  this._traverseSelections(selection.selections, dataID);
325
376
  }
326
- } else if (RelayFeatureFlags.ENABLE_PRECISE_TYPE_REFINEMENT) {
377
+ } else {
327
378
  // Abstract refinement: check data depending on whether the type
328
379
  // conforms to the interface/union or not:
329
380
  // - Type known to _not_ implement the interface: don't check the selections.
@@ -349,10 +400,6 @@ class DataChecker {
349
400
  // missing so don't bother reading the fragment
350
401
  this._handleMissing();
351
402
  } // else false: known to not implement the interface
352
- } else {
353
- // legacy behavior for abstract refinements: always check even
354
- // if the type doesn't conform
355
- this._traverseSelections(selection.selections, dataID);
356
403
  }
357
404
  break;
358
405
  }
@@ -388,9 +435,15 @@ class DataChecker {
388
435
  case STREAM:
389
436
  this._traverseSelections(selection.selections, dataID);
390
437
  break;
391
- // $FlowFixMe[incompatible-type]
392
438
  case FRAGMENT_SPREAD:
439
+ const prevVariables = this._variables;
440
+ this._variables = getLocalVariables(
441
+ this._variables,
442
+ selection.fragment.argumentDefinitions,
443
+ selection.args,
444
+ );
393
445
  this._traverseSelections(selection.fragment.selections, dataID);
446
+ this._variables = prevVariables;
394
447
  break;
395
448
  case CLIENT_EXTENSION:
396
449
  const recordWasMissing = this._recordWasMissing;
@@ -398,25 +451,23 @@ class DataChecker {
398
451
  this._recordWasMissing = recordWasMissing;
399
452
  break;
400
453
  case TYPE_DISCRIMINATOR:
401
- if (RelayFeatureFlags.ENABLE_PRECISE_TYPE_REFINEMENT) {
402
- const {abstractKey} = selection;
403
- const recordType = this._mutator.getType(dataID);
404
- invariant(
405
- recordType != null,
406
- 'DataChecker: Expected record `%s` to have a known type',
407
- dataID,
408
- );
409
- const typeID = generateTypeID(recordType);
410
- const implementsInterface = this._mutator.getValue(
411
- typeID,
412
- abstractKey,
413
- );
414
- if (implementsInterface == null) {
415
- // unsure if the type implements the interface: data is
416
- // missing
417
- this._handleMissing();
418
- } // else: if it does or doesn't implement, we don't need to check or skip anything else
419
- }
454
+ const {abstractKey} = selection;
455
+ const recordType = this._mutator.getType(dataID);
456
+ invariant(
457
+ recordType != null,
458
+ 'DataChecker: Expected record `%s` to have a known type',
459
+ dataID,
460
+ );
461
+ const typeID = generateTypeID(recordType);
462
+ const implementsInterface = this._mutator.getValue(
463
+ typeID,
464
+ abstractKey,
465
+ );
466
+ if (implementsInterface == null) {
467
+ // unsure if the type implements the interface: data is
468
+ // missing
469
+ this._handleMissing();
470
+ } // else: if it does or doesn't implement, we don't need to check or skip anything else
420
471
  break;
421
472
  case FLIGHT_FIELD:
422
473
  if (RelayFeatureFlags.ENABLE_REACT_FLIGHT_COMPONENT_FIELD) {
@@ -462,7 +513,14 @@ class DataChecker {
462
513
  const normalizationRootNode = operationLoader.get(operationReference);
463
514
  if (normalizationRootNode != null) {
464
515
  const operation = getOperation(normalizationRootNode);
516
+ const prevVariables = this._variables;
517
+ this._variables = getLocalVariables(
518
+ this._variables,
519
+ operation.argumentDefinitions,
520
+ moduleImport.args,
521
+ );
465
522
  this._traverse(operation, dataID);
523
+ this._variables = prevVariables;
466
524
  } else {
467
525
  // If the fragment is not available, we assume that the data cannot have been
468
526
  // processed yet and must therefore be missing.
@@ -519,6 +577,39 @@ class DataChecker {
519
577
  }
520
578
  }
521
579
 
580
+ _checkActorChange(field: NormalizationLinkedField, dataID: DataID): void {
581
+ const storageKey = getStorageKey(field, this._variables);
582
+ const record = this._source.get(dataID);
583
+ const tuple =
584
+ record != null
585
+ ? RelayModernRecord.getActorLinkedRecordID(record, storageKey)
586
+ : record;
587
+
588
+ if (tuple == null) {
589
+ if (tuple === undefined) {
590
+ this._handleMissing();
591
+ }
592
+ } else {
593
+ const [actorIdentifier, linkedID] = tuple;
594
+ const prevSource = this._source;
595
+ const prevMutator = this._mutator;
596
+ const prevRecordSourceProxy = this._recordSourceProxy;
597
+
598
+ const [
599
+ mutator,
600
+ recordSourceProxy,
601
+ ] = this._getMutatorAndRecordProxyForActor(actorIdentifier);
602
+
603
+ this._source = this._getSourceForActor(actorIdentifier);
604
+ this._mutator = mutator;
605
+ this._recordSourceProxy = recordSourceProxy;
606
+ this._traverse(field, linkedID);
607
+ this._source = prevSource;
608
+ this._mutator = prevMutator;
609
+ this._recordSourceProxy = prevRecordSourceProxy;
610
+ }
611
+ }
612
+
522
613
  _checkFlightField(field: NormalizationFlightField, dataID: DataID): void {
523
614
  const storageKey = getStorageKey(field, this._variables);
524
615
  const linkedID = this._mutator.getLinkedRecordID(dataID, storageKey);