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.
- package/handlers/RelayDefaultHandlerProvider.js.flow +6 -0
- package/handlers/connection/MutationHandlers.js.flow +152 -20
- package/index.js +1 -1
- package/index.js.flow +17 -1
- package/lib/handlers/RelayDefaultHandlerProvider.js +9 -0
- package/lib/handlers/connection/MutationHandlers.js +185 -21
- package/lib/index.js +7 -0
- package/lib/mutations/RelayDeclarativeMutationConfig.js +5 -7
- package/lib/mutations/commitMutation.js +1 -4
- package/lib/mutations/validateMutation.js +28 -12
- package/lib/network/RelayQueryResponseCache.js +3 -7
- package/lib/query/GraphQLTag.js +2 -1
- package/lib/query/fetchQuery.js +2 -3
- package/lib/query/fetchQueryInternal.js +2 -3
- package/lib/store/DataChecker.js +85 -10
- package/lib/store/RelayConcreteVariables.js +2 -6
- package/lib/store/RelayModernEnvironment.js +81 -72
- package/lib/store/RelayModernFragmentSpecResolver.js +14 -7
- package/lib/store/RelayModernOperationDescriptor.js +6 -5
- package/lib/store/RelayModernQueryExecutor.js +46 -33
- package/lib/store/RelayModernRecord.js +3 -7
- package/lib/store/RelayModernStore.js +39 -137
- package/lib/store/RelayOperationTracker.js +7 -9
- package/lib/store/RelayOptimisticRecordSource.js +2 -6
- package/lib/store/RelayPublishQueue.js +1 -1
- package/lib/store/RelayReader.js +196 -33
- package/lib/store/RelayRecordSourceMapImpl.js +3 -5
- package/lib/store/RelayReferenceMarker.js +87 -5
- package/lib/store/RelayResponseNormalizer.js +115 -19
- package/lib/store/RelayStoreReactFlightUtils.js +47 -0
- package/lib/store/RelayStoreSubscriptions.js +162 -0
- package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +258 -0
- package/lib/store/StoreInspector.js +2 -6
- package/lib/store/createRelayContext.js +5 -0
- package/lib/store/defaultRequiredFieldLogger.js +18 -0
- package/lib/store/normalizeRelayPayload.js +2 -6
- package/lib/subscription/requestSubscription.js +2 -3
- package/lib/util/NormalizationNode.js +1 -5
- package/lib/util/RelayConcreteNode.js +2 -0
- package/lib/util/RelayFeatureFlags.js +7 -2
- package/lib/util/createPayloadFor3DField.js +2 -7
- package/lib/util/getFragmentIdentifier.js +12 -3
- package/lib/util/getOperation.js +33 -0
- package/lib/util/isEmptyObject.js +25 -0
- package/lib/util/recycleNodesInto.js +4 -1
- package/lib/util/reportMissingRequiredFields.js +48 -0
- package/mutations/commitMutation.js.flow +1 -2
- package/mutations/validateMutation.js.flow +34 -5
- package/network/RelayNetworkTypes.js.flow +22 -0
- package/package.json +2 -2
- package/query/GraphQLTag.js.flow +3 -1
- package/query/fetchQuery.js.flow +2 -2
- package/query/fetchQueryInternal.js.flow +0 -5
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/DataChecker.js.flow +68 -2
- package/store/RelayModernEnvironment.js.flow +107 -87
- package/store/RelayModernFragmentSpecResolver.js.flow +13 -1
- package/store/RelayModernOperationDescriptor.js.flow +5 -1
- package/store/RelayModernQueryExecutor.js.flow +47 -23
- package/store/RelayModernStore.js.flow +33 -107
- package/store/RelayPublishQueue.js.flow +1 -1
- package/store/RelayReader.js.flow +180 -15
- package/store/RelayReferenceMarker.js.flow +72 -5
- package/store/RelayResponseNormalizer.js.flow +130 -19
- package/store/RelayStoreReactFlightUtils.js.flow +64 -0
- package/store/RelayStoreSubscriptions.js.flow +168 -0
- package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +259 -0
- package/store/RelayStoreTypes.js.flow +130 -37
- package/store/createRelayContext.js.flow +3 -0
- package/store/defaultRequiredFieldLogger.js.flow +23 -0
- package/subscription/requestSubscription.js.flow +5 -2
- package/util/NormalizationNode.js.flow +17 -2
- package/util/ReaderNode.js.flow +20 -1
- package/util/RelayConcreteNode.js.flow +6 -0
- package/util/RelayFeatureFlags.js.flow +12 -1
- package/util/getFragmentIdentifier.js.flow +33 -9
- package/util/getOperation.js.flow +40 -0
- package/util/getRequestIdentifier.js.flow +1 -1
- package/util/isEmptyObject.js.flow +25 -0
- package/util/recycleNodesInto.js.flow +11 -0
- package/util/reportMissingRequiredFields.js.flow +51 -0
|
@@ -0,0 +1,259 @@
|
|
|
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
|
+
*/
|
|
10
|
+
|
|
11
|
+
// flowlint ambiguous-object-type:error
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const RelayReader = require('./RelayReader');
|
|
16
|
+
|
|
17
|
+
const deepFreeze = require('../util/deepFreeze');
|
|
18
|
+
const recycleNodesInto = require('../util/recycleNodesInto');
|
|
19
|
+
|
|
20
|
+
import type {DataID, Disposable} from '../util/RelayRuntimeTypes';
|
|
21
|
+
import type {
|
|
22
|
+
RecordMap,
|
|
23
|
+
RecordSource,
|
|
24
|
+
RequestDescriptor,
|
|
25
|
+
Snapshot,
|
|
26
|
+
StoreSubscriptions,
|
|
27
|
+
UpdatedRecords,
|
|
28
|
+
} from './RelayStoreTypes';
|
|
29
|
+
|
|
30
|
+
type Subscription = {|
|
|
31
|
+
backup: ?Snapshot,
|
|
32
|
+
callback: (snapshot: Snapshot) => void,
|
|
33
|
+
notifiedRevision: number,
|
|
34
|
+
snapshot: Snapshot,
|
|
35
|
+
snapshotRevision: number,
|
|
36
|
+
|};
|
|
37
|
+
|
|
38
|
+
class RelayStoreSubscriptionsUsingMapByID implements StoreSubscriptions {
|
|
39
|
+
_notifiedRevision: number;
|
|
40
|
+
_snapshotRevision: number;
|
|
41
|
+
_subscriptionsByDataId: Map<DataID, Set<Subscription>>;
|
|
42
|
+
_staleSubscriptions: Set<Subscription>;
|
|
43
|
+
|
|
44
|
+
constructor() {
|
|
45
|
+
this._notifiedRevision = 0;
|
|
46
|
+
this._snapshotRevision = 0;
|
|
47
|
+
this._subscriptionsByDataId = new Map();
|
|
48
|
+
this._staleSubscriptions = new Set();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
subscribe(
|
|
52
|
+
snapshot: Snapshot,
|
|
53
|
+
callback: (snapshot: Snapshot) => void,
|
|
54
|
+
): Disposable {
|
|
55
|
+
const subscription = {
|
|
56
|
+
backup: null,
|
|
57
|
+
callback,
|
|
58
|
+
notifiedRevision: this._notifiedRevision,
|
|
59
|
+
snapshotRevision: this._snapshotRevision,
|
|
60
|
+
snapshot,
|
|
61
|
+
};
|
|
62
|
+
const dispose = () => {
|
|
63
|
+
for (const dataId in snapshot.seenRecords) {
|
|
64
|
+
const subscriptionsForDataId = this._subscriptionsByDataId.get(dataId);
|
|
65
|
+
if (subscriptionsForDataId != null) {
|
|
66
|
+
subscriptionsForDataId.delete(subscription);
|
|
67
|
+
if (subscriptionsForDataId.size === 0) {
|
|
68
|
+
this._subscriptionsByDataId.delete(dataId);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
for (const dataId in snapshot.seenRecords) {
|
|
75
|
+
const subscriptionsForDataId = this._subscriptionsByDataId.get(dataId);
|
|
76
|
+
if (subscriptionsForDataId != null) {
|
|
77
|
+
subscriptionsForDataId.add(subscription);
|
|
78
|
+
} else {
|
|
79
|
+
this._subscriptionsByDataId.set(dataId, new Set([subscription]));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {dispose};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
snapshotSubscriptions(source: RecordSource) {
|
|
87
|
+
this._snapshotRevision++;
|
|
88
|
+
this._subscriptionsByDataId.forEach(subscriptions => {
|
|
89
|
+
subscriptions.forEach(subscription => {
|
|
90
|
+
if (subscription.snapshotRevision === this._snapshotRevision) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
subscription.snapshotRevision = this._snapshotRevision;
|
|
94
|
+
|
|
95
|
+
// Backup occurs after writing a new "final" payload(s) and before (re)applying
|
|
96
|
+
// optimistic changes. Each subscription's `snapshot` represents what was *last
|
|
97
|
+
// published to the subscriber*, which notably may include previous optimistic
|
|
98
|
+
// updates. Therefore a subscription can be in any of the following states:
|
|
99
|
+
// - stale=true: This subscription was restored to a different value than
|
|
100
|
+
// `snapshot`. That means this subscription has changes relative to its base,
|
|
101
|
+
// but its base has changed (we just applied a final payload): recompute
|
|
102
|
+
// a backup so that we can later restore to the state the subscription
|
|
103
|
+
// should be in.
|
|
104
|
+
// - stale=false: This subscription was restored to the same value than
|
|
105
|
+
// `snapshot`. That means this subscription does *not* have changes relative
|
|
106
|
+
// to its base, so the current `snapshot` is valid to use as a backup.
|
|
107
|
+
if (!this._staleSubscriptions.has(subscription)) {
|
|
108
|
+
subscription.backup = subscription.snapshot;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const snapshot = subscription.snapshot;
|
|
112
|
+
const backup = RelayReader.read(source, snapshot.selector);
|
|
113
|
+
const nextData = recycleNodesInto(snapshot.data, backup.data);
|
|
114
|
+
(backup: $FlowFixMe).data = nextData; // backup owns the snapshot and can safely mutate
|
|
115
|
+
subscription.backup = backup;
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
restoreSubscriptions() {
|
|
121
|
+
this._snapshotRevision++;
|
|
122
|
+
this._subscriptionsByDataId.forEach(subscriptions => {
|
|
123
|
+
subscriptions.forEach(subscription => {
|
|
124
|
+
if (subscription.snapshotRevision === this._snapshotRevision) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
subscription.snapshotRevision = this._snapshotRevision;
|
|
128
|
+
|
|
129
|
+
const backup = subscription.backup;
|
|
130
|
+
subscription.backup = null;
|
|
131
|
+
if (backup) {
|
|
132
|
+
if (backup.data !== subscription.snapshot.data) {
|
|
133
|
+
this._staleSubscriptions.add(subscription);
|
|
134
|
+
}
|
|
135
|
+
const prevSeenRecords = subscription.snapshot.seenRecords;
|
|
136
|
+
subscription.snapshot = {
|
|
137
|
+
data: subscription.snapshot.data,
|
|
138
|
+
isMissingData: backup.isMissingData,
|
|
139
|
+
seenRecords: backup.seenRecords,
|
|
140
|
+
selector: backup.selector,
|
|
141
|
+
missingRequiredFields: backup.missingRequiredFields,
|
|
142
|
+
};
|
|
143
|
+
this._updateSubscriptionsMap(subscription, prevSeenRecords);
|
|
144
|
+
} else {
|
|
145
|
+
this._staleSubscriptions.add(subscription);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
updateSubscriptions(
|
|
152
|
+
source: RecordSource,
|
|
153
|
+
updatedRecordIDs: UpdatedRecords,
|
|
154
|
+
updatedOwners: Array<RequestDescriptor>,
|
|
155
|
+
) {
|
|
156
|
+
this._notifiedRevision++;
|
|
157
|
+
Object.keys(updatedRecordIDs).forEach(updatedRecordId => {
|
|
158
|
+
const subcriptionsForDataId = this._subscriptionsByDataId.get(
|
|
159
|
+
updatedRecordId,
|
|
160
|
+
);
|
|
161
|
+
if (subcriptionsForDataId == null) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
subcriptionsForDataId.forEach(subscription => {
|
|
165
|
+
if (subscription.notifiedRevision === this._notifiedRevision) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const owner = this._updateSubscription(source, subscription, false);
|
|
169
|
+
if (owner != null) {
|
|
170
|
+
updatedOwners.push(owner);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
this._staleSubscriptions.forEach(subscription => {
|
|
175
|
+
if (subscription.notifiedRevision === this._notifiedRevision) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const owner = this._updateSubscription(source, subscription, true);
|
|
179
|
+
if (owner != null) {
|
|
180
|
+
updatedOwners.push(owner);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
this._staleSubscriptions.clear();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Notifies the callback for the subscription if the data for the associated
|
|
188
|
+
* snapshot has changed.
|
|
189
|
+
* Additionally, updates the subscription snapshot with the latest snapshot,
|
|
190
|
+
* amarks it as not stale, and updates the subscription tracking for any
|
|
191
|
+
* any new ids observed in the latest data snapshot.
|
|
192
|
+
* Returns the owner (RequestDescriptor) if the subscription was affected by the
|
|
193
|
+
* latest update, or null if it was not affected.
|
|
194
|
+
*/
|
|
195
|
+
_updateSubscription(
|
|
196
|
+
source: RecordSource,
|
|
197
|
+
subscription: Subscription,
|
|
198
|
+
stale: boolean,
|
|
199
|
+
): ?RequestDescriptor {
|
|
200
|
+
const {backup, callback, snapshot} = subscription;
|
|
201
|
+
let nextSnapshot: Snapshot =
|
|
202
|
+
stale && backup != null
|
|
203
|
+
? backup
|
|
204
|
+
: RelayReader.read(source, snapshot.selector);
|
|
205
|
+
const nextData = recycleNodesInto(snapshot.data, nextSnapshot.data);
|
|
206
|
+
nextSnapshot = ({
|
|
207
|
+
data: nextData,
|
|
208
|
+
isMissingData: nextSnapshot.isMissingData,
|
|
209
|
+
seenRecords: nextSnapshot.seenRecords,
|
|
210
|
+
selector: nextSnapshot.selector,
|
|
211
|
+
missingRequiredFields: nextSnapshot.missingRequiredFields,
|
|
212
|
+
}: Snapshot);
|
|
213
|
+
if (__DEV__) {
|
|
214
|
+
deepFreeze(nextSnapshot);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const prevSeenRecords = subscription.snapshot.seenRecords;
|
|
218
|
+
subscription.snapshot = nextSnapshot;
|
|
219
|
+
subscription.notifiedRevision = this._notifiedRevision;
|
|
220
|
+
this._updateSubscriptionsMap(subscription, prevSeenRecords);
|
|
221
|
+
|
|
222
|
+
if (nextSnapshot.data !== snapshot.data) {
|
|
223
|
+
callback(nextSnapshot);
|
|
224
|
+
return snapshot.selector.owner;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Updates the Map that tracks subscriptions by id.
|
|
230
|
+
* Given an updated subscription and the records that where seen
|
|
231
|
+
* on the previous subscription snapshot, updates our tracking
|
|
232
|
+
* to track the subscription for the newly and no longer seen ids.
|
|
233
|
+
*/
|
|
234
|
+
_updateSubscriptionsMap(
|
|
235
|
+
subscription: Subscription,
|
|
236
|
+
prevSeenRecords: RecordMap,
|
|
237
|
+
) {
|
|
238
|
+
for (const dataId in prevSeenRecords) {
|
|
239
|
+
const subscriptionsForDataId = this._subscriptionsByDataId.get(dataId);
|
|
240
|
+
if (subscriptionsForDataId != null) {
|
|
241
|
+
subscriptionsForDataId.delete(subscription);
|
|
242
|
+
if (subscriptionsForDataId.size === 0) {
|
|
243
|
+
this._subscriptionsByDataId.delete(dataId);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
for (const dataId in subscription.snapshot.seenRecords) {
|
|
249
|
+
const subscriptionsForDataId = this._subscriptionsByDataId.get(dataId);
|
|
250
|
+
if (subscriptionsForDataId != null) {
|
|
251
|
+
subscriptionsForDataId.add(subscription);
|
|
252
|
+
} else {
|
|
253
|
+
this._subscriptionsByDataId.set(dataId, new Set([subscription]));
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
module.exports = RelayStoreSubscriptionsUsingMapByID;
|
|
@@ -17,14 +17,15 @@ import type {
|
|
|
17
17
|
INetwork,
|
|
18
18
|
PayloadData,
|
|
19
19
|
PayloadError,
|
|
20
|
+
ReactFlightServerTree,
|
|
20
21
|
UploadableMap,
|
|
21
22
|
} from '../network/RelayNetworkTypes';
|
|
22
23
|
import type RelayObservable from '../network/RelayObservable';
|
|
23
24
|
import type {
|
|
24
25
|
NormalizationLinkedField,
|
|
26
|
+
NormalizationRootNode,
|
|
25
27
|
NormalizationScalarField,
|
|
26
28
|
NormalizationSelectableNode,
|
|
27
|
-
NormalizationSplitOperation,
|
|
28
29
|
} from '../util/NormalizationNode';
|
|
29
30
|
import type {ReaderFragment} from '../util/ReaderNode';
|
|
30
31
|
import type {
|
|
@@ -83,6 +84,7 @@ export type RequestDescriptor = {|
|
|
|
83
84
|
+identifier: RequestIdentifier,
|
|
84
85
|
+node: ConcreteRequest,
|
|
85
86
|
+variables: Variables,
|
|
87
|
+
+cacheConfig: ?CacheConfig,
|
|
86
88
|
|};
|
|
87
89
|
|
|
88
90
|
/**
|
|
@@ -95,16 +97,25 @@ export type NormalizationSelector = {|
|
|
|
95
97
|
+variables: Variables,
|
|
96
98
|
|};
|
|
97
99
|
|
|
100
|
+
type MissingRequiredField = {|
|
|
101
|
+
path: string,
|
|
102
|
+
owner: string,
|
|
103
|
+
|};
|
|
104
|
+
|
|
105
|
+
export type MissingRequiredFields =
|
|
106
|
+
| {|action: 'THROW', field: MissingRequiredField|}
|
|
107
|
+
| {|action: 'LOG', fields: Array<MissingRequiredField>|};
|
|
108
|
+
|
|
98
109
|
/**
|
|
99
110
|
* A representation of a selector and its results at a particular point in time.
|
|
100
111
|
*/
|
|
101
|
-
export type
|
|
102
|
-
+data:
|
|
112
|
+
export type Snapshot = {|
|
|
113
|
+
+data: ?SelectorData,
|
|
103
114
|
+isMissingData: boolean,
|
|
104
115
|
+seenRecords: RecordMap,
|
|
105
116
|
+selector: SingularReaderSelector,
|
|
117
|
+
+missingRequiredFields: ?MissingRequiredFields,
|
|
106
118
|
|};
|
|
107
|
-
export type Snapshot = TypedSnapshot<?SelectorData>;
|
|
108
119
|
|
|
109
120
|
/**
|
|
110
121
|
* An operation selector describes a specific instance of a GraphQL operation
|
|
@@ -236,8 +247,6 @@ export interface Store {
|
|
|
236
247
|
|
|
237
248
|
/**
|
|
238
249
|
* Read the results of a selector from in-memory records in the store.
|
|
239
|
-
* Optionally takes an owner, corresponding to the operation that
|
|
240
|
-
* owns this selector (fragment).
|
|
241
250
|
*/
|
|
242
251
|
lookup(selector: SingularReaderSelector): Snapshot;
|
|
243
252
|
|
|
@@ -247,7 +256,7 @@ export interface Store {
|
|
|
247
256
|
* Optionally provide an OperationDescriptor indicating the source operation
|
|
248
257
|
* that was being processed to produce this run.
|
|
249
258
|
*
|
|
250
|
-
* This method should return an array of the affected fragment owners
|
|
259
|
+
* This method should return an array of the affected fragment owners.
|
|
251
260
|
*/
|
|
252
261
|
notify(
|
|
253
262
|
sourceOperation?: OperationDescriptor,
|
|
@@ -263,7 +272,7 @@ export interface Store {
|
|
|
263
272
|
|
|
264
273
|
/**
|
|
265
274
|
* Ensure that all the records necessary to fulfill the given selector are
|
|
266
|
-
* retained in
|
|
275
|
+
* retained in memory. The records will not be eligible for garbage collection
|
|
267
276
|
* until the returned reference is disposed.
|
|
268
277
|
*/
|
|
269
278
|
retain(operation: OperationDescriptor): Disposable;
|
|
@@ -324,6 +333,40 @@ export interface Store {
|
|
|
324
333
|
): Disposable;
|
|
325
334
|
}
|
|
326
335
|
|
|
336
|
+
export interface StoreSubscriptions {
|
|
337
|
+
/**
|
|
338
|
+
* Subscribe to changes to the results of a selector. The callback is called
|
|
339
|
+
* when `updateSubscriptions()` is called *and* records have been published that affect the
|
|
340
|
+
* selector results relative to the last update.
|
|
341
|
+
*/
|
|
342
|
+
subscribe(
|
|
343
|
+
snapshot: Snapshot,
|
|
344
|
+
callback: (snapshot: Snapshot) => void,
|
|
345
|
+
): Disposable;
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Record a backup/snapshot of the current state of the subscriptions.
|
|
349
|
+
* This state can be restored with restore().
|
|
350
|
+
*/
|
|
351
|
+
snapshotSubscriptions(source: RecordSource): void;
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Reset the state of the subscriptions to the point that snapshot() was last called.
|
|
355
|
+
*/
|
|
356
|
+
restoreSubscriptions(): void;
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Notifies each subscription if the snapshot for the subscription selector has changed.
|
|
360
|
+
* Mutates the updatedOwners array with any owners (RequestDescriptors) associated
|
|
361
|
+
* with the subscriptions that were notifed; i.e. the owners affected by the changes.
|
|
362
|
+
*/
|
|
363
|
+
updateSubscriptions(
|
|
364
|
+
source: RecordSource,
|
|
365
|
+
updatedRecordIDs: UpdatedRecords,
|
|
366
|
+
updatedOwners: Array<RequestDescriptor>,
|
|
367
|
+
): void;
|
|
368
|
+
}
|
|
369
|
+
|
|
327
370
|
/**
|
|
328
371
|
* A type that accepts a callback and schedules it to run at some future time.
|
|
329
372
|
* By convention, implementations should not execute the callback immediately.
|
|
@@ -422,32 +465,32 @@ export type LogEvent =
|
|
|
422
465
|
+profilerContext: mixed,
|
|
423
466
|
|}
|
|
424
467
|
| {|
|
|
425
|
-
+name: '
|
|
468
|
+
+name: 'network.info',
|
|
426
469
|
+transactionID: number,
|
|
427
470
|
+info: mixed,
|
|
428
471
|
|}
|
|
429
472
|
| {|
|
|
430
|
-
+name: '
|
|
473
|
+
+name: 'network.start',
|
|
431
474
|
+transactionID: number,
|
|
432
475
|
+params: RequestParameters,
|
|
433
476
|
+variables: Variables,
|
|
434
477
|
|}
|
|
435
478
|
| {|
|
|
436
|
-
+name: '
|
|
479
|
+
+name: 'network.next',
|
|
437
480
|
+transactionID: number,
|
|
438
481
|
+response: GraphQLResponse,
|
|
439
482
|
|}
|
|
440
483
|
| {|
|
|
441
|
-
+name: '
|
|
484
|
+
+name: 'network.error',
|
|
442
485
|
+transactionID: number,
|
|
443
486
|
+error: Error,
|
|
444
487
|
|}
|
|
445
488
|
| {|
|
|
446
|
-
+name: '
|
|
489
|
+
+name: 'network.complete',
|
|
447
490
|
+transactionID: number,
|
|
448
491
|
|}
|
|
449
492
|
| {|
|
|
450
|
-
+name: '
|
|
493
|
+
+name: 'network.unsubscribe',
|
|
451
494
|
+transactionID: number,
|
|
452
495
|
|}
|
|
453
496
|
| {|
|
|
@@ -472,7 +515,13 @@ export type LogEvent =
|
|
|
472
515
|
+name: 'store.notify.complete',
|
|
473
516
|
+updatedRecordIDs: UpdatedRecords,
|
|
474
517
|
+invalidatedRecordIDs: Set<DataID>,
|
|
518
|
+
|}
|
|
519
|
+
| {|
|
|
520
|
+
+name: 'entrypoint.root.consume',
|
|
521
|
+
+profilerContext: mixed,
|
|
522
|
+
+rootModuleID: string,
|
|
475
523
|
|};
|
|
524
|
+
|
|
476
525
|
export type LogFunction = LogEvent => void;
|
|
477
526
|
export type LogRequestInfoFunction = mixed => void;
|
|
478
527
|
|
|
@@ -563,14 +612,12 @@ export interface IEnvironment {
|
|
|
563
612
|
/**
|
|
564
613
|
* EXPERIMENTAL
|
|
565
614
|
* Returns the default render policy to use when rendering a query
|
|
566
|
-
* that uses Relay Hooks
|
|
615
|
+
* that uses Relay Hooks.
|
|
567
616
|
*/
|
|
568
617
|
UNSTABLE_getDefaultRenderPolicy(): RenderPolicy;
|
|
569
618
|
|
|
570
619
|
/**
|
|
571
620
|
* Read the results of a selector from in-memory records in the store.
|
|
572
|
-
* Optionally takes an owner, corresponding to the operation that
|
|
573
|
-
* owns this selector (fragment).
|
|
574
621
|
*/
|
|
575
622
|
lookup(selector: SingularReaderSelector): Snapshot;
|
|
576
623
|
|
|
@@ -587,7 +634,6 @@ export interface IEnvironment {
|
|
|
587
634
|
*/
|
|
588
635
|
execute(config: {|
|
|
589
636
|
operation: OperationDescriptor,
|
|
590
|
-
cacheConfig?: ?CacheConfig,
|
|
591
637
|
updater?: ?SelectorStoreUpdater,
|
|
592
638
|
|}): RelayObservable<GraphQLResponse>;
|
|
593
639
|
|
|
@@ -602,7 +648,6 @@ export interface IEnvironment {
|
|
|
602
648
|
* environment.executeMutation({...}).subscribe({...}).
|
|
603
649
|
*/
|
|
604
650
|
executeMutation({|
|
|
605
|
-
cacheConfig?: ?CacheConfig,
|
|
606
651
|
operation: OperationDescriptor,
|
|
607
652
|
optimisticUpdater?: ?SelectorStoreUpdater,
|
|
608
653
|
optimisticResponse?: ?Object,
|
|
@@ -639,18 +684,13 @@ export interface IEnvironment {
|
|
|
639
684
|
* whether we need to set up certain caches and timeout's.
|
|
640
685
|
*/
|
|
641
686
|
isServer(): boolean;
|
|
642
|
-
}
|
|
643
687
|
|
|
644
|
-
/**
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
__fragments: {[fragmentName: string]: Variables, ...},
|
|
651
|
-
__fragmentOwner: RequestDescriptor,
|
|
652
|
-
...
|
|
653
|
-
};
|
|
688
|
+
/**
|
|
689
|
+
* Called by Relay when it encounters a missing field that has been annotated
|
|
690
|
+
* with `@required(action: LOG)`.
|
|
691
|
+
*/
|
|
692
|
+
requiredFieldLogger: RequiredFieldLogger;
|
|
693
|
+
}
|
|
654
694
|
|
|
655
695
|
/**
|
|
656
696
|
* The partial shape of an object with a '...Fragment @module(name: "...")'
|
|
@@ -699,7 +739,9 @@ export type HandleFieldPayload = {|
|
|
|
699
739
|
|
|
700
740
|
/**
|
|
701
741
|
* A payload that represents data necessary to process the results of an object
|
|
702
|
-
* with a `@module` fragment spread:
|
|
742
|
+
* with a `@module` fragment spread, or a Flight field's:
|
|
743
|
+
*
|
|
744
|
+
* ## @module Fragment Spread
|
|
703
745
|
* - data: The GraphQL response value for the @match field.
|
|
704
746
|
* - dataID: The ID of the store object linked to by the @match field.
|
|
705
747
|
* - operationReference: A reference to a generated module containing the
|
|
@@ -710,6 +752,21 @@ export type HandleFieldPayload = {|
|
|
|
710
752
|
* The dataID, variables, and fragmentName can be used to create a Selector
|
|
711
753
|
* which can in turn be used to normalize and publish the data. The dataID and
|
|
712
754
|
* typeName can also be used to construct a root record for normalization.
|
|
755
|
+
*
|
|
756
|
+
* ## Flight fields
|
|
757
|
+
* In Flight, data for additional components rendered by the requested server
|
|
758
|
+
* component are included in the response returned by a Flight compliant server.
|
|
759
|
+
*
|
|
760
|
+
* - data: Data used by additional components rendered by the server component
|
|
761
|
+
* being requested.
|
|
762
|
+
* - dataID: For Flight fields, this should always be ROOT_ID. This is because
|
|
763
|
+
* the query data isn't relative to the parent record–it's root data.
|
|
764
|
+
* - operationReference: The query's module that will be later used by an
|
|
765
|
+
* operation loader.
|
|
766
|
+
* - variables: The query's variables.
|
|
767
|
+
* - typeName: For Flight fields, this should always be ROOT_TYPE. This is
|
|
768
|
+
* because the query data isn't relative to the parent record–it's
|
|
769
|
+
* root data.
|
|
713
770
|
*/
|
|
714
771
|
export type ModuleImportPayload = {|
|
|
715
772
|
+data: PayloadData,
|
|
@@ -744,22 +801,22 @@ export type StreamPlaceholder = {|
|
|
|
744
801
|
export type IncrementalDataPlaceholder = DeferPlaceholder | StreamPlaceholder;
|
|
745
802
|
|
|
746
803
|
/**
|
|
747
|
-
* A user-supplied object to load a generated operation (SplitOperation
|
|
748
|
-
* by a module reference. The exact format of a module
|
|
749
|
-
* the application, but it must be a plain JavaScript value
|
|
750
|
-
* or object/array of same).
|
|
804
|
+
* A user-supplied object to load a generated operation (SplitOperation or
|
|
805
|
+
* ConcreteRequest) AST by a module reference. The exact format of a module
|
|
806
|
+
* reference is left to the application, but it must be a plain JavaScript value
|
|
807
|
+
* (string, number, or object/array of same).
|
|
751
808
|
*/
|
|
752
809
|
export type OperationLoader = {|
|
|
753
810
|
/**
|
|
754
811
|
* Synchronously load an operation, returning either the node or null if it
|
|
755
812
|
* cannot be resolved synchronously.
|
|
756
813
|
*/
|
|
757
|
-
get(reference: mixed): ?
|
|
814
|
+
get(reference: mixed): ?NormalizationRootNode,
|
|
758
815
|
|
|
759
816
|
/**
|
|
760
817
|
* Asynchronously load an operation.
|
|
761
818
|
*/
|
|
762
|
-
load(reference: mixed): Promise<?
|
|
819
|
+
load(reference: mixed): Promise<?NormalizationRootNode>,
|
|
763
820
|
|};
|
|
764
821
|
|
|
765
822
|
/**
|
|
@@ -837,6 +894,23 @@ export type MissingFieldHandler =
|
|
|
837
894
|
) => ?Array<?DataID>,
|
|
838
895
|
|};
|
|
839
896
|
|
|
897
|
+
/**
|
|
898
|
+
* A handler for events related to @required fields. Currently reports missing
|
|
899
|
+
* fields with either `action: LOG` or `action: THROW`.
|
|
900
|
+
*/
|
|
901
|
+
export type RequiredFieldLogger = (
|
|
902
|
+
| {|
|
|
903
|
+
+kind: 'missing_field.log',
|
|
904
|
+
+owner: string,
|
|
905
|
+
+fieldPath: string,
|
|
906
|
+
|}
|
|
907
|
+
| {|
|
|
908
|
+
+kind: 'missing_field.throw',
|
|
909
|
+
+owner: string,
|
|
910
|
+
+fieldPath: string,
|
|
911
|
+
|},
|
|
912
|
+
) => void;
|
|
913
|
+
|
|
840
914
|
/**
|
|
841
915
|
* The results of normalizing a query.
|
|
842
916
|
*/
|
|
@@ -897,3 +971,22 @@ export interface PublishQueue {
|
|
|
897
971
|
*/
|
|
898
972
|
run(sourceOperation?: OperationDescriptor): $ReadOnlyArray<RequestDescriptor>;
|
|
899
973
|
}
|
|
974
|
+
|
|
975
|
+
/**
|
|
976
|
+
* ReactFlightDOMRelayClient processes a ReactFlightServerTree into a
|
|
977
|
+
* ReactFlightClientResponse object. readRoot() can suspend.
|
|
978
|
+
*/
|
|
979
|
+
export type ReactFlightClientResponse = {readRoot: () => mixed, ...};
|
|
980
|
+
|
|
981
|
+
export type ReactFlightReachableQuery = {|
|
|
982
|
+
+module: mixed,
|
|
983
|
+
+variables: Variables,
|
|
984
|
+
|};
|
|
985
|
+
|
|
986
|
+
/**
|
|
987
|
+
* A user-supplied function that takes a ReactFlightServerTree, and deserializes
|
|
988
|
+
* it into a ReactFlightClientResponse object.
|
|
989
|
+
*/
|
|
990
|
+
export type ReactFlightPayloadDeserializer = (
|
|
991
|
+
tree: ReactFlightServerTree,
|
|
992
|
+
) => ReactFlightClientResponse;
|
|
@@ -31,6 +31,9 @@ let firstReact: ?React;
|
|
|
31
31
|
function createRelayContext(react: React): React$Context<RelayContext | null> {
|
|
32
32
|
if (!relayContext) {
|
|
33
33
|
relayContext = react.createContext(null);
|
|
34
|
+
if (__DEV__) {
|
|
35
|
+
relayContext.displayName = 'RelayContext';
|
|
36
|
+
}
|
|
34
37
|
firstReact = react;
|
|
35
38
|
}
|
|
36
39
|
invariant(
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
*/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
import type {RequiredFieldLogger} from './RelayStoreTypes';
|
|
14
|
+
|
|
15
|
+
const defaultRequiredFieldLogger: RequiredFieldLogger = event => {
|
|
16
|
+
if (__DEV__ && event.kind === 'missing_field.log') {
|
|
17
|
+
throw new Error(
|
|
18
|
+
'Relay Environment Configuration Error (dev only): `@required(action: LOG)` requires that the Relay Environment be configured with a `requiredFieldLogger`.',
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
module.exports = defaultRequiredFieldLogger;
|
|
@@ -60,7 +60,11 @@ function requestSubscription<TSubscriptionPayload>(
|
|
|
60
60
|
variables,
|
|
61
61
|
cacheConfig,
|
|
62
62
|
} = config;
|
|
63
|
-
const operation = createOperationDescriptor(
|
|
63
|
+
const operation = createOperationDescriptor(
|
|
64
|
+
subscription,
|
|
65
|
+
variables,
|
|
66
|
+
cacheConfig,
|
|
67
|
+
);
|
|
64
68
|
|
|
65
69
|
warning(
|
|
66
70
|
!(config.updater && configs),
|
|
@@ -80,7 +84,6 @@ function requestSubscription<TSubscriptionPayload>(
|
|
|
80
84
|
.execute({
|
|
81
85
|
operation,
|
|
82
86
|
updater,
|
|
83
|
-
cacheConfig,
|
|
84
87
|
})
|
|
85
88
|
.map(() => {
|
|
86
89
|
const data = environment.lookup(operation.fragment).data;
|