relay-runtime 8.0.0 → 10.0.1
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 +41 -0
- package/handlers/connection/ConnectionHandler.js.flow +549 -0
- package/handlers/connection/ConnectionInterface.js.flow +92 -0
- package/handlers/connection/MutationHandlers.js.flow +88 -0
- package/index.js +1 -1
- package/index.js.flow +320 -0
- package/lib/handlers/RelayDefaultHandlerProvider.js +13 -2
- package/lib/handlers/connection/{RelayConnectionHandler.js → ConnectionHandler.js} +33 -35
- package/lib/handlers/connection/{RelayConnectionInterface.js → ConnectionInterface.js} +2 -2
- package/lib/handlers/connection/MutationHandlers.js +86 -0
- package/lib/index.js +15 -19
- package/lib/mutations/RelayDeclarativeMutationConfig.js +29 -52
- package/lib/mutations/RelayRecordProxy.js +1 -3
- package/lib/mutations/RelayRecordSourceMutator.js +2 -9
- package/lib/mutations/RelayRecordSourceProxy.js +2 -4
- package/lib/mutations/RelayRecordSourceSelectorProxy.js +1 -13
- package/lib/mutations/commitMutation.js +13 -3
- package/lib/mutations/validateMutation.js +16 -9
- package/lib/network/RelayObservable.js +9 -9
- package/lib/network/RelayQueryResponseCache.js +8 -6
- package/lib/query/PreloadableQueryRegistry.js +70 -0
- package/lib/query/fetchQueryInternal.js +31 -23
- package/lib/store/DataChecker.js +122 -110
- package/lib/store/RelayConcreteVariables.js +6 -2
- package/lib/store/RelayModernEnvironment.js +121 -67
- package/lib/store/RelayModernFragmentSpecResolver.js +12 -16
- package/lib/store/RelayModernQueryExecutor.js +389 -314
- package/lib/store/RelayModernRecord.js +14 -9
- package/lib/store/RelayModernSelector.js +7 -3
- package/lib/store/RelayModernStore.js +289 -484
- package/lib/store/RelayOperationTracker.js +35 -78
- package/lib/store/RelayOptimisticRecordSource.js +7 -5
- package/lib/store/RelayPublishQueue.js +6 -33
- package/lib/store/RelayReader.js +113 -45
- package/lib/store/RelayRecordSource.js +2 -9
- package/lib/store/RelayRecordSourceMapImpl.js +13 -18
- package/lib/store/RelayReferenceMarker.js +40 -60
- package/lib/store/RelayResponseNormalizer.js +158 -193
- package/lib/store/RelayStoreUtils.js +1 -0
- package/lib/store/StoreInspector.js +8 -8
- package/lib/store/TypeID.js +28 -0
- package/lib/store/cloneRelayScalarHandleSourceField.js +44 -0
- package/lib/store/normalizeRelayPayload.js +6 -2
- package/lib/store/readInlineData.js +1 -1
- package/lib/subscription/requestSubscription.js +5 -3
- package/lib/util/RelayConcreteNode.js +9 -6
- package/lib/util/RelayError.js +39 -9
- package/lib/util/RelayFeatureFlags.js +2 -5
- package/lib/util/RelayReplaySubject.js +3 -3
- package/lib/util/createPayloadFor3DField.js +7 -2
- package/lib/util/getRequestIdentifier.js +2 -2
- package/lib/util/recycleNodesInto.js +2 -6
- package/mutations/RelayDeclarativeMutationConfig.js.flow +380 -0
- package/mutations/RelayRecordProxy.js.flow +165 -0
- package/mutations/RelayRecordSourceMutator.js.flow +238 -0
- package/mutations/RelayRecordSourceProxy.js.flow +164 -0
- package/mutations/RelayRecordSourceSelectorProxy.js.flow +119 -0
- package/mutations/applyOptimisticMutation.js.flow +76 -0
- package/mutations/commitLocalUpdate.js.flow +24 -0
- package/mutations/commitMutation.js.flow +182 -0
- package/mutations/validateMutation.js.flow +213 -0
- package/network/ConvertToExecuteFunction.js.flow +49 -0
- package/network/RelayNetwork.js.flow +84 -0
- package/network/RelayNetworkTypes.js.flow +123 -0
- package/network/RelayObservable.js.flow +634 -0
- package/network/RelayQueryResponseCache.js.flow +111 -0
- package/package.json +1 -1
- package/query/GraphQLTag.js.flow +166 -0
- package/query/PreloadableQueryRegistry.js.flow +65 -0
- package/query/fetchQuery.js.flow +47 -0
- package/query/fetchQueryInternal.js.flow +348 -0
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/ClientID.js.flow +43 -0
- package/store/DataChecker.js.flow +502 -0
- package/store/RelayConcreteVariables.js.flow +96 -0
- package/store/RelayModernEnvironment.js.flow +551 -0
- package/store/RelayModernFragmentSpecResolver.js.flow +426 -0
- package/store/RelayModernOperationDescriptor.js.flow +88 -0
- package/store/RelayModernQueryExecutor.js.flow +1321 -0
- package/store/RelayModernRecord.js.flow +403 -0
- package/store/RelayModernSelector.js.flow +455 -0
- package/store/RelayModernStore.js.flow +842 -0
- package/store/RelayOperationTracker.js.flow +164 -0
- package/store/RelayOptimisticRecordSource.js.flow +119 -0
- package/store/RelayPublishQueue.js.flow +401 -0
- package/store/RelayReader.js.flow +473 -0
- package/store/RelayRecordSource.js.flow +29 -0
- package/store/RelayRecordSourceMapImpl.js.flow +87 -0
- package/store/RelayRecordState.js.flow +37 -0
- package/store/RelayReferenceMarker.js.flow +257 -0
- package/store/RelayResponseNormalizer.js.flow +680 -0
- package/store/RelayStoreTypes.js.flow +899 -0
- package/store/RelayStoreUtils.js.flow +219 -0
- package/store/StoreInspector.js.flow +171 -0
- package/store/TypeID.js.flow +28 -0
- package/store/ViewerPattern.js.flow +26 -0
- package/store/cloneRelayHandleSourceField.js.flow +66 -0
- package/store/cloneRelayScalarHandleSourceField.js.flow +62 -0
- package/store/createFragmentSpecResolver.js.flow +55 -0
- package/store/createRelayContext.js.flow +44 -0
- package/store/defaultGetDataID.js.flow +27 -0
- package/store/hasOverlappingIDs.js.flow +34 -0
- package/store/isRelayModernEnvironment.js.flow +27 -0
- package/store/normalizeRelayPayload.js.flow +51 -0
- package/store/readInlineData.js.flow +75 -0
- package/subscription/requestSubscription.js.flow +100 -0
- package/util/JSResourceTypes.flow.js.flow +20 -0
- package/util/NormalizationNode.js.flow +198 -0
- package/util/ReaderNode.js.flow +208 -0
- package/util/RelayConcreteNode.js.flow +93 -0
- package/util/RelayDefaultHandleKey.js.flow +17 -0
- package/util/RelayError.js.flow +62 -0
- package/util/RelayFeatureFlags.js.flow +30 -0
- package/util/RelayProfiler.js.flow +284 -0
- package/util/RelayReplaySubject.js.flow +135 -0
- package/util/RelayRuntimeTypes.js.flow +72 -0
- package/util/createPayloadFor3DField.js.flow +43 -0
- package/util/deepFreeze.js.flow +36 -0
- package/util/generateID.js.flow +21 -0
- package/util/getFragmentIdentifier.js.flow +52 -0
- package/util/getRelayHandleKey.js.flow +41 -0
- package/util/getRequestIdentifier.js.flow +42 -0
- package/util/isPromise.js.flow +21 -0
- package/util/isScalarAndEqual.js.flow +26 -0
- package/util/recycleNodesInto.js.flow +76 -0
- package/util/resolveImmediate.js.flow +30 -0
- package/util/stableCopy.js.flow +35 -0
- package/lib/handlers/RelayDefaultMissingFieldHandlers.js +0 -26
- package/lib/handlers/getRelayDefaultMissingFieldHandlers.js +0 -36
- package/lib/query/RelayModernGraphQLTag.js +0 -104
- package/lib/store/RelayConnection.js +0 -37
- package/lib/store/RelayConnectionResolver.js +0 -178
- package/lib/store/RelayRecordSourceObjectImpl.js +0 -79
- package/lib/util/getFragmentSpecIdentifier.js +0 -27
|
@@ -0,0 +1,93 @@
|
|
|
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
|
+
import type {
|
|
16
|
+
NormalizationOperation,
|
|
17
|
+
NormalizationSplitOperation,
|
|
18
|
+
} from './NormalizationNode';
|
|
19
|
+
import type {ReaderFragment, ReaderInlineDataFragment} from './ReaderNode';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Represents a common GraphQL request that can be executed, an `operation`
|
|
23
|
+
* containing information to normalize the results, and a `fragment` derived
|
|
24
|
+
* from that operation to read the response data (masking data from child
|
|
25
|
+
* fragments).
|
|
26
|
+
*/
|
|
27
|
+
export type ConcreteRequest = {|
|
|
28
|
+
+kind: 'Request',
|
|
29
|
+
+fragment: ReaderFragment,
|
|
30
|
+
+operation: NormalizationOperation,
|
|
31
|
+
+params: RequestParameters,
|
|
32
|
+
|};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Contains the parameters required for executing a GraphQL request.
|
|
36
|
+
* The operation can either be provided as a persisted `id` or `text`. If given
|
|
37
|
+
* in `text` format, a `cacheID` as a hash of the text should be set to be used
|
|
38
|
+
* for local caching.
|
|
39
|
+
*/
|
|
40
|
+
export type RequestParameters =
|
|
41
|
+
| {|
|
|
42
|
+
+id: string,
|
|
43
|
+
+text: null,
|
|
44
|
+
// common fields
|
|
45
|
+
+name: string,
|
|
46
|
+
+operationKind: 'mutation' | 'query' | 'subscription',
|
|
47
|
+
+metadata: {[key: string]: mixed, ...},
|
|
48
|
+
|}
|
|
49
|
+
| {|
|
|
50
|
+
+cacheID: string,
|
|
51
|
+
+id: null,
|
|
52
|
+
+text: string,
|
|
53
|
+
// common fields
|
|
54
|
+
+name: string,
|
|
55
|
+
+operationKind: 'mutation' | 'query' | 'subscription',
|
|
56
|
+
+metadata: {[key: string]: mixed, ...},
|
|
57
|
+
|};
|
|
58
|
+
|
|
59
|
+
export type GeneratedNode =
|
|
60
|
+
| ConcreteRequest
|
|
61
|
+
| ReaderFragment
|
|
62
|
+
| ReaderInlineDataFragment
|
|
63
|
+
| NormalizationSplitOperation;
|
|
64
|
+
|
|
65
|
+
const RelayConcreteNode = {
|
|
66
|
+
CONDITION: 'Condition',
|
|
67
|
+
CLIENT_EXTENSION: 'ClientExtension',
|
|
68
|
+
DEFER: 'Defer',
|
|
69
|
+
CONNECTION: 'Connection',
|
|
70
|
+
FRAGMENT: 'Fragment',
|
|
71
|
+
FRAGMENT_SPREAD: 'FragmentSpread',
|
|
72
|
+
INLINE_DATA_FRAGMENT_SPREAD: 'InlineDataFragmentSpread',
|
|
73
|
+
INLINE_DATA_FRAGMENT: 'InlineDataFragment',
|
|
74
|
+
INLINE_FRAGMENT: 'InlineFragment',
|
|
75
|
+
LINKED_FIELD: 'LinkedField',
|
|
76
|
+
LINKED_HANDLE: 'LinkedHandle',
|
|
77
|
+
LITERAL: 'Literal',
|
|
78
|
+
LIST_VALUE: 'ListValue',
|
|
79
|
+
LOCAL_ARGUMENT: 'LocalArgument',
|
|
80
|
+
MODULE_IMPORT: 'ModuleImport',
|
|
81
|
+
OBJECT_VALUE: 'ObjectValue',
|
|
82
|
+
OPERATION: 'Operation',
|
|
83
|
+
REQUEST: 'Request',
|
|
84
|
+
ROOT_ARGUMENT: 'RootArgument',
|
|
85
|
+
SCALAR_FIELD: 'ScalarField',
|
|
86
|
+
SCALAR_HANDLE: 'ScalarHandle',
|
|
87
|
+
SPLIT_OPERATION: 'SplitOperation',
|
|
88
|
+
STREAM: 'Stream',
|
|
89
|
+
TYPE_DISCRIMINATOR: 'TypeDiscriminator',
|
|
90
|
+
VARIABLE: 'Variable',
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
module.exports = RelayConcreteNode;
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
*/
|
|
10
|
+
|
|
11
|
+
// flowlint ambiguous-object-type:error
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
DEFAULT_HANDLE_KEY: '',
|
|
17
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// flowlint ambiguous-object-type:error
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @private
|
|
17
|
+
*/
|
|
18
|
+
function createError(
|
|
19
|
+
type: 'fatal' | 'error' | 'warn' | 'info',
|
|
20
|
+
name: string,
|
|
21
|
+
messageFormat: string,
|
|
22
|
+
...messageParams: Array<string | number | boolean>
|
|
23
|
+
): Error {
|
|
24
|
+
let index = 0;
|
|
25
|
+
const message = messageFormat.replace(/%s/g, () =>
|
|
26
|
+
String(messageParams[index++]),
|
|
27
|
+
);
|
|
28
|
+
const err = new Error(message);
|
|
29
|
+
const error = Object.assign((err: any), {
|
|
30
|
+
name,
|
|
31
|
+
messageFormat,
|
|
32
|
+
messageParams,
|
|
33
|
+
type,
|
|
34
|
+
taalOpcodes: [2, 2], // skip frame (code=2) twice
|
|
35
|
+
});
|
|
36
|
+
// In V8, Error objects keep the closure scope chain alive until the
|
|
37
|
+
// err.stack property is accessed.
|
|
38
|
+
if (error.stack === undefined) {
|
|
39
|
+
// IE sets the stack only if error is thrown
|
|
40
|
+
try {
|
|
41
|
+
throw error;
|
|
42
|
+
} catch {}
|
|
43
|
+
}
|
|
44
|
+
return error;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = {
|
|
48
|
+
create(
|
|
49
|
+
name: string,
|
|
50
|
+
messageFormat: string,
|
|
51
|
+
...messageParams: Array<string | number | boolean>
|
|
52
|
+
): Error {
|
|
53
|
+
return createError('error', name, messageFormat, ...messageParams);
|
|
54
|
+
},
|
|
55
|
+
createWarning(
|
|
56
|
+
name: string,
|
|
57
|
+
messageFormat: string,
|
|
58
|
+
...messageParams: Array<string | number | boolean>
|
|
59
|
+
): Error {
|
|
60
|
+
return createError('warn', name, messageFormat, ...messageParams);
|
|
61
|
+
},
|
|
62
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
*/
|
|
10
|
+
|
|
11
|
+
// flowlint ambiguous-object-type:error
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
type FeatureFlags = {|
|
|
16
|
+
ENABLE_VARIABLE_CONNECTION_KEY: boolean,
|
|
17
|
+
ENABLE_PARTIAL_RENDERING_DEFAULT: boolean,
|
|
18
|
+
ENABLE_RELAY_CONTAINERS_SUSPENSE: boolean,
|
|
19
|
+
ENABLE_PRECISE_TYPE_REFINEMENT: boolean,
|
|
20
|
+
|};
|
|
21
|
+
|
|
22
|
+
const RelayFeatureFlags: FeatureFlags = {
|
|
23
|
+
// T45504512: new connection model
|
|
24
|
+
ENABLE_VARIABLE_CONNECTION_KEY: false,
|
|
25
|
+
ENABLE_PARTIAL_RENDERING_DEFAULT: false,
|
|
26
|
+
ENABLE_RELAY_CONTAINERS_SUSPENSE: false,
|
|
27
|
+
ENABLE_PRECISE_TYPE_REFINEMENT: false,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
module.exports = RelayFeatureFlags;
|
|
@@ -0,0 +1,284 @@
|
|
|
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
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// flowlint ambiguous-object-type:error
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
type Handler = (name: string, callback: () => void) => void;
|
|
16
|
+
type ProfileHandler = (name: string, state?: any) => (error?: Error) => void;
|
|
17
|
+
|
|
18
|
+
function emptyFunction() {}
|
|
19
|
+
|
|
20
|
+
const aggregateHandlersByName: {[name: string]: Array<Handler>, ...} = {
|
|
21
|
+
'*': [],
|
|
22
|
+
};
|
|
23
|
+
const profileHandlersByName: {[name: string]: Array<ProfileHandler>, ...} = {
|
|
24
|
+
'*': [],
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const NOT_INVOKED = {};
|
|
28
|
+
const defaultProfiler = {stop: emptyFunction};
|
|
29
|
+
const shouldInstrument = name => {
|
|
30
|
+
if (__DEV__) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return name.charAt(0) !== '@';
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @public
|
|
38
|
+
*
|
|
39
|
+
* Instruments methods to allow profiling various parts of Relay. Profiling code
|
|
40
|
+
* in Relay consists of three steps:
|
|
41
|
+
*
|
|
42
|
+
* - Instrument the function to be profiled.
|
|
43
|
+
* - Attach handlers to the instrumented function.
|
|
44
|
+
* - Run the code which triggers the handlers.
|
|
45
|
+
*
|
|
46
|
+
* Handlers attached to instrumented methods are called with an instrumentation
|
|
47
|
+
* name and a callback that must be synchronously executed:
|
|
48
|
+
*
|
|
49
|
+
* instrumentedMethod.attachHandler(function(name, callback) {
|
|
50
|
+
* const start = performance.now();
|
|
51
|
+
* callback();
|
|
52
|
+
* console.log('Duration', performance.now() - start);
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* Handlers for profiles are callbacks that return a stop method:
|
|
56
|
+
*
|
|
57
|
+
* RelayProfiler.attachProfileHandler('profileName', (name, state) => {
|
|
58
|
+
* const start = performance.now();
|
|
59
|
+
* return function stop(name, state) {
|
|
60
|
+
* console.log(`Duration (${name})`, performance.now() - start);
|
|
61
|
+
* }
|
|
62
|
+
* });
|
|
63
|
+
*
|
|
64
|
+
* In order to reduce the impact on performance in production, instrumented
|
|
65
|
+
* methods and profilers with names that begin with `@` will only be measured
|
|
66
|
+
* if `__DEV__` is true. This should be used for very hot functions.
|
|
67
|
+
*/
|
|
68
|
+
const RelayProfiler = {
|
|
69
|
+
/**
|
|
70
|
+
* Instruments methods on a class or object. This re-assigns the method in
|
|
71
|
+
* order to preserve function names in stack traces (which are detected by
|
|
72
|
+
* modern debuggers via heuristics). Example usage:
|
|
73
|
+
*
|
|
74
|
+
* const RelayStore = { primeCache: function() {...} };
|
|
75
|
+
* RelayProfiler.instrumentMethods(RelayStore, {
|
|
76
|
+
* primeCache: 'RelayStore.primeCache'
|
|
77
|
+
* });
|
|
78
|
+
*
|
|
79
|
+
* RelayStore.primeCache.attachHandler(...);
|
|
80
|
+
*
|
|
81
|
+
* As a result, the methods will be replaced by wrappers that provide the
|
|
82
|
+
* `attachHandler` and `detachHandler` methods.
|
|
83
|
+
*/
|
|
84
|
+
instrumentMethods(
|
|
85
|
+
object: Function | Object,
|
|
86
|
+
names: {[key: string]: string, ...},
|
|
87
|
+
): void {
|
|
88
|
+
for (const key in names) {
|
|
89
|
+
if (names.hasOwnProperty(key)) {
|
|
90
|
+
if (typeof object[key] === 'function') {
|
|
91
|
+
object[key] = RelayProfiler.instrument(names[key], object[key]);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Wraps the supplied function with one that provides the `attachHandler` and
|
|
99
|
+
* `detachHandler` methods. Example usage:
|
|
100
|
+
*
|
|
101
|
+
* const printRelayQuery =
|
|
102
|
+
* RelayProfiler.instrument('printRelayQuery', printRelayQuery);
|
|
103
|
+
*
|
|
104
|
+
* printRelayQuery.attachHandler(...);
|
|
105
|
+
*
|
|
106
|
+
* NOTE: The instrumentation assumes that no handlers are attached or detached
|
|
107
|
+
* in the course of executing another handler.
|
|
108
|
+
*/
|
|
109
|
+
instrument<T: Function>(name: string, originalFunction: T): T {
|
|
110
|
+
if (!shouldInstrument(name)) {
|
|
111
|
+
originalFunction.attachHandler = emptyFunction;
|
|
112
|
+
originalFunction.detachHandler = emptyFunction;
|
|
113
|
+
return originalFunction;
|
|
114
|
+
}
|
|
115
|
+
if (!aggregateHandlersByName.hasOwnProperty(name)) {
|
|
116
|
+
aggregateHandlersByName[name] = [];
|
|
117
|
+
}
|
|
118
|
+
const catchallHandlers = aggregateHandlersByName['*'];
|
|
119
|
+
const aggregateHandlers = aggregateHandlersByName[name];
|
|
120
|
+
const handlers: Array<Handler> = [];
|
|
121
|
+
const contexts: Array<[number, number, number, any, any, any]> = [];
|
|
122
|
+
const invokeHandlers = function() {
|
|
123
|
+
const context = contexts[contexts.length - 1];
|
|
124
|
+
if (context[0]) {
|
|
125
|
+
context[0]--;
|
|
126
|
+
catchallHandlers[context[0]](name, invokeHandlers);
|
|
127
|
+
} else if (context[1]) {
|
|
128
|
+
context[1]--;
|
|
129
|
+
aggregateHandlers[context[1]](name, invokeHandlers);
|
|
130
|
+
} else if (context[2]) {
|
|
131
|
+
context[2]--;
|
|
132
|
+
handlers[context[2]](name, invokeHandlers);
|
|
133
|
+
} else {
|
|
134
|
+
context[5] = originalFunction.apply(context[3], context[4]);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const instrumentedCallback = function() {
|
|
138
|
+
let returnValue;
|
|
139
|
+
if (
|
|
140
|
+
aggregateHandlers.length === 0 &&
|
|
141
|
+
handlers.length === 0 &&
|
|
142
|
+
catchallHandlers.length === 0
|
|
143
|
+
) {
|
|
144
|
+
returnValue = originalFunction.apply(this, arguments);
|
|
145
|
+
} else {
|
|
146
|
+
contexts.push([
|
|
147
|
+
catchallHandlers.length,
|
|
148
|
+
aggregateHandlers.length,
|
|
149
|
+
handlers.length,
|
|
150
|
+
this,
|
|
151
|
+
arguments,
|
|
152
|
+
NOT_INVOKED,
|
|
153
|
+
]);
|
|
154
|
+
invokeHandlers();
|
|
155
|
+
const context = contexts.pop();
|
|
156
|
+
returnValue = context[5];
|
|
157
|
+
if (returnValue === NOT_INVOKED) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
'RelayProfiler: Handler did not invoke original function.',
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return returnValue;
|
|
164
|
+
};
|
|
165
|
+
instrumentedCallback.attachHandler = function(handler: Handler): void {
|
|
166
|
+
handlers.push(handler);
|
|
167
|
+
};
|
|
168
|
+
instrumentedCallback.detachHandler = function(handler: Handler): void {
|
|
169
|
+
removeFromArray(handlers, handler);
|
|
170
|
+
};
|
|
171
|
+
instrumentedCallback.displayName = '(instrumented ' + name + ')';
|
|
172
|
+
return (instrumentedCallback: any);
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Attaches a handler to all methods instrumented with the supplied name.
|
|
177
|
+
*
|
|
178
|
+
* function createRenderer() {
|
|
179
|
+
* return RelayProfiler.instrument('render', function() {...});
|
|
180
|
+
* }
|
|
181
|
+
* const renderA = createRenderer();
|
|
182
|
+
* const renderB = createRenderer();
|
|
183
|
+
*
|
|
184
|
+
* // Only profiles `renderA`.
|
|
185
|
+
* renderA.attachHandler(...);
|
|
186
|
+
*
|
|
187
|
+
* // Profiles both `renderA` and `renderB`.
|
|
188
|
+
* RelayProfiler.attachAggregateHandler('render', ...);
|
|
189
|
+
*
|
|
190
|
+
*/
|
|
191
|
+
attachAggregateHandler(name: string, handler: Handler): void {
|
|
192
|
+
if (shouldInstrument(name)) {
|
|
193
|
+
if (!aggregateHandlersByName.hasOwnProperty(name)) {
|
|
194
|
+
aggregateHandlersByName[name] = [];
|
|
195
|
+
}
|
|
196
|
+
aggregateHandlersByName[name].push(handler);
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Detaches a handler attached via `attachAggregateHandler`.
|
|
202
|
+
*/
|
|
203
|
+
detachAggregateHandler(name: string, handler: Handler): void {
|
|
204
|
+
if (shouldInstrument(name)) {
|
|
205
|
+
if (aggregateHandlersByName.hasOwnProperty(name)) {
|
|
206
|
+
removeFromArray(aggregateHandlersByName[name], handler);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Instruments profiling for arbitrarily asynchronous code by a name.
|
|
213
|
+
*
|
|
214
|
+
* const timerProfiler = RelayProfiler.profile('timeout');
|
|
215
|
+
* setTimeout(function() {
|
|
216
|
+
* timerProfiler.stop();
|
|
217
|
+
* }, 1000);
|
|
218
|
+
*
|
|
219
|
+
* RelayProfiler.attachProfileHandler('timeout', ...);
|
|
220
|
+
*
|
|
221
|
+
* Arbitrary state can also be passed into `profile` as a second argument. The
|
|
222
|
+
* attached profile handlers will receive this as the second argument.
|
|
223
|
+
*/
|
|
224
|
+
profile(name: string, state?: any): {stop: (error?: Error) => void, ...} {
|
|
225
|
+
const hasCatchAllHandlers = profileHandlersByName['*'].length > 0;
|
|
226
|
+
const hasNamedHandlers = profileHandlersByName.hasOwnProperty(name);
|
|
227
|
+
if (hasNamedHandlers || hasCatchAllHandlers) {
|
|
228
|
+
const profileHandlers =
|
|
229
|
+
hasNamedHandlers && hasCatchAllHandlers
|
|
230
|
+
? profileHandlersByName[name].concat(profileHandlersByName['*'])
|
|
231
|
+
: hasNamedHandlers
|
|
232
|
+
? profileHandlersByName[name]
|
|
233
|
+
: profileHandlersByName['*'];
|
|
234
|
+
let stopHandlers;
|
|
235
|
+
for (let ii = profileHandlers.length - 1; ii >= 0; ii--) {
|
|
236
|
+
const profileHandler = profileHandlers[ii];
|
|
237
|
+
const stopHandler = profileHandler(name, state);
|
|
238
|
+
stopHandlers = stopHandlers || [];
|
|
239
|
+
stopHandlers.unshift(stopHandler);
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
stop(error?: Error): void {
|
|
243
|
+
if (stopHandlers) {
|
|
244
|
+
stopHandlers.forEach(stopHandler => stopHandler(error));
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
return defaultProfiler;
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Attaches a handler to profiles with the supplied name. You can also
|
|
254
|
+
* attach to the special name '*' which is a catch all.
|
|
255
|
+
*/
|
|
256
|
+
attachProfileHandler(name: string, handler: ProfileHandler): void {
|
|
257
|
+
if (shouldInstrument(name)) {
|
|
258
|
+
if (!profileHandlersByName.hasOwnProperty(name)) {
|
|
259
|
+
profileHandlersByName[name] = [];
|
|
260
|
+
}
|
|
261
|
+
profileHandlersByName[name].push(handler);
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Detaches a handler attached via `attachProfileHandler`.
|
|
267
|
+
*/
|
|
268
|
+
detachProfileHandler(name: string, handler: ProfileHandler): void {
|
|
269
|
+
if (shouldInstrument(name)) {
|
|
270
|
+
if (profileHandlersByName.hasOwnProperty(name)) {
|
|
271
|
+
removeFromArray(profileHandlersByName[name], handler);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
function removeFromArray<T>(array: Array<T>, element: T): void {
|
|
278
|
+
var index = array.indexOf(element);
|
|
279
|
+
if (index !== -1) {
|
|
280
|
+
array.splice(index, 1);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
module.exports = RelayProfiler;
|
|
@@ -0,0 +1,135 @@
|
|
|
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 RelayObservable = require('../network/RelayObservable');
|
|
16
|
+
|
|
17
|
+
const invariant = require('invariant');
|
|
18
|
+
|
|
19
|
+
import type {Observer, Sink, Subscription} from '../network/RelayObservable';
|
|
20
|
+
|
|
21
|
+
type Event<T> =
|
|
22
|
+
| {
|
|
23
|
+
kind: 'next',
|
|
24
|
+
data: T,
|
|
25
|
+
...
|
|
26
|
+
}
|
|
27
|
+
| {
|
|
28
|
+
kind: 'error',
|
|
29
|
+
error: Error,
|
|
30
|
+
...
|
|
31
|
+
}
|
|
32
|
+
| {kind: 'complete', ...};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* An implementation of a `ReplaySubject` for Relay Observables.
|
|
36
|
+
*
|
|
37
|
+
* Records events provided and synchronously plays them back to new subscribers,
|
|
38
|
+
* as well as forwarding new asynchronous events.
|
|
39
|
+
*/
|
|
40
|
+
class RelayReplaySubject<T> {
|
|
41
|
+
_complete: boolean = false;
|
|
42
|
+
_events: Array<Event<T>> = [];
|
|
43
|
+
_sinks: Set<Sink<T>> = new Set();
|
|
44
|
+
_observable: RelayObservable<T>;
|
|
45
|
+
_subscription: ?Subscription = null;
|
|
46
|
+
|
|
47
|
+
constructor() {
|
|
48
|
+
this._observable = RelayObservable.create(sink => {
|
|
49
|
+
this._sinks.add(sink);
|
|
50
|
+
|
|
51
|
+
const events = this._events;
|
|
52
|
+
for (let i = 0; i < events.length; i++) {
|
|
53
|
+
if (sink.closed) {
|
|
54
|
+
// Bail if an event made the observer unsubscribe.
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
const event = events[i];
|
|
58
|
+
switch (event.kind) {
|
|
59
|
+
case 'complete':
|
|
60
|
+
sink.complete();
|
|
61
|
+
break;
|
|
62
|
+
case 'error':
|
|
63
|
+
sink.error(event.error);
|
|
64
|
+
break;
|
|
65
|
+
case 'next':
|
|
66
|
+
sink.next(event.data);
|
|
67
|
+
break;
|
|
68
|
+
default:
|
|
69
|
+
(event.kind: empty);
|
|
70
|
+
invariant(
|
|
71
|
+
false,
|
|
72
|
+
'RelayReplaySubject: Unknown event kind `%s`.',
|
|
73
|
+
event.kind,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return () => {
|
|
79
|
+
this._sinks.delete(sink);
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
complete(): void {
|
|
85
|
+
if (this._complete === true) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this._complete = true;
|
|
89
|
+
this._events.push({
|
|
90
|
+
kind: 'complete',
|
|
91
|
+
});
|
|
92
|
+
this._sinks.forEach(sink => sink.complete());
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
error(error: Error): void {
|
|
96
|
+
if (this._complete === true) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this._complete = true;
|
|
100
|
+
this._events.push({
|
|
101
|
+
kind: 'error',
|
|
102
|
+
error,
|
|
103
|
+
});
|
|
104
|
+
this._sinks.forEach(sink => sink.error(error));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
next(data: T): void {
|
|
108
|
+
if (this._complete === true) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
this._events.push({
|
|
112
|
+
kind: 'next',
|
|
113
|
+
data,
|
|
114
|
+
});
|
|
115
|
+
this._sinks.forEach(sink => sink.next(data));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
subscribe(observer: Observer<T> | Sink<T>): Subscription {
|
|
119
|
+
this._subscription = this._observable.subscribe(observer);
|
|
120
|
+
return this._subscription;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
unsubscribe() {
|
|
124
|
+
if (this._subscription) {
|
|
125
|
+
this._subscription.unsubscribe();
|
|
126
|
+
this._subscription = null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
getObserverCount(): number {
|
|
131
|
+
return this._sinks.size;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = RelayReplaySubject;
|
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
*/
|
|
10
|
+
|
|
11
|
+
// flowlint ambiguous-object-type:error
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Basic types used throughout Relay.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Represents any resource that must be explicitly disposed of. The most common
|
|
21
|
+
* use-case is as a return value for subscriptions, where calling `dispose()`
|
|
22
|
+
* would cancel the subscription.
|
|
23
|
+
*/
|
|
24
|
+
export type Disposable = {dispose(): void, ...};
|
|
25
|
+
|
|
26
|
+
export type DataID = string;
|
|
27
|
+
|
|
28
|
+
// Variables
|
|
29
|
+
export type Variables = {+[string]: $FlowFixMe, ...};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Generated operation flow types are subtypes of this.
|
|
33
|
+
*/
|
|
34
|
+
export type OperationType = {|
|
|
35
|
+
// TODO(T33395812) Make this an open object type
|
|
36
|
+
+variables: Variables,
|
|
37
|
+
+response: mixed,
|
|
38
|
+
+rawResponse?: {...},
|
|
39
|
+
|};
|
|
40
|
+
|
|
41
|
+
export type VariablesOf<T: OperationType> = $ElementType<T, 'variables'>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Settings for how a query response may be cached.
|
|
45
|
+
*
|
|
46
|
+
* - `force`: causes a query to be issued unconditionally, irrespective of the
|
|
47
|
+
* state of any configured response cache.
|
|
48
|
+
* - `poll`: causes a query to live update by polling at the specified interval
|
|
49
|
+
* in milliseconds. (This value will be passed to setTimeout.)
|
|
50
|
+
* - `liveConfigId`: causes a query to live update by calling GraphQLLiveQuery,
|
|
51
|
+
* it represents a configuration of gateway when doing live query
|
|
52
|
+
* - `metadata`: user-supplied metadata.
|
|
53
|
+
* - `transactionId`: a user-supplied value, intended for use as a unique id for
|
|
54
|
+
* a given instance of executing an operation.
|
|
55
|
+
*/
|
|
56
|
+
export type CacheConfig = {|
|
|
57
|
+
force?: ?boolean,
|
|
58
|
+
poll?: ?number,
|
|
59
|
+
liveConfigId?: ?string,
|
|
60
|
+
metadata?: {[key: string]: mixed, ...},
|
|
61
|
+
transactionId?: ?string,
|
|
62
|
+
|};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Experimental
|
|
66
|
+
*/
|
|
67
|
+
export type FetchQueryFetchPolicy = 'store-or-network' | 'network-only';
|
|
68
|
+
export type FetchPolicy =
|
|
69
|
+
| FetchQueryFetchPolicy
|
|
70
|
+
| 'store-and-network'
|
|
71
|
+
| 'store-only';
|
|
72
|
+
export type RenderPolicy = 'full' | 'partial';
|