relay-runtime 0.0.0-main-1ac62c2b → 0.0.0-main-c9cf5515

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/experimental.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Relay v0.0.0-main-1ac62c2b
2
+ * Relay v0.0.0-main-c9cf5515
3
3
  *
4
4
  * Copyright (c) Meta Platforms, Inc. and affiliates.
5
5
  *
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Relay v0.0.0-main-1ac62c2b
2
+ * Relay v0.0.0-main-c9cf5515
3
3
  *
4
4
  * Copyright (c) Meta Platforms, Inc. and affiliates.
5
5
  *
@@ -328,9 +328,20 @@ var Executor = /*#__PURE__*/function () {
328
328
  return ((_x$extensions = x.extensions) === null || _x$extensions === void 0 ? void 0 : _x$extensions.is_final) === true;
329
329
  });
330
330
  if (isFinal) {
331
- this._state = 'loading_final';
332
- this._updateActiveState();
333
- this._incrementalPayloadsPending = false;
331
+ if (this._useExecTimeResolvers && this._state !== 'loading_final' && responses.some(function (x) {
332
+ var _x$extensions2;
333
+ return ((_x$extensions2 = x.extensions) === null || _x$extensions2 === void 0 ? void 0 : _x$extensions2.is_normalized) === true;
334
+ })) {
335
+ this._execTimeResolverResponseComplete = true;
336
+ if (this._isClientQuery) {
337
+ this._state = 'loading_final';
338
+ }
339
+ this._updateActiveState();
340
+ } else {
341
+ this._state = 'loading_final';
342
+ this._updateActiveState();
343
+ this._incrementalPayloadsPending = false;
344
+ }
334
345
  }
335
346
  this._sink.next(response);
336
347
  return;
@@ -7,6 +7,7 @@ var _require = require('../multi-actor-environment/ActorIdentifier'),
7
7
  INTERNAL_ACTOR_IDENTIFIER_DO_NOT_USE = _require.INTERNAL_ACTOR_IDENTIFIER_DO_NOT_USE,
8
8
  assertInternalActorIdentifier = _require.assertInternalActorIdentifier;
9
9
  var deepFreeze = require('../util/deepFreeze');
10
+ var RelayFeatureFlags = require('../util/RelayFeatureFlags');
10
11
  var resolveImmediate = require('../util/resolveImmediate');
11
12
  var DataChecker = require('./DataChecker');
12
13
  var defaultGetDataID = require('./defaultGetDataID');
@@ -218,17 +219,33 @@ var RelayModernStore = /*#__PURE__*/function () {
218
219
  sourceOperation: sourceOperation
219
220
  });
220
221
  }
221
- this._currentWriteEpoch++;
222
- if (invalidateStore === true) {
223
- this._globalInvalidationEpoch = this._currentWriteEpoch;
222
+ if (!RelayFeatureFlags.OPTIMIZE_NOTIFY) {
223
+ this._currentWriteEpoch++;
224
+ if (invalidateStore === true) {
225
+ this._globalInvalidationEpoch = this._currentWriteEpoch;
226
+ }
227
+ }
228
+ if (!RelayFeatureFlags.OPTIMIZE_NOTIFY || this._updatedRecordIDs.size > 0) {
229
+ this._resolverCache.invalidateDataIDs(this._updatedRecordIDs);
224
230
  }
225
- this._resolverCache.invalidateDataIDs(this._updatedRecordIDs);
226
231
  var source = this.getSource();
227
232
  var updatedOwners = [];
228
- this._storeSubscriptions.updateSubscriptions(source, this._updatedRecordIDs, updatedOwners, sourceOperation);
229
- this._invalidationSubscriptions.forEach(function (subscription) {
230
- _this3._updateInvalidationSubscription(subscription, invalidateStore === true);
231
- });
233
+ if (!RelayFeatureFlags.OPTIMIZE_NOTIFY || this._updatedRecordIDs.size > 0) {
234
+ this._storeSubscriptions.updateSubscriptions(source, this._updatedRecordIDs, updatedOwners, sourceOperation);
235
+ } else {
236
+ this._storeSubscriptions.updateStaleSubscriptions(source, this._updatedRecordIDs, updatedOwners, sourceOperation);
237
+ }
238
+ if (RelayFeatureFlags.OPTIMIZE_NOTIFY && (this._updatedRecordIDs.size > 0 || updatedOwners.length > 0 || this._invalidatedRecordIDs.size > 0 || invalidateStore === true || this._globalInvalidationEpoch === this._currentWriteEpoch)) {
239
+ this._currentWriteEpoch++;
240
+ if (invalidateStore === true) {
241
+ this._globalInvalidationEpoch = this._currentWriteEpoch;
242
+ }
243
+ }
244
+ if (!RelayFeatureFlags.OPTIMIZE_NOTIFY || this._invalidatedRecordIDs.size > 0 || invalidateStore === true) {
245
+ this._invalidationSubscriptions.forEach(function (subscription) {
246
+ _this3._updateInvalidationSubscription(subscription, invalidateStore === true);
247
+ });
248
+ }
232
249
  if (sourceOperation != null) {
233
250
  var id = sourceOperation.request.identifier;
234
251
  var rootEntry = this._roots.get(id);
@@ -9,6 +9,7 @@ var RelayReader = require('./RelayReader');
9
9
  var RelayStoreSubscriptions = /*#__PURE__*/function () {
10
10
  function RelayStoreSubscriptions(log, resolverCache, resolverContext) {
11
11
  this._subscriptions = new Set();
12
+ this._staleSubscriptions = new Set();
12
13
  this.__log = log;
13
14
  this._resolverCache = resolverCache;
14
15
  this._resolverContext = resolverContext;
@@ -24,6 +25,9 @@ var RelayStoreSubscriptions = /*#__PURE__*/function () {
24
25
  };
25
26
  var dispose = function dispose() {
26
27
  _this._subscriptions["delete"](subscription);
28
+ if (RelayFeatureFlags.OPTIMIZE_NOTIFY && subscription.stale) {
29
+ _this._staleSubscriptions["delete"](subscription);
30
+ }
27
31
  };
28
32
  this._subscriptions.add(subscription);
29
33
  return {
@@ -45,12 +49,16 @@ var RelayStoreSubscriptions = /*#__PURE__*/function () {
45
49
  });
46
50
  };
47
51
  _proto.restoreSubscriptions = function restoreSubscriptions() {
52
+ var _this3 = this;
48
53
  this._subscriptions.forEach(function (subscription) {
49
54
  var backup = subscription.backup;
50
55
  subscription.backup = null;
51
56
  if (backup) {
52
57
  if (backup.data !== subscription.snapshot.data) {
53
58
  subscription.stale = true;
59
+ if (RelayFeatureFlags.OPTIMIZE_NOTIFY) {
60
+ _this3._staleSubscriptions.add(subscription);
61
+ }
54
62
  }
55
63
  subscription.snapshot = {
56
64
  data: subscription.snapshot.data,
@@ -63,14 +71,27 @@ var RelayStoreSubscriptions = /*#__PURE__*/function () {
63
71
  };
64
72
  } else {
65
73
  subscription.stale = true;
74
+ if (RelayFeatureFlags.OPTIMIZE_NOTIFY) {
75
+ _this3._staleSubscriptions.add(subscription);
76
+ }
66
77
  }
67
78
  });
68
79
  };
69
80
  _proto.updateSubscriptions = function updateSubscriptions(source, updatedRecordIDs, updatedOwners, sourceOperation) {
70
- var _this3 = this;
81
+ var _this4 = this;
71
82
  var hasUpdatedRecords = updatedRecordIDs.size !== 0;
72
83
  this._subscriptions.forEach(function (subscription) {
73
- var owner = _this3._updateSubscription(source, subscription, updatedRecordIDs, hasUpdatedRecords, sourceOperation);
84
+ var owner = _this4._updateSubscription(source, subscription, updatedRecordIDs, hasUpdatedRecords, sourceOperation);
85
+ if (owner != null) {
86
+ updatedOwners.push(owner);
87
+ }
88
+ });
89
+ };
90
+ _proto.updateStaleSubscriptions = function updateStaleSubscriptions(source, updatedRecordIDs, updatedOwners, sourceOperation) {
91
+ var _this5 = this;
92
+ var hasUpdatedRecords = updatedRecordIDs.size !== 0;
93
+ this._staleSubscriptions.forEach(function (subscription) {
94
+ var owner = _this5._updateSubscription(source, subscription, updatedRecordIDs, hasUpdatedRecords, sourceOperation);
74
95
  if (owner != null) {
75
96
  updatedOwners.push(owner);
76
97
  }
@@ -101,6 +122,9 @@ var RelayStoreSubscriptions = /*#__PURE__*/function () {
101
122
  }
102
123
  subscription.snapshot = nextSnapshot;
103
124
  subscription.stale = false;
125
+ if (RelayFeatureFlags.OPTIMIZE_NOTIFY && stale) {
126
+ this._staleSubscriptions["delete"](subscription);
127
+ }
104
128
  if (nextSnapshot.data !== snapshot.data) {
105
129
  if (this.__log && RelayFeatureFlags.ENABLE_NOTIFY_SUBSCRIPTION) {
106
130
  this.__log({
@@ -27,6 +27,7 @@ var RelayFeatureFlags = {
27
27
  ENABLE_TYPENAME_PREFIXED_DATA_ID: false,
28
28
  ENABLE_UI_CONTEXT_ON_RELAY_LOGGER: false,
29
29
  CHECK_ALL_FRAGMENTS_FOR_MISSING_CLIENT_EDGES: false,
30
- FILTER_OUT_RELAY_RESOLVER_RECORDS: false
30
+ FILTER_OUT_RELAY_RESOLVER_RECORDS: false,
31
+ OPTIMIZE_NOTIFY: false
31
32
  };
32
33
  module.exports = RelayFeatureFlags;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "relay-runtime",
3
3
  "description": "A core runtime for building GraphQL-driven applications.",
4
- "version": "0.0.0-main-1ac62c2b",
4
+ "version": "0.0.0-main-c9cf5515",
5
5
  "keywords": [
6
6
  "graphql",
7
7
  "relay"
@@ -515,12 +515,32 @@ class Executor<TMutation: MutationParameters> {
515
515
 
516
516
  if (responsesWithData.length === 0) {
517
517
  // no results with data, nothing to process
518
- // this can occur with extensions-only payloads
518
+ // this can occur with extensions-only payloads, or exec time resolver
519
+ // responses
519
520
  const isFinal = responses.some(x => x.extensions?.is_final === true);
520
521
  if (isFinal) {
521
- this._state = 'loading_final';
522
- this._updateActiveState();
523
- this._incrementalPayloadsPending = false;
522
+ if (
523
+ this._useExecTimeResolvers &&
524
+ this._state !== 'loading_final' &&
525
+ responses.some(x => x.extensions?.is_normalized === true)
526
+ ) {
527
+ // An exec time resolver query can flush an empty response, if the
528
+ // same response has been included in other queries. Check if we need
529
+ // to mark the request as final
530
+ this._execTimeResolverResponseComplete = true;
531
+ // Need to update the active state to mark the query as inactive,
532
+ // incase server payloads have completed
533
+ if (this._isClientQuery) {
534
+ // If it is a client query, there is no server response to set the
535
+ // final state, so we need to set it here
536
+ this._state = 'loading_final';
537
+ }
538
+ this._updateActiveState();
539
+ } else {
540
+ this._state = 'loading_final';
541
+ this._updateActiveState();
542
+ this._incrementalPayloadsPending = false;
543
+ }
524
544
  }
525
545
  this._sink.next(response);
526
546
  return;
@@ -40,6 +40,7 @@ const {
40
40
  assertInternalActorIdentifier,
41
41
  } = require('../multi-actor-environment/ActorIdentifier');
42
42
  const deepFreeze = require('../util/deepFreeze');
43
+ const RelayFeatureFlags = require('../util/RelayFeatureFlags');
43
44
  const resolveImmediate = require('../util/resolveImmediate');
44
45
  const DataChecker = require('./DataChecker');
45
46
  const defaultGetDataID = require('./defaultGetDataID');
@@ -413,34 +414,73 @@ class RelayModernStore implements Store {
413
414
  });
414
415
  }
415
416
 
416
- // Increment the current write when notifying after executing
417
- // a set of changes to the store.
418
- this._currentWriteEpoch++;
417
+ if (!RelayFeatureFlags.OPTIMIZE_NOTIFY) {
418
+ // Increment the current write when notifying after executing
419
+ // a set of changes to the store.
420
+ this._currentWriteEpoch++;
419
421
 
420
- if (invalidateStore === true) {
421
- this._globalInvalidationEpoch = this._currentWriteEpoch;
422
+ if (invalidateStore === true) {
423
+ this._globalInvalidationEpoch = this._currentWriteEpoch;
424
+ }
422
425
  }
423
426
 
424
427
  // When a record is updated, we need to also handle records that depend on it,
425
428
  // specifically Relay Resolver result records containing results based on the
426
429
  // updated records. This both adds to updatedRecordIDs and invalidates any
427
430
  // cached data as needed.
428
- this._resolverCache.invalidateDataIDs(this._updatedRecordIDs);
431
+ if (!RelayFeatureFlags.OPTIMIZE_NOTIFY || this._updatedRecordIDs.size > 0) {
432
+ this._resolverCache.invalidateDataIDs(this._updatedRecordIDs);
433
+ }
429
434
 
430
435
  const source = this.getSource();
431
436
  const updatedOwners: Array<RequestDescriptor> = [];
432
- this._storeSubscriptions.updateSubscriptions(
433
- source,
434
- this._updatedRecordIDs,
435
- updatedOwners,
436
- sourceOperation,
437
- );
438
- this._invalidationSubscriptions.forEach(subscription => {
439
- this._updateInvalidationSubscription(
440
- subscription,
441
- invalidateStore === true,
437
+ if (!RelayFeatureFlags.OPTIMIZE_NOTIFY || this._updatedRecordIDs.size > 0) {
438
+ this._storeSubscriptions.updateSubscriptions(
439
+ source,
440
+ this._updatedRecordIDs,
441
+ updatedOwners,
442
+ sourceOperation,
442
443
  );
443
- });
444
+ } else {
445
+ // If no record is updated, we still need to traverse stale subscriptions for
446
+ // subscriptions that were using values from optimistic updates
447
+ this._storeSubscriptions.updateStaleSubscriptions(
448
+ source,
449
+ this._updatedRecordIDs,
450
+ updatedOwners,
451
+ sourceOperation,
452
+ );
453
+ }
454
+
455
+ if (
456
+ RelayFeatureFlags.OPTIMIZE_NOTIFY &&
457
+ (this._updatedRecordIDs.size > 0 ||
458
+ updatedOwners.length > 0 ||
459
+ this._invalidatedRecordIDs.size > 0 ||
460
+ invalidateStore === true ||
461
+ this._globalInvalidationEpoch === this._currentWriteEpoch)
462
+ ) {
463
+ // Increment the current write when notifying after executing
464
+ // a set of changes to the store.
465
+ this._currentWriteEpoch++;
466
+
467
+ if (invalidateStore === true) {
468
+ this._globalInvalidationEpoch = this._currentWriteEpoch;
469
+ }
470
+ }
471
+
472
+ if (
473
+ !RelayFeatureFlags.OPTIMIZE_NOTIFY ||
474
+ this._invalidatedRecordIDs.size > 0 ||
475
+ invalidateStore === true
476
+ ) {
477
+ this._invalidationSubscriptions.forEach(subscription => {
478
+ this._updateInvalidationSubscription(
479
+ subscription,
480
+ invalidateStore === true,
481
+ );
482
+ });
483
+ }
444
484
 
445
485
  // If a source operation was provided (indicating the operation
446
486
  // that produced this update to the store), record the current epoch
@@ -43,6 +43,9 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
43
43
  __log: ?LogFunction;
44
44
  _resolverCache: ResolverCache;
45
45
  _resolverContext: ?ResolverContext;
46
+ // Stores `subscriptions` with stale snapshots, used for reducing the traversal
47
+ // that has to happen on `notify`
48
+ _staleSubscriptions: Set<Subscription>;
46
49
 
47
50
  constructor(
48
51
  log?: ?LogFunction,
@@ -50,6 +53,7 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
50
53
  resolverContext?: ResolverContext,
51
54
  ) {
52
55
  this._subscriptions = new Set();
56
+ this._staleSubscriptions = new Set();
53
57
  this.__log = log;
54
58
  this._resolverCache = resolverCache;
55
59
  this._resolverContext = resolverContext;
@@ -67,6 +71,9 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
67
71
  };
68
72
  const dispose = () => {
69
73
  this._subscriptions.delete(subscription);
74
+ if (RelayFeatureFlags.OPTIMIZE_NOTIFY && subscription.stale) {
75
+ this._staleSubscriptions.delete(subscription);
76
+ }
70
77
  };
71
78
  this._subscriptions.add(subscription);
72
79
  return {dispose};
@@ -112,6 +119,9 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
112
119
  // This subscription's data changed in the optimistic state. We will
113
120
  // need to re-read.
114
121
  subscription.stale = true;
122
+ if (RelayFeatureFlags.OPTIMIZE_NOTIFY) {
123
+ this._staleSubscriptions.add(subscription);
124
+ }
115
125
  }
116
126
  subscription.snapshot = {
117
127
  data: subscription.snapshot.data,
@@ -126,6 +136,9 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
126
136
  // This subscription was created during the optimisitic state. We should
127
137
  // re-read.
128
138
  subscription.stale = true;
139
+ if (RelayFeatureFlags.OPTIMIZE_NOTIFY) {
140
+ this._staleSubscriptions.add(subscription);
141
+ }
129
142
  }
130
143
  });
131
144
  }
@@ -151,6 +164,27 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
151
164
  });
152
165
  }
153
166
 
167
+ updateStaleSubscriptions(
168
+ source: RecordSource,
169
+ updatedRecordIDs: DataIDSet,
170
+ updatedOwners: Array<RequestDescriptor>,
171
+ sourceOperation?: OperationDescriptor,
172
+ ) {
173
+ const hasUpdatedRecords = updatedRecordIDs.size !== 0;
174
+ this._staleSubscriptions.forEach(subscription => {
175
+ const owner = this._updateSubscription(
176
+ source,
177
+ subscription,
178
+ updatedRecordIDs,
179
+ hasUpdatedRecords,
180
+ sourceOperation,
181
+ );
182
+ if (owner != null) {
183
+ updatedOwners.push(owner);
184
+ }
185
+ });
186
+ }
187
+
154
188
  /**
155
189
  * Notifies the callback for the subscription if the data for the associated
156
190
  * snapshot has changed.
@@ -197,6 +231,9 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
197
231
  }
198
232
  subscription.snapshot = nextSnapshot;
199
233
  subscription.stale = false;
234
+ if (RelayFeatureFlags.OPTIMIZE_NOTIFY && stale) {
235
+ this._staleSubscriptions.delete(subscription);
236
+ }
200
237
  if (nextSnapshot.data !== snapshot.data) {
201
238
  if (this.__log && RelayFeatureFlags.ENABLE_NOTIFY_SUBSCRIPTION) {
202
239
  this.__log({
@@ -422,6 +422,16 @@ export interface StoreSubscriptions {
422
422
  sourceOperation?: OperationDescriptor,
423
423
  ): void;
424
424
 
425
+ /**
426
+ * Same as `updateSubscriptions`, except it only notifies subscriptions with stale snapshots.
427
+ */
428
+ updateStaleSubscriptions(
429
+ source: RecordSource,
430
+ updatedRecordIDs: DataIDSet,
431
+ updatedOwners: Array<RequestDescriptor>,
432
+ sourceOperation?: OperationDescriptor,
433
+ ): void;
434
+
425
435
  /**
426
436
  * returns the number of subscriptions
427
437
  */
@@ -84,6 +84,9 @@ export type FeatureFlags = {
84
84
  // When enabled, records created for Relay Resolvers will be filtered out
85
85
  // from the store when serializing to JSON.
86
86
  FILTER_OUT_RELAY_RESOLVER_RECORDS: boolean,
87
+
88
+ // Reduce the work on store.notify
89
+ OPTIMIZE_NOTIFY: boolean,
87
90
  };
88
91
 
89
92
  const RelayFeatureFlags: FeatureFlags = {
@@ -114,6 +117,7 @@ const RelayFeatureFlags: FeatureFlags = {
114
117
  ENABLE_UI_CONTEXT_ON_RELAY_LOGGER: false,
115
118
  CHECK_ALL_FRAGMENTS_FOR_MISSING_CLIENT_EDGES: false,
116
119
  FILTER_OUT_RELAY_RESOLVER_RECORDS: false,
120
+ OPTIMIZE_NOTIFY: false,
117
121
  };
118
122
 
119
123
  module.exports = RelayFeatureFlags;