relay-runtime 20.1.1 → 21.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.
Files changed (334) hide show
  1. package/experimental.d.ts +34 -0
  2. package/experimental.js +1 -1
  3. package/experimental.js.flow +11 -11
  4. package/handlers/RelayDefaultHandlerProvider.d.ts +12 -0
  5. package/handlers/connection/ConnectionHandler.d.ts +51 -0
  6. package/handlers/connection/ConnectionHandler.js.flow +5 -5
  7. package/handlers/connection/ConnectionInterface.d.ts +40 -0
  8. package/handlers/connection/ConnectionInterface.js.flow +1 -1
  9. package/handlers/connection/MutationHandlers.d.ts +17 -0
  10. package/index.d.ts +274 -0
  11. package/index.js +1 -1
  12. package/index.js.flow +125 -62
  13. package/lib/experimental.js +3 -3
  14. package/lib/index.js +105 -57
  15. package/lib/multi-actor-environment/ActorIdentifier.js +2 -2
  16. package/lib/multi-actor-environment/MultiActorEnvironment.js +3 -1
  17. package/lib/mutations/commitMutation.js +8 -8
  18. package/lib/mutations/validateMutation.js +4 -4
  19. package/lib/query/GraphQLTag.js +3 -3
  20. package/lib/query/fetchQuery.js +15 -3
  21. package/lib/store/DataChecker.js +38 -4
  22. package/lib/store/NormalizationEngine.js +373 -0
  23. package/lib/store/OperationExecutor.js +172 -113
  24. package/lib/store/RelayConcreteVariables.js +1 -1
  25. package/lib/store/RelayErrorTrie.js +2 -2
  26. package/lib/store/RelayExperimentalGraphResponseTransform.js +8 -8
  27. package/lib/store/RelayModernEnvironment.js +26 -19
  28. package/lib/store/RelayModernRecord.js +18 -8
  29. package/lib/store/RelayModernSelector.js +9 -9
  30. package/lib/store/RelayModernStore.js +152 -43
  31. package/lib/store/RelayPublishQueue.js +1 -1
  32. package/lib/store/RelayReader.js +76 -38
  33. package/lib/store/RelayRecordSource.js +6 -0
  34. package/lib/store/RelayReferenceMarker.js +2 -1
  35. package/lib/store/RelayResponseNormalizer.js +88 -55
  36. package/lib/store/RelayStoreSubscriptions.js +34 -10
  37. package/lib/store/RelayStoreUtils.js +8 -1
  38. package/lib/store/ResolverFragments.js +2 -2
  39. package/lib/store/live-resolvers/LiveResolverCache.js +25 -9
  40. package/lib/store/observeFragmentExperimental.js +17 -1
  41. package/lib/store/observeQueryExperimental.js +2 -2
  42. package/lib/subscription/requestSubscription.js +3 -3
  43. package/lib/util/RelayError.js +3 -0
  44. package/lib/util/RelayFeatureFlags.js +6 -2
  45. package/lib/util/RelayReplaySubject.js +4 -4
  46. package/lib/util/handlePotentialSnapshotErrors.js +2 -2
  47. package/lib/util/stableCopy.js +2 -2
  48. package/llm-docs/api-reference/entrypoint-apis/entrypoint-container.mdx +38 -0
  49. package/llm-docs/api-reference/entrypoint-apis/load-entrypoint.mdx +77 -0
  50. package/llm-docs/api-reference/entrypoint-apis/use-entrypoint-loader.mdx +99 -0
  51. package/llm-docs/api-reference/graphql/graphql-directives.mdx +378 -0
  52. package/llm-docs/api-reference/hooks/_use-lazy-load-query-extra.mdx +16 -0
  53. package/llm-docs/api-reference/hooks/load-query.mdx +84 -0
  54. package/llm-docs/api-reference/hooks/relay-environment-provider.mdx +78 -0
  55. package/llm-docs/api-reference/hooks/use-client-query.mdx +65 -0
  56. package/llm-docs/api-reference/hooks/use-fragment.mdx +69 -0
  57. package/llm-docs/api-reference/hooks/use-lazy-load-query.mdx +62 -0
  58. package/llm-docs/api-reference/hooks/use-mutation.mdx +94 -0
  59. package/llm-docs/api-reference/hooks/use-pagination-fragment.mdx +166 -0
  60. package/llm-docs/api-reference/hooks/use-prefetchable-forward-pagination-fragment.mdx +134 -0
  61. package/llm-docs/api-reference/hooks/use-preloaded-query.mdx +84 -0
  62. package/llm-docs/api-reference/hooks/use-query-loader.mdx +95 -0
  63. package/llm-docs/api-reference/hooks/use-refetchable-fragment.mdx +122 -0
  64. package/llm-docs/api-reference/hooks/use-relay-environment.mdx +37 -0
  65. package/llm-docs/api-reference/hooks/use-subscription.mdx +66 -0
  66. package/llm-docs/api-reference/relay-resolvers/docblock-format.mdx +321 -0
  67. package/llm-docs/api-reference/relay-resolvers/runtime-functions.mdx +94 -0
  68. package/llm-docs/api-reference/relay-runtime/commit-mutation.mdx +65 -0
  69. package/llm-docs/api-reference/relay-runtime/fetch-query.mdx +118 -0
  70. package/llm-docs/api-reference/relay-runtime/field-logger.mdx +170 -0
  71. package/llm-docs/api-reference/relay-runtime/observe-fragment.mdx +92 -0
  72. package/llm-docs/api-reference/relay-runtime/relay-environment.mdx +53 -0
  73. package/llm-docs/api-reference/relay-runtime/request-subscription.mdx +54 -0
  74. package/llm-docs/api-reference/relay-runtime/runtime-configuration.mdx +52 -0
  75. package/llm-docs/api-reference/relay-runtime/store.mdx +734 -0
  76. package/llm-docs/api-reference/relay-runtime/wait-for-fragment-data.mdx +89 -0
  77. package/llm-docs/api-reference/types/CacheConfig.mdx +8 -0
  78. package/llm-docs/api-reference/types/Disposable.mdx +4 -0
  79. package/llm-docs/api-reference/types/GraphQLSubscriptionConfig.mdx +17 -0
  80. package/llm-docs/api-reference/types/MutationConfig.mdx +31 -0
  81. package/llm-docs/api-reference/types/SelectorStoreUpdater.mdx +6 -0
  82. package/llm-docs/api-reference/types/UploadableMap.mdx +3 -0
  83. package/llm-docs/community/learning-resources.mdx +64 -0
  84. package/llm-docs/debugging/declarative-mutation-directives.mdx +34 -0
  85. package/llm-docs/debugging/disallowed-id-types-error.mdx +43 -0
  86. package/llm-docs/debugging/inconsistent-typename-error.mdx +47 -0
  87. package/llm-docs/debugging/relay-devtools.mdx +73 -0
  88. package/llm-docs/debugging/why-null.mdx +116 -0
  89. package/llm-docs/editor-support.mdx +55 -0
  90. package/llm-docs/error-reference/unknown-field.mdx +36 -0
  91. package/llm-docs/getting-started/babel-plugin.mdx +31 -0
  92. package/llm-docs/getting-started/compiler-config.mdx +25 -0
  93. package/llm-docs/getting-started/compiler.mdx +98 -0
  94. package/llm-docs/getting-started/lint-rules.mdx +87 -0
  95. package/llm-docs/getting-started/production.mdx +30 -0
  96. package/llm-docs/getting-started/quick-start.mdx +216 -0
  97. package/llm-docs/glossary/glossary.mdx +1040 -0
  98. package/llm-docs/guided-tour/list-data/advanced-pagination.mdx +157 -0
  99. package/llm-docs/guided-tour/list-data/connections.mdx +81 -0
  100. package/llm-docs/guided-tour/list-data/pagination.mdx +193 -0
  101. package/llm-docs/guided-tour/list-data/rendering-connections.mdx +112 -0
  102. package/llm-docs/guided-tour/list-data/streaming-pagination.mdx +87 -0
  103. package/llm-docs/guided-tour/managing-data-outside-react/retaining-queries.mdx +51 -0
  104. package/llm-docs/guided-tour/refetching/refetching-queries-with-different-data.mdx +337 -0
  105. package/llm-docs/guided-tour/refetching/refreshing-queries.mdx +350 -0
  106. package/llm-docs/guided-tour/rendering/environment.mdx +59 -0
  107. package/llm-docs/guided-tour/rendering/error-states.mdx +295 -0
  108. package/llm-docs/guided-tour/rendering/fragments.mdx +354 -0
  109. package/llm-docs/guided-tour/rendering/loading-states.mdx +245 -0
  110. package/llm-docs/guided-tour/rendering/queries.mdx +261 -0
  111. package/llm-docs/guided-tour/rendering/variables.mdx +233 -0
  112. package/llm-docs/guided-tour/reusing-cached-data/fetch-policies.mdx +56 -0
  113. package/llm-docs/guided-tour/reusing-cached-data/filling-in-missing-data.mdx +102 -0
  114. package/llm-docs/guided-tour/reusing-cached-data/introduction.mdx +22 -0
  115. package/llm-docs/guided-tour/reusing-cached-data/presence-of-data.mdx +93 -0
  116. package/llm-docs/guided-tour/reusing-cached-data/rendering-partially-cached-data.mdx +175 -0
  117. package/llm-docs/guided-tour/reusing-cached-data/staleness-of-data.mdx +116 -0
  118. package/llm-docs/guided-tour/updating-data/client-only-data.mdx +115 -0
  119. package/llm-docs/guided-tour/updating-data/graphql-mutations.mdx +334 -0
  120. package/llm-docs/guided-tour/updating-data/graphql-subscriptions.mdx +279 -0
  121. package/llm-docs/guided-tour/updating-data/imperatively-modifying-linked-fields.mdx +511 -0
  122. package/llm-docs/guided-tour/updating-data/imperatively-modifying-store-data-legacy.mdx +142 -0
  123. package/llm-docs/guided-tour/updating-data/imperatively-modifying-store-data.mdx +275 -0
  124. package/llm-docs/guided-tour/updating-data/introduction.mdx +25 -0
  125. package/llm-docs/guided-tour/updating-data/local-data-updates.mdx +71 -0
  126. package/llm-docs/guided-tour/updating-data/typesafe-updaters-faq.mdx +83 -0
  127. package/llm-docs/guided-tour/updating-data/updating-connections.mdx +592 -0
  128. package/llm-docs/guides/alias-directive.mdx +160 -0
  129. package/llm-docs/guides/catch-directive.mdx +167 -0
  130. package/llm-docs/guides/client-schema-extensions.mdx +208 -0
  131. package/llm-docs/guides/codemods.mdx +79 -0
  132. package/llm-docs/guides/data-driven-dependencies/client-3d.mdx +255 -0
  133. package/llm-docs/guides/data-driven-dependencies/configuration.mdx +127 -0
  134. package/llm-docs/guides/data-driven-dependencies/introduction.mdx +39 -0
  135. package/llm-docs/guides/data-driven-dependencies/server-3d.mdx +664 -0
  136. package/llm-docs/guides/document-comparison.mdx +106 -0
  137. package/llm-docs/guides/graphql-server-specification.mdx +453 -0
  138. package/llm-docs/guides/network-layer.mdx +69 -0
  139. package/llm-docs/guides/persisted-queries.mdx +328 -0
  140. package/llm-docs/guides/relay-resolvers/context.mdx +99 -0
  141. package/llm-docs/guides/relay-resolvers/defining-fields.mdx +151 -0
  142. package/llm-docs/guides/relay-resolvers/defining-types.mdx +164 -0
  143. package/llm-docs/guides/relay-resolvers/deprecated.mdx +27 -0
  144. package/llm-docs/guides/relay-resolvers/derived-fields.mdx +127 -0
  145. package/llm-docs/guides/relay-resolvers/descriptions.mdx +44 -0
  146. package/llm-docs/guides/relay-resolvers/enabling.mdx +41 -0
  147. package/llm-docs/guides/relay-resolvers/errors.mdx +64 -0
  148. package/llm-docs/guides/relay-resolvers/field-arguments.mdx +63 -0
  149. package/llm-docs/guides/relay-resolvers/introduction.mdx +62 -0
  150. package/llm-docs/guides/relay-resolvers/limitations.mdx +30 -0
  151. package/llm-docs/guides/relay-resolvers/live-fields.mdx +164 -0
  152. package/llm-docs/guides/relay-resolvers/return-types.mdx +161 -0
  153. package/llm-docs/guides/relay-resolvers/suspense.mdx +41 -0
  154. package/llm-docs/guides/required-directive.mdx +240 -0
  155. package/llm-docs/guides/semantic-nullability.mdx +93 -0
  156. package/llm-docs/guides/testing-relay-components.mdx +642 -0
  157. package/llm-docs/guides/testing-relay-with-preloaded-queries.mdx +160 -0
  158. package/llm-docs/guides/throw-on-field-error-directive.mdx +58 -0
  159. package/llm-docs/guides/type-emission.mdx +414 -0
  160. package/llm-docs/home.mdx +32 -0
  161. package/llm-docs/principles-and-architecture/architecture-overview.mdx +24 -0
  162. package/llm-docs/principles-and-architecture/compiler-architecture.mdx +106 -0
  163. package/llm-docs/principles-and-architecture/runtime-architecture.mdx +249 -0
  164. package/llm-docs/principles-and-architecture/thinking-in-graphql.mdx +309 -0
  165. package/llm-docs/principles-and-architecture/thinking-in-relay.mdx +104 -0
  166. package/llm-docs/principles-and-architecture/videos.mdx +50 -0
  167. package/llm-docs/tutorial/arrays-lists.mdx +126 -0
  168. package/llm-docs/tutorial/fragments-1.mdx +487 -0
  169. package/llm-docs/tutorial/graphql.mdx +172 -0
  170. package/llm-docs/tutorial/interfaces-polymorphism.mdx +161 -0
  171. package/llm-docs/tutorial/intro.mdx +58 -0
  172. package/llm-docs/tutorial/mutations-updates.mdx +624 -0
  173. package/llm-docs/tutorial/organizing-mutations-queries-and-subscriptions.mdx +13 -0
  174. package/llm-docs/tutorial/queries-1.mdx +267 -0
  175. package/llm-docs/tutorial/queries-2.mdx +389 -0
  176. package/llm-docs/tutorial/refetchable-fragments.mdx +352 -0
  177. package/multi-actor-environment/ActorIdentifier.d.ts +17 -0
  178. package/multi-actor-environment/ActorIdentifier.js.flow +2 -2
  179. package/multi-actor-environment/ActorSpecificEnvironment.js.flow +15 -15
  180. package/multi-actor-environment/ActorUtils.js.flow +1 -1
  181. package/multi-actor-environment/MultiActorEnvironment.d.ts +123 -0
  182. package/multi-actor-environment/MultiActorEnvironment.js.flow +32 -24
  183. package/multi-actor-environment/MultiActorEnvironmentTypes.d.ts +225 -0
  184. package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +6 -6
  185. package/multi-actor-environment/index.d.ts +14 -0
  186. package/multi-actor-environment.d.ts +8 -0
  187. package/mutations/RelayDeclarativeMutationConfig.d.ts +70 -0
  188. package/mutations/RelayDeclarativeMutationConfig.js.flow +9 -9
  189. package/mutations/RelayRecordProxy.js.flow +8 -11
  190. package/mutations/RelayRecordSourceMutator.js.flow +4 -4
  191. package/mutations/RelayRecordSourceProxy.js.flow +4 -4
  192. package/mutations/RelayRecordSourceSelectorProxy.js.flow +6 -6
  193. package/mutations/applyOptimisticMutation.d.ts +25 -0
  194. package/mutations/applyOptimisticMutation.js.flow +2 -2
  195. package/mutations/commitLocalUpdate.d.ts +10 -0
  196. package/mutations/commitMutation.d.ts +48 -0
  197. package/mutations/commitMutation.js.flow +21 -17
  198. package/mutations/createUpdatableProxy.js.flow +19 -19
  199. package/mutations/readUpdatableFragment.js.flow +3 -3
  200. package/mutations/readUpdatableQuery.js.flow +3 -3
  201. package/mutations/validateMutation.js.flow +7 -7
  202. package/network/RelayNetwork.d.ts +12 -0
  203. package/network/RelayNetworkTypes.d.ts +145 -0
  204. package/network/RelayNetworkTypes.js.flow +18 -18
  205. package/network/RelayObservable.d.ts +197 -0
  206. package/network/RelayObservable.js.flow +32 -30
  207. package/network/RelayQueryResponseCache.d.ts +16 -0
  208. package/network/RelayQueryResponseCache.js.flow +3 -3
  209. package/network/wrapNetworkWithLogObserver.js.flow +1 -1
  210. package/package.json +2 -1
  211. package/query/GraphQLTag.d.ts +45 -0
  212. package/query/GraphQLTag.js.flow +22 -10
  213. package/query/fetchQuery.d.ts +21 -0
  214. package/query/fetchQuery.js.flow +23 -10
  215. package/query/fetchQueryInternal.d.ts +26 -0
  216. package/query/fetchQueryInternal.js.flow +4 -4
  217. package/query/fetchQuery_DEPRECATED.d.ts +17 -0
  218. package/query/fetchQuery_DEPRECATED.js.flow +1 -1
  219. package/store/ClientID.d.ts +14 -0
  220. package/store/DataChecker.js.flow +51 -15
  221. package/store/NormalizationEngine.js.flow +782 -0
  222. package/store/OperationExecutor.d.ts +51 -0
  223. package/store/OperationExecutor.js.flow +204 -98
  224. package/store/RelayConcreteVariables.js.flow +5 -5
  225. package/store/RelayErrorTrie.js.flow +12 -12
  226. package/store/RelayExperimentalGraphResponseHandler.js.flow +3 -3
  227. package/store/RelayExperimentalGraphResponseTransform.js.flow +10 -10
  228. package/store/RelayModernEnvironment.d.ts +97 -0
  229. package/store/RelayModernEnvironment.js.flow +58 -43
  230. package/store/RelayModernFragmentSpecResolver.js.flow +1 -1
  231. package/store/RelayModernOperationDescriptor.d.ts +28 -0
  232. package/store/RelayModernOperationDescriptor.js.flow +1 -1
  233. package/store/RelayModernRecord.d.ts +92 -0
  234. package/store/RelayModernRecord.js.flow +44 -20
  235. package/store/RelayModernSelector.d.ts +123 -0
  236. package/store/RelayModernSelector.js.flow +21 -21
  237. package/store/RelayModernStore.d.ts +57 -0
  238. package/store/RelayModernStore.js.flow +219 -58
  239. package/store/RelayOperationTracker.d.ts +29 -0
  240. package/store/RelayOperationTracker.js.flow +2 -2
  241. package/store/RelayOptimisticRecordSource.js.flow +2 -2
  242. package/store/RelayPublishQueue.js.flow +29 -20
  243. package/store/RelayReader.js.flow +129 -57
  244. package/store/RelayRecordSource.d.ts +26 -0
  245. package/store/RelayRecordSource.js.flow +10 -0
  246. package/store/RelayRecordState.d.ts +28 -0
  247. package/store/RelayRecordState.js.flow +1 -1
  248. package/store/RelayReferenceMarker.js.flow +5 -4
  249. package/store/RelayResponseNormalizer.d.ts +28 -0
  250. package/store/RelayResponseNormalizer.js.flow +130 -62
  251. package/store/RelayStoreSubscriptions.js.flow +52 -8
  252. package/store/RelayStoreTypes.d.ts +1327 -0
  253. package/store/RelayStoreTypes.js.flow +371 -278
  254. package/store/RelayStoreUtils.d.ts +86 -0
  255. package/store/RelayStoreUtils.js.flow +16 -8
  256. package/store/ResolverCache.js.flow +2 -2
  257. package/store/ResolverFragments.d.ts +43 -0
  258. package/store/ResolverFragments.js.flow +22 -14
  259. package/store/StoreInspector.js.flow +7 -8
  260. package/store/ViewerPattern.d.ts +11 -0
  261. package/store/cloneRelayHandleSourceField.js.flow +1 -1
  262. package/store/cloneRelayScalarHandleSourceField.js.flow +1 -1
  263. package/store/createFragmentSpecResolver.d.ts +16 -0
  264. package/store/createRelayContext.js.flow +1 -1
  265. package/store/createRelayLoggingContext.js.flow +4 -4
  266. package/store/defaultGetDataID.js.flow +2 -2
  267. package/store/isRelayModernEnvironment.d.ts +8 -0
  268. package/store/isRelayModernEnvironment.js.flow +4 -2
  269. package/store/live-resolvers/LiveResolverCache.js.flow +55 -20
  270. package/store/live-resolvers/LiveResolverSuspenseSentinel.js.flow +3 -3
  271. package/store/live-resolvers/getOutputTypeRecordIDs.js.flow +1 -1
  272. package/store/live-resolvers/isLiveStateValue.js.flow +2 -2
  273. package/store/live-resolvers/resolverDataInjector.d.ts +27 -0
  274. package/store/live-resolvers/resolverDataInjector.js.flow +8 -5
  275. package/store/observeFragmentExperimental.d.ts +46 -0
  276. package/store/observeFragmentExperimental.js.flow +50 -21
  277. package/store/observeQueryExperimental.d.ts +30 -0
  278. package/store/observeQueryExperimental.js.flow +5 -5
  279. package/store/readInlineData.d.ts +19 -0
  280. package/store/readInlineData.js.flow +5 -5
  281. package/store/waitForFragmentExperimental.d.ts +49 -0
  282. package/store/waitForFragmentExperimental.js.flow +3 -3
  283. package/subscription/requestSubscription.d.ts +27 -0
  284. package/subscription/requestSubscription.js.flow +10 -10
  285. package/util/JSResourceTypes.flow.js.flow +4 -4
  286. package/util/NormalizationNode.d.ts +235 -0
  287. package/util/NormalizationNode.js.flow +127 -123
  288. package/util/ReaderNode.d.ts +264 -0
  289. package/util/ReaderNode.js.flow +156 -151
  290. package/util/RelayConcreteNode.d.ts +120 -0
  291. package/util/RelayConcreteNode.js.flow +32 -32
  292. package/util/RelayError.d.ts +13 -0
  293. package/util/RelayError.js.flow +4 -1
  294. package/util/RelayFeatureFlags.d.ts +40 -0
  295. package/util/RelayFeatureFlags.js.flow +21 -1
  296. package/util/RelayProfiler.d.ts +121 -0
  297. package/util/RelayProfiler.js.flow +1 -1
  298. package/util/RelayReplaySubject.d.ts +25 -0
  299. package/util/RelayReplaySubject.js.flow +3 -3
  300. package/util/RelayRuntimeTypes.d.ts +59 -0
  301. package/util/RelayRuntimeTypes.js.flow +36 -33
  302. package/util/createPayloadFor3DField.d.ts +17 -0
  303. package/util/createPayloadFor3DField.js.flow +9 -5
  304. package/util/deepFreeze.d.ts +8 -0
  305. package/util/deepFreeze.js.flow +2 -2
  306. package/util/getFragmentIdentifier.d.ts +10 -0
  307. package/util/getFragmentIdentifier.js.flow +1 -1
  308. package/util/getPaginationMetadata.d.ts +20 -0
  309. package/util/getPaginationMetadata.js.flow +1 -1
  310. package/util/getPaginationVariables.d.ts +20 -0
  311. package/util/getPaginationVariables.js.flow +1 -1
  312. package/util/getPendingOperationsForFragment.d.ts +18 -0
  313. package/util/getPendingOperationsForFragment.js.flow +2 -2
  314. package/util/getRefetchMetadata.d.ts +19 -0
  315. package/util/getRefetchMetadata.js.flow +6 -5
  316. package/util/getRelayHandleKey.d.ts +8 -0
  317. package/util/getRequestIdentifier.d.ts +17 -0
  318. package/util/getValueAtPath.d.ts +8 -0
  319. package/util/getValueAtPath.js.flow +3 -3
  320. package/util/handlePotentialSnapshotErrors.d.ts +14 -0
  321. package/util/handlePotentialSnapshotErrors.js.flow +5 -5
  322. package/util/isEmptyObject.js.flow +1 -1
  323. package/util/isPromise.d.ts +8 -0
  324. package/util/isPromise.js.flow +2 -2
  325. package/util/isScalarAndEqual.d.ts +8 -0
  326. package/util/isScalarAndEqual.js.flow +1 -1
  327. package/util/recycleNodesInto.d.ts +8 -0
  328. package/util/recycleNodesInto.js.flow +2 -2
  329. package/util/registerEnvironmentWithDevTools.js.flow +1 -1
  330. package/util/shallowFreeze.js.flow +1 -1
  331. package/util/stableCopy.d.ts +8 -0
  332. package/util/stableCopy.js.flow +5 -5
  333. package/util/withProvidedVariables.d.ts +19 -0
  334. package/util/withProvidedVariables.js.flow +14 -10
@@ -31,6 +31,6 @@ const RelayRecordState = {
31
31
  UNKNOWN: 'UNKNOWN',
32
32
  } as const;
33
33
 
34
- export type RecordState = $Keys<typeof RelayRecordState>;
34
+ export type RecordState = keyof typeof RelayRecordState;
35
35
 
36
36
  module.exports = RelayRecordState;
@@ -106,7 +106,7 @@ class RelayReferenceMarker {
106
106
  this._traverseSelections(node.selections, record);
107
107
  }
108
108
 
109
- _getVariableValue(name: string): mixed {
109
+ _getVariableValue(name: string): unknown {
110
110
  invariant(
111
111
  this._variables.hasOwnProperty(name),
112
112
  'RelayReferenceMarker(): Undefined variable `%s`.',
@@ -116,7 +116,7 @@ class RelayReferenceMarker {
116
116
  }
117
117
 
118
118
  _traverseSelections(
119
- selections: $ReadOnlyArray<NormalizationSelection>,
119
+ selections: ReadonlyArray<NormalizationSelection>,
120
120
  record: Record,
121
121
  ): void {
122
122
  selections.forEach(selection => {
@@ -229,7 +229,7 @@ class RelayReferenceMarker {
229
229
  this._traverseClientEdgeToClientObject(selection, record);
230
230
  break;
231
231
  default:
232
- (selection: empty);
232
+ selection as empty;
233
233
  invariant(
234
234
  false,
235
235
  'RelayReferenceMarker: Unknown AST node `%s`.',
@@ -255,16 +255,17 @@ class RelayReferenceMarker {
255
255
  if (resolverRecord == null) {
256
256
  return;
257
257
  }
258
+ const {linkedField} = field;
258
259
  if (field.backingField.isOutputType) {
259
260
  // Mark all @outputType record IDs
260
261
  const outputTypeRecordIDs = getOutputTypeRecordIDs(resolverRecord);
261
262
  if (outputTypeRecordIDs != null) {
262
263
  for (const dataID of outputTypeRecordIDs) {
263
264
  this._references.add(dataID);
265
+ this._traverse(linkedField, dataID);
264
266
  }
265
267
  }
266
268
  } else {
267
- const {linkedField} = field;
268
269
  const concreteType = linkedField.concreteType;
269
270
  if (concreteType == null) {
270
271
  // TODO: Handle retaining abstract client edges to client types.
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and 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
+
8
+ import { PayloadData } from '../network/RelayNetworkTypes';
9
+ import {MutableRecordSource, NormalizationSelector, RelayResponsePayload, RequestDescriptor} from './RelayStoreTypes';
10
+
11
+ export type GetDataID = (fieldValue: { [key: string]: any }, typeName: string) => any;
12
+
13
+ export interface NormalizationOptions {
14
+ getDataID: GetDataID;
15
+ path?: readonly string[] | undefined;
16
+ request: RequestDescriptor;
17
+ }
18
+
19
+ /**
20
+ * Normalizes the results of a query and standard GraphQL response, writing the
21
+ * normalized records/fields into the given MutableRecordSource.
22
+ */
23
+ export function normalize(
24
+ recordSource: MutableRecordSource,
25
+ selector: NormalizationSelector,
26
+ response: PayloadData,
27
+ options: NormalizationOptions,
28
+ ): RelayResponsePayload;
@@ -15,7 +15,9 @@ import type {ActorIdentifier} from '../multi-actor-environment/ActorIdentifier';
15
15
  import type {PayloadData, PayloadError} from '../network/RelayNetworkTypes';
16
16
  import type {
17
17
  NormalizationActorChange,
18
+ NormalizationClientEdgeToClientObject,
18
19
  NormalizationDefer,
20
+ NormalizationInlineFragment,
19
21
  NormalizationLinkedField,
20
22
  NormalizationLiveResolverField,
21
23
  NormalizationModuleImport,
@@ -54,6 +56,7 @@ const RelayModernRecord = require('./RelayModernRecord');
54
56
  const {createNormalizationSelector} = require('./RelayModernSelector');
55
57
  const {
56
58
  ROOT_ID,
59
+ ROOT_TYPE,
57
60
  TYPENAME_KEY,
58
61
  getArgumentValues,
59
62
  getHandleStorageKey,
@@ -67,17 +70,18 @@ const invariant = require('invariant');
67
70
  const warning = require('warning');
68
71
 
69
72
  export type GetDataID = (
70
- fieldValue: {+[string]: mixed},
73
+ fieldValue: {readonly [string]: unknown},
71
74
  typeName: string,
72
- ) => mixed;
75
+ ) => unknown;
73
76
 
74
77
  export type NormalizationOptions = {
75
- +getDataID: GetDataID,
76
- +treatMissingFieldsAsNull: boolean,
77
- +log: ?LogFunction,
78
- +path?: $ReadOnlyArray<string>,
79
- +shouldProcessClientComponents?: ?boolean,
80
- +actorIdentifier?: ?ActorIdentifier,
78
+ readonly getDataID: GetDataID,
79
+ readonly treatMissingFieldsAsNull: boolean,
80
+ readonly deferDeduplicatedFields: boolean,
81
+ readonly log: ?LogFunction,
82
+ readonly path?: ReadonlyArray<string>,
83
+ readonly shouldProcessClientComponents?: ?boolean,
84
+ readonly actorIdentifier?: ?ActorIdentifier,
81
85
  };
82
86
 
83
87
  /**
@@ -112,6 +116,7 @@ class RelayResponseNormalizer {
112
116
  _getDataId: GetDataID;
113
117
  _handleFieldPayloads: Array<HandleFieldPayload>;
114
118
  _treatMissingFieldsAsNull: boolean;
119
+ _deferDeduplicatedFields: boolean;
115
120
  _incrementalPlaceholders: Array<IncrementalDataPlaceholder>;
116
121
  _isClientExtension: boolean;
117
122
  _isUnmatchedAbstractType: boolean;
@@ -123,6 +128,17 @@ class RelayResponseNormalizer {
123
128
  _shouldProcessClientComponents: ?boolean;
124
129
  _errorTrie: RelayErrorTrie | null;
125
130
  _log: ?LogFunction;
131
+ _s2cExecutions: Map<
132
+ DataID,
133
+ {
134
+ selections: Array<
135
+ | NormalizationClientEdgeToClientObject
136
+ | NormalizationLiveResolverField
137
+ | NormalizationResolverField,
138
+ >,
139
+ typeName: string,
140
+ },
141
+ >;
126
142
 
127
143
  constructor(
128
144
  recordSource: MutableRecordSource,
@@ -134,6 +150,7 @@ class RelayResponseNormalizer {
134
150
  this._getDataId = options.getDataID;
135
151
  this._handleFieldPayloads = [];
136
152
  this._treatMissingFieldsAsNull = options.treatMissingFieldsAsNull;
153
+ this._deferDeduplicatedFields = options.deferDeduplicatedFields;
137
154
  this._incrementalPlaceholders = [];
138
155
  this._isClientExtension = false;
139
156
  this._isUnmatchedAbstractType = false;
@@ -144,6 +161,7 @@ class RelayResponseNormalizer {
144
161
  this._variables = variables;
145
162
  this._shouldProcessClientComponents = options.shouldProcessClientComponents;
146
163
  this._log = options.log;
164
+ this._s2cExecutions = new Map();
147
165
  }
148
166
 
149
167
  normalizeResponse(
@@ -164,10 +182,20 @@ class RelayResponseNormalizer {
164
182
  return {
165
183
  errors,
166
184
  fieldPayloads: this._handleFieldPayloads,
167
- incrementalPlaceholders: this._incrementalPlaceholders,
168
185
  followupPayloads: this._followupPayloads,
169
- source: this._recordSource,
186
+ incrementalPlaceholders: this._incrementalPlaceholders,
170
187
  isFinal: false,
188
+ s2cExecutions:
189
+ this._s2cExecutions.size > 0
190
+ ? Array.from(this._s2cExecutions.entries()).map(
191
+ ([recordID, entry]) => ({
192
+ recordID,
193
+ selections: entry.selections,
194
+ typeName: entry.typeName,
195
+ }),
196
+ )
197
+ : undefined,
198
+ source: this._recordSource,
171
199
  };
172
200
  }
173
201
 
@@ -192,7 +220,7 @@ class RelayResponseNormalizer {
192
220
  }
193
221
  }
194
222
 
195
- _getVariableValue(name: string): mixed {
223
+ _getVariableValue(name: string): unknown {
196
224
  invariant(
197
225
  this._variables.hasOwnProperty(name),
198
226
  'RelayResponseNormalizer(): Undefined variable `%s`.',
@@ -202,7 +230,7 @@ class RelayResponseNormalizer {
202
230
  }
203
231
 
204
232
  _getRecordType(data: PayloadData): string {
205
- const typeName = (data: any)[TYPENAME_KEY];
233
+ const typeName = (data as any)[TYPENAME_KEY];
206
234
  invariant(
207
235
  typeName != null,
208
236
  'RelayResponseNormalizer(): Expected a typename for record `%s`.',
@@ -243,34 +271,7 @@ class RelayResponseNormalizer {
243
271
  break;
244
272
  }
245
273
  case 'InlineFragment': {
246
- const {abstractKey} = selection;
247
- if (abstractKey == null) {
248
- const typeName = RelayModernRecord.getType(record);
249
- if (typeName === selection.type) {
250
- this._traverseSelections(selection, record, data);
251
- }
252
- } else {
253
- // $FlowFixMe[method-unbinding] - data could be prototype less
254
- const implementsInterface = Object.prototype.hasOwnProperty.call(
255
- data,
256
- abstractKey,
257
- );
258
- const typeName = RelayModernRecord.getType(record);
259
- const typeID = generateTypeID(typeName);
260
- let typeRecord = this._recordSource.get(typeID);
261
- if (typeRecord == null) {
262
- typeRecord = RelayModernRecord.create(typeID, TYPE_SCHEMA_TYPE);
263
- this._recordSource.set(typeID, typeRecord);
264
- }
265
- RelayModernRecord.setValue(
266
- typeRecord,
267
- abstractKey,
268
- implementsInterface,
269
- );
270
- if (implementsInterface) {
271
- this._traverseSelections(selection, record, data);
272
- }
273
- }
274
+ this._normalizeInlineFragment(selection, record, data);
274
275
  break;
275
276
  }
276
277
  case 'TypeDiscriminator': {
@@ -306,10 +307,10 @@ class RelayResponseNormalizer {
306
307
  dataID: RelayModernRecord.getDataID(record),
307
308
  fieldKey,
308
309
  handle: selection.handle,
309
- handleKey,
310
310
  handleArgs: selection.handleArgs
311
311
  ? getArgumentValues(selection.handleArgs, this._variables)
312
312
  : {},
313
+ handleKey,
313
314
  });
314
315
  break;
315
316
  case 'ModuleImport':
@@ -340,15 +341,21 @@ class RelayResponseNormalizer {
340
341
  case 'RelayLiveResolver':
341
342
  if (!this._useExecTimeResolvers) {
342
343
  this._normalizeResolver(selection, record, data);
344
+ } else if (selection.resolverInfo?.rootFragment != null) {
345
+ this._collectS2CExecution(selection, record);
343
346
  }
344
347
  break;
345
348
  case 'ClientEdgeToClientObject':
346
349
  if (!this._useExecTimeResolvers) {
347
350
  this._normalizeResolver(selection.backingField, record, data);
351
+ } else if (
352
+ selection.backingField.resolverInfo?.rootFragment != null
353
+ ) {
354
+ this._collectS2CExecution(selection, record);
348
355
  }
349
356
  break;
350
357
  default:
351
- (selection: empty);
358
+ selection as empty;
352
359
  invariant(
353
360
  false,
354
361
  'RelayResponseNormalizer(): Unexpected ast kind `%s`.',
@@ -358,14 +365,73 @@ class RelayResponseNormalizer {
358
365
  }
359
366
  }
360
367
 
368
+ _normalizeInlineFragment(
369
+ selection: NormalizationInlineFragment,
370
+ record: Record,
371
+ data: PayloadData,
372
+ ) {
373
+ const {abstractKey} = selection;
374
+ if (abstractKey == null) {
375
+ const typeName = RelayModernRecord.getType(record);
376
+ if (
377
+ typeName === selection.type ||
378
+ // The root record type is a special `__Root` type and may not match the
379
+ // type on the ast, so ignore type mismatches at the root. We currently
380
+ // detect whether we're at the root by checking against ROOT_ID, but this
381
+ // does not work for mutations/subscriptions which generate unique root
382
+ // ids. This is acceptable in practice as we don't read data for
383
+ // mutations/subscriptions in a situation where we would use
384
+ // isMissingData to decide whether to suspend or not.
385
+ // TODO T96653810: Correctly detect reading from root of mutation/subscription
386
+ typeName === ROOT_TYPE
387
+ ) {
388
+ this._traverseSelections(selection, record, data);
389
+ }
390
+ } else {
391
+ // $FlowFixMe[method-unbinding] - data could be prototype less
392
+ const implementsInterface = Object.prototype.hasOwnProperty.call(
393
+ data,
394
+ abstractKey,
395
+ );
396
+ const typeName = RelayModernRecord.getType(record);
397
+ const typeID = generateTypeID(typeName);
398
+ let typeRecord = this._recordSource.get(typeID);
399
+ if (typeRecord == null) {
400
+ typeRecord = RelayModernRecord.create(typeID, TYPE_SCHEMA_TYPE);
401
+ this._recordSource.set(typeID, typeRecord);
402
+ }
403
+ RelayModernRecord.setValue(typeRecord, abstractKey, implementsInterface);
404
+ if (implementsInterface) {
405
+ this._traverseSelections(selection, record, data);
406
+ }
407
+ }
408
+ }
409
+
361
410
  _normalizeResolver(
362
411
  resolver: NormalizationResolverField | NormalizationLiveResolverField,
363
412
  record: Record,
364
413
  data: PayloadData,
365
414
  ) {
366
415
  if (resolver.fragment != null) {
367
- this._traverseSelections(resolver.fragment, record, data);
416
+ this._normalizeInlineFragment(resolver.fragment, record, data);
417
+ }
418
+ }
419
+
420
+ _collectS2CExecution(
421
+ selection:
422
+ | NormalizationClientEdgeToClientObject
423
+ | NormalizationLiveResolverField
424
+ | NormalizationResolverField,
425
+ record: Record,
426
+ ): void {
427
+ const recordID = RelayModernRecord.getDataID(record);
428
+ const typeName = RelayModernRecord.getType(record);
429
+ let entry = this._s2cExecutions.get(recordID);
430
+ if (entry == null) {
431
+ entry = {selections: [], typeName};
432
+ this._s2cExecutions.set(recordID, entry);
368
433
  }
434
+ entry.selections.push(selection);
369
435
  }
370
436
 
371
437
  _normalizeDefer(
@@ -390,8 +456,9 @@ class RelayResponseNormalizer {
390
456
  // Otherwise data *for this selection* should not be present: enqueue
391
457
  // metadata to process the subsequent response chunk.
392
458
  this._incrementalPlaceholders.push({
393
- kind: 'defer',
459
+ actorIdentifier: this._actorIdentifier,
394
460
  data,
461
+ kind: 'defer',
395
462
  label: defer.label,
396
463
  path: [...this._path],
397
464
  selector: createNormalizationSelector(
@@ -400,7 +467,6 @@ class RelayResponseNormalizer {
400
467
  this._variables,
401
468
  ),
402
469
  typeName: RelayModernRecord.getType(record),
403
- actorIdentifier: this._actorIdentifier,
404
470
  });
405
471
  }
406
472
  }
@@ -427,13 +493,13 @@ class RelayResponseNormalizer {
427
493
  // If streaming is enabled, *also* emit metadata to process any
428
494
  // response chunks that may be delivered.
429
495
  this._incrementalPlaceholders.push({
496
+ actorIdentifier: this._actorIdentifier,
430
497
  kind: 'stream',
431
498
  label: stream.label,
432
- path: [...this._path],
433
- parentID: RelayModernRecord.getDataID(record),
434
499
  node: stream,
500
+ parentID: RelayModernRecord.getDataID(record),
501
+ path: [...this._path],
435
502
  variables: this._variables,
436
- actorIdentifier: this._actorIdentifier,
437
503
  });
438
504
  }
439
505
  }
@@ -466,15 +532,15 @@ class RelayResponseNormalizer {
466
532
  );
467
533
  if (operationReference != null) {
468
534
  this._followupPayloads.push({
469
- kind: 'ModuleImportPayload',
535
+ actorIdentifier: this._actorIdentifier,
470
536
  args: moduleImport.args,
471
537
  data,
472
538
  dataID: RelayModernRecord.getDataID(record),
539
+ kind: 'ModuleImportPayload',
473
540
  operationReference,
474
541
  path: [...this._path],
475
542
  typeName,
476
543
  variables: this._variables,
477
- actorIdentifier: this._actorIdentifier,
478
544
  });
479
545
  }
480
546
  }
@@ -508,7 +574,9 @@ class RelayResponseNormalizer {
508
574
  // client is assumed to be correctly configured with
509
575
  // treatMissingFieldsAsNull=true.
510
576
  const isOptionalField =
511
- this._isClientExtension || this._isUnmatchedAbstractType;
577
+ this._isClientExtension ||
578
+ this._isUnmatchedAbstractType ||
579
+ this._deferDeduplicatedFields;
512
580
 
513
581
  if (isOptionalField) {
514
582
  // Field not expected to exist regardless of whether the server is pruning null
@@ -583,7 +651,7 @@ class RelayResponseNormalizer {
583
651
  this._errorTrie = oldErrorTrie;
584
652
  this._path.pop();
585
653
  } else {
586
- (selection: empty);
654
+ selection as empty;
587
655
  invariant(
588
656
  false,
589
657
  'RelayResponseNormalizer(): Unexpected ast kind `%s` during normalization.',
@@ -648,11 +716,11 @@ class RelayResponseNormalizer {
648
716
  return;
649
717
  }
650
718
 
651
- // $FlowFixMe[incompatible-call]
719
+ // $FlowFixMe[incompatible-type]
652
720
  const typeName = field.concreteType ?? this._getRecordType(fieldValue);
653
721
  const nextID =
654
722
  this._getDataId(
655
- // $FlowFixMe[incompatible-call]
723
+ // $FlowFixMe[incompatible-type]
656
724
  fieldValue,
657
725
  typeName,
658
726
  ) ||
@@ -673,14 +741,14 @@ class RelayResponseNormalizer {
673
741
  );
674
742
 
675
743
  this._followupPayloads.push({
676
- kind: 'ActorPayload',
677
- data: (fieldValue: $FlowFixMe),
744
+ actorIdentifier,
745
+ data: fieldValue as $FlowFixMe,
678
746
  dataID: nextID,
747
+ kind: 'ActorPayload',
748
+ node: field,
679
749
  path: [...this._path, responseKey],
680
750
  typeName,
681
751
  variables: this._variables,
682
- node: field,
683
- actorIdentifier,
684
752
  });
685
753
  }
686
754
 
@@ -688,7 +756,7 @@ class RelayResponseNormalizer {
688
756
  field: NormalizationLinkedField,
689
757
  record: Record,
690
758
  storageKey: string,
691
- fieldValue: mixed,
759
+ fieldValue: unknown,
692
760
  ): void {
693
761
  invariant(
694
762
  typeof fieldValue === 'object' && fieldValue,
@@ -733,7 +801,7 @@ class RelayResponseNormalizer {
733
801
  field: NormalizationLinkedField,
734
802
  record: Record,
735
803
  storageKey: string,
736
- fieldValue: mixed,
804
+ fieldValue: unknown,
737
805
  ): void {
738
806
  invariant(
739
807
  Array.isArray(fieldValue),
@@ -823,8 +891,8 @@ class RelayResponseNormalizer {
823
891
  if (!expected) {
824
892
  const logEvent: IdCollisionTypenameLogEvent = {
825
893
  name: 'idCollision.typename',
826
- previous_typename: RelayModernRecord.getType(record),
827
894
  new_typename: typeName,
895
+ previous_typename: RelayModernRecord.getType(record),
828
896
  };
829
897
  if (this._log != null) {
830
898
  this._log(logEvent);
@@ -858,7 +926,7 @@ class RelayResponseNormalizer {
858
926
  _validateConflictingFieldsWithIdenticalId(
859
927
  record: Record,
860
928
  storageKey: string,
861
- fieldValue: mixed,
929
+ fieldValue: unknown,
862
930
  ): void {
863
931
  // NOTE: Only emit a warning in DEV
864
932
  if (__DEV__) {
@@ -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;
@@ -59,9 +63,17 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
59
63
  snapshot: Snapshot,
60
64
  callback: (snapshot: Snapshot) => void,
61
65
  ): Disposable {
62
- const subscription = {backup: null, callback, snapshot, stale: false};
66
+ const subscription: Subscription = {
67
+ backup: null,
68
+ callback,
69
+ snapshot,
70
+ stale: false,
71
+ };
63
72
  const dispose = () => {
64
73
  this._subscriptions.delete(subscription);
74
+ if (RelayFeatureFlags.OPTIMIZE_NOTIFY && subscription.stale) {
75
+ this._staleSubscriptions.delete(subscription);
76
+ }
65
77
  };
66
78
  this._subscriptions.add(subscription);
67
79
  return {dispose};
@@ -89,11 +101,12 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
89
101
  const backup = RelayReader.read(
90
102
  source,
91
103
  snapshot.selector,
104
+ this.__log,
92
105
  this._resolverCache,
93
106
  this._resolverContext,
94
107
  );
95
108
  const nextData = recycleNodesInto(snapshot.data, backup.data);
96
- (backup: $FlowFixMe).data = nextData; // backup owns the snapshot and can safely mutate
109
+ (backup as $FlowFixMe).data = nextData; // backup owns the snapshot and can safely mutate
97
110
  subscription.backup = backup;
98
111
  });
99
112
  }
@@ -107,20 +120,26 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
107
120
  // This subscription's data changed in the optimistic state. We will
108
121
  // need to re-read.
109
122
  subscription.stale = true;
123
+ if (RelayFeatureFlags.OPTIMIZE_NOTIFY) {
124
+ this._staleSubscriptions.add(subscription);
125
+ }
110
126
  }
111
127
  subscription.snapshot = {
112
128
  data: subscription.snapshot.data,
129
+ fieldErrors: backup.fieldErrors,
113
130
  isMissingData: backup.isMissingData,
114
131
  missingClientEdges: backup.missingClientEdges,
115
132
  missingLiveResolverFields: backup.missingLiveResolverFields,
116
133
  seenRecords: backup.seenRecords,
117
134
  selector: backup.selector,
118
- fieldErrors: backup.fieldErrors,
119
135
  };
120
136
  } else {
121
137
  // This subscription was created during the optimisitic state. We should
122
138
  // re-read.
123
139
  subscription.stale = true;
140
+ if (RelayFeatureFlags.OPTIMIZE_NOTIFY) {
141
+ this._staleSubscriptions.add(subscription);
142
+ }
124
143
  }
125
144
  });
126
145
  }
@@ -146,6 +165,27 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
146
165
  });
147
166
  }
148
167
 
168
+ updateStaleSubscriptions(
169
+ source: RecordSource,
170
+ updatedRecordIDs: DataIDSet,
171
+ updatedOwners: Array<RequestDescriptor>,
172
+ sourceOperation?: OperationDescriptor,
173
+ ) {
174
+ const hasUpdatedRecords = updatedRecordIDs.size !== 0;
175
+ this._staleSubscriptions.forEach(subscription => {
176
+ const owner = this._updateSubscription(
177
+ source,
178
+ subscription,
179
+ updatedRecordIDs,
180
+ hasUpdatedRecords,
181
+ sourceOperation,
182
+ );
183
+ if (owner != null) {
184
+ updatedOwners.push(owner);
185
+ }
186
+ });
187
+ }
188
+
149
189
  /**
150
190
  * Notifies the callback for the subscription if the data for the associated
151
191
  * snapshot has changed.
@@ -173,32 +213,36 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
173
213
  ? RelayReader.read(
174
214
  source,
175
215
  snapshot.selector,
216
+ this.__log,
176
217
  this._resolverCache,
177
218
  this._resolverContext,
178
219
  )
179
220
  : backup;
180
221
  const nextData = recycleNodesInto(snapshot.data, nextSnapshot.data);
181
- nextSnapshot = ({
222
+ nextSnapshot = {
182
223
  data: nextData,
224
+ fieldErrors: nextSnapshot.fieldErrors,
183
225
  isMissingData: nextSnapshot.isMissingData,
184
226
  missingClientEdges: nextSnapshot.missingClientEdges,
185
227
  missingLiveResolverFields: nextSnapshot.missingLiveResolverFields,
186
228
  seenRecords: nextSnapshot.seenRecords,
187
229
  selector: nextSnapshot.selector,
188
- fieldErrors: nextSnapshot.fieldErrors,
189
- }: Snapshot);
230
+ } as Snapshot;
190
231
  if (__DEV__) {
191
232
  deepFreeze(nextSnapshot);
192
233
  }
193
234
  subscription.snapshot = nextSnapshot;
194
235
  subscription.stale = false;
236
+ if (RelayFeatureFlags.OPTIMIZE_NOTIFY && stale) {
237
+ this._staleSubscriptions.delete(subscription);
238
+ }
195
239
  if (nextSnapshot.data !== snapshot.data) {
196
240
  if (this.__log && RelayFeatureFlags.ENABLE_NOTIFY_SUBSCRIPTION) {
197
241
  this.__log({
198
242
  name: 'store.notify.subscription',
199
- sourceOperation,
200
- snapshot,
201
243
  nextSnapshot,
244
+ snapshot,
245
+ sourceOperation,
202
246
  });
203
247
  }
204
248
  callback(nextSnapshot);