diff --git a/types/react-relay/classic.d.ts b/types/react-relay/classic.d.ts deleted file mode 100644 index ab1ed1b287..0000000000 --- a/types/react-relay/classic.d.ts +++ /dev/null @@ -1,223 +0,0 @@ -import * as React from 'react'; -import * as RelayRuntimeTypes from 'relay-runtime'; - -// ~~~~~~~~~~~~~~~~~~~~~ -// Maybe Fix -// ~~~~~~~~~~~~~~~~~~~~~ -export type StoreReaderData = any; -export type StoreReaderOptions = any; -export type RelayStoreData = any; -export interface RelayQuery { - Fragment: any; - Node: any; - Root: any; -} - -// ~~~~~~~~~~~~~~~~~~~~~ -// Environment -// ~~~~~~~~~~~~~~~~~~~~~ -export interface FragmentResolver { - dispose(): void; - resolve( - fragment: RelayQuery['Fragment'], - dataIDs: RelayRuntimeTypes.DataID | RelayRuntimeTypes.DataID[] - ): StoreReaderData | StoreReaderData[] | undefined | null; -} - -export interface RelayEnvironmentInterface { - forceFetch( - querySet: RelayRuntimeTypes.RelayQuerySet, - onReadyStateChange: RelayRuntimeTypes.ReadyStateChangeCallback - ): RelayRuntimeTypes.Abortable; - getFragmentResolver(fragment: RelayQuery['Fragment'], onNext: () => void): FragmentResolver; - getStoreData(): RelayStoreData; - primeCache( - querySet: RelayRuntimeTypes.RelayQuerySet, - onReadyStateChange: RelayRuntimeTypes.ReadyStateChangeCallback - ): RelayRuntimeTypes.Abortable; - read( - node: RelayQuery['Node'], - dataID: RelayRuntimeTypes.DataID, - options?: StoreReaderOptions - ): StoreReaderData | void; - readQuery(root: RelayQuery['Root'], options?: StoreReaderOptions): StoreReaderData[] | void; -} - -// ~~~~~~~~~~~~~~~~~~~~~ -// the rest is to match pre-existing types from before v1 -// ~~~~~~~~~~~~~~~~~~~~~ -export type ClientMutationID = string; - -/** Fragments are a hash of functions */ -export interface Fragments { - [query: string]: (variables?: RelayVariables) => string; -} - -export interface CreateContainerOpts { - initialVariables?: any; - fragments: Fragments; - prepareVariables?(prevVariables: RelayVariables): RelayVariables; -} - -export interface RelayVariables { - [name: string]: any; -} - -/** add static getFragment method to the component constructor */ -export interface RelayContainerClass extends React.ComponentClass { - getFragment: (q: string, v?: RelayVariables) => string; -} - -export interface RelayQueryRequestResolve { - response: any; -} - -export type RelayMutationStatus = - | 'UNCOMMITTED' // Transaction hasn't yet been sent to the server. Transaction can be committed or rolled back. - | 'COMMIT_QUEUED' // Transaction was committed but another transaction with the same collision key is pending, so the transaction has been queued to send to the server. - | 'COLLISION_COMMIT_FAILED' // Transaction was queued for commit but another transaction with the same collision key failed. All transactions in the collision queue, - // including this one, have been failed. Transaction can be recommitted or rolled back. - | 'COMMITTING' // Transaction is waiting for the server to respond. - | 'COMMIT_FAILED'; - -export class RelayMutationTransaction { - applyOptimistic(): RelayMutationTransaction; - commit(): RelayMutationTransaction | null; - recommit(): void; - rollback(): void; - getError(): Error; - getStatus(): RelayMutationStatus; - getHash(): string; - getID(): ClientMutationID; -} - -export interface RelayMutationRequest { - getQueryString(): string; - getVariables(): RelayVariables; - resolve(result: RelayQueryRequestResolve): any; - reject(errors: any): any; -} - -export interface RelayQueryRequest { - resolve(result: RelayQueryRequestResolve): any; - reject(errors: any): any; - getQueryString(): string; - getVariables(): RelayVariables; - getID(): string; - getDebugName(): string; -} - -export interface RelayNetworkLayer { - supports(...options: string[]): boolean; -} - -export class DefaultNetworkLayer implements RelayNetworkLayer { - constructor(host: string, options?: any); - supports(...options: string[]): boolean; -} - -export function createContainer( - component: React.ComponentType, - params?: CreateContainerOpts -): RelayContainerClass; -export function injectNetworkLayer(networkLayer: RelayNetworkLayer): any; -export function isContainer(component: React.ComponentClass): boolean; -export function QL(...args: any[]): string; - -export class Route { - constructor(params?: RelayVariables); -} - -/** - * Relay Mutation class, where T are the props it takes and S is the returned payload from Relay.Store.update. - * S is typically dynamic as it depends on the data the app is currently using, but it's possible to always - * return some data in the payload using REQUIRED_CHILDREN which is where specifying S is the most useful. - */ -export class Mutation { - props: T; - - constructor(props: T); - static getFragment(q: string): string; -} - -export interface Transaction { - getError(): Error; - Status(): number; -} - -export interface StoreUpdateCallbacks { - onFailure?(transaction: Transaction): any; - onSuccess?(response: T): any; -} - -export interface Store { - commitUpdate(mutation: Mutation, callbacks?: StoreUpdateCallbacks): any; -} - -export const Store: Store; - -export class RootContainer extends React.Component {} - -export interface RootContainerProps extends React.Props { - Component: RelayContainerClass; - route: Route; - renderLoading?(): JSX.Element; - renderFetched?(data: any): JSX.Element; - renderFailure?(error: Error, retry: (...args: any[]) => any): JSX.Element; -} - -export class Renderer extends React.Component {} - -export interface RendererProps { - Container: RelayContainerClass; // Relay container that defines fragments and the view to render. - forceFetch?: boolean; // Whether to send a server request regardless of data available on the client. - queryConfig: Route; // `QueryConfig` or `Relay.Route` that defines the query roots. - environment: Store; // An instance of `Relay.Environment` or any object that implements the `RelayEnvironment` interface. - render?: RenderCallback; // Called to render when data requirements are being fulfilled. - onReadyStateChange?: OnReadyStateChange; -} - -export interface RenderStateConfig { - props?: { [propName: string]: any }; - done: boolean; - error?: Error; - retry?(): void; - stale: boolean; -} -export type RenderCallback = (renderState: RenderStateConfig) => any; - -export type ReadyStateEvent = - | 'ABORT' - | 'CACHE_RESTORED_REQUIRED' - | 'CACHE_RESTORE_FAILED' - | 'CACHE_RESTORE_START' - | 'NETWORK_QUERY_ERROR' - | 'NETWORK_QUERY_RECEIVED_ALL' - | 'NETWORK_QUERY_RECEIVED_REQUIRED' - | 'NETWORK_QUERY_START' - | 'STORE_FOUND_ALL' - | 'STORE_FOUND_REQUIRED'; - -export type OnReadyStateChange = (readyState: { - ready: boolean; - done: boolean; - stale: boolean; - error?: Error; - events: ReadyStateEvent[]; - aborted: boolean; -}) => void; - -export interface RelayProp { - readonly route: { name: string }; // incomplete, also has params and queries - readonly variables: V; - readonly pendingVariables?: V; - setVariables(variables: V, onReadyStateChange?: OnReadyStateChange): void; - forceFetch(variables: V, onReadyStateChange?: OnReadyStateChange): void; - hasOptimisticUpdate(record: any): boolean; - getPendingTransactions(record: any): RelayMutationTransaction[]; - commitUpdate(mutation: Mutation, callbacks?: StoreUpdateCallbacks): any; -} - -export interface RelayProps { - readonly relay: RelayProp; -} diff --git a/types/react-relay/compat.d.ts b/types/react-relay/compat.d.ts deleted file mode 100644 index 6a92fc9396..0000000000 --- a/types/react-relay/compat.d.ts +++ /dev/null @@ -1,85 +0,0 @@ -export { QueryRenderer, fetchQuery, graphql } from './index'; -import { - ConnectionConfig, - RelayPaginationProp as RelayModernPaginationProp, - RelayRefetchProp as RelayModernRefetchProp, -} from './index'; -export { ConcreteFragment, ConcreteRequest, ConcreteBatchRequest } from 'relay-runtime'; -import * as RelayRuntimeTypes from 'relay-runtime'; -import { RelayEnvironmentInterface } from './classic'; - -// ~~~~~~~~~~~~~~~~~~~~~ -// Maybe Fix -// ~~~~~~~~~~~~~~~~~~~~~ -export type ConcreteFragmentDefinition = object; -export type ConcreteOperationDefinition = object; - -// ~~~~~~~~~~~~~~~~~~~~~ -// Util -// ~~~~~~~~~~~~~~~~~~~~~ -export function getFragment(q: string, v?: RelayRuntimeTypes.Variables): string; -export interface ComponentWithFragment extends React.ComponentClass { - getFragment: typeof getFragment; -} -export interface StatelessWithFragment extends React.StatelessComponent { - getFragment: typeof getFragment; -} -export type ReactFragmentComponent = ComponentWithFragment | StatelessWithFragment; -export type RelayClassicEnvironment = RelayEnvironmentInterface; - -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayCompatTypes -// ~~~~~~~~~~~~~~~~~~~~~ -export type CompatEnvironment = RelayRuntimeTypes.Environment | RelayClassicEnvironment; - -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayProps -// ~~~~~~~~~~~~~~~~~~~~~ -export interface RelayProp { - environment: CompatEnvironment; -} - -export type RelayPaginationProp = RelayModernPaginationProp & RelayProp; -export type RelayRefetchProp = RelayModernRefetchProp & RelayProp; - -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayCompatMutations -// ~~~~~~~~~~~~~~~~~~~~~ -export function commitMutation( - environment: CompatEnvironment, - config: RelayRuntimeTypes.MutationConfig -): RelayRuntimeTypes.Disposable; -export function applyOptimisticMutation( - environment: CompatEnvironment, - config: RelayRuntimeTypes.OptimisticMutationConfig -): RelayRuntimeTypes.Disposable; - -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayCompatContainers -// ~~~~~~~~~~~~~~~~~~~~~ -export interface GeneratedNodeMap { - [key: string]: RelayRuntimeTypes.GraphQLTaggedNode; -} - -export function createFragmentContainer( - Component: React.ComponentType, - fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap -): ReactFragmentComponent; - -export function createRefetchContainer( - Component: React.ComponentType, - fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap, - taggedNode: RelayRuntimeTypes.GraphQLTaggedNode -): ReactFragmentComponent; - -export function createPaginationContainer( - Component: React.ComponentType, - fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap, - connectionConfig: ConnectionConfig -): ReactFragmentComponent; - -// ~~~~~~~~~~~~~~~~~~~~~ -// injectDefaultVariablesProvider -// ~~~~~~~~~~~~~~~~~~~~~ -export type VariablesProvider = () => RelayRuntimeTypes.Variables; -export function injectDefaultVariablesProvider(variablesProvider: VariablesProvider): void; diff --git a/types/react-relay/index.d.ts b/types/react-relay/index.d.ts index d02a399412..fc0c190bd1 100644 --- a/types/react-relay/index.d.ts +++ b/types/react-relay/index.d.ts @@ -1,4 +1,4 @@ -// Type definitions for react-relay 1.3 +// Type definitions for react-relay 4.0 // Project: https://github.com/facebook/relay, https://facebook.github.io/relay // Definitions by: Johannes Schickling // Matt Martin @@ -8,26 +8,61 @@ // Kaare Hoff Skovgaard // Matt Krick // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.9 - -// Prettified with: -// $ prettier --parser typescript --tab-width 4 --semi --trailing-comma es5 --write --print-width 120 \ -// types/{react-relay,relay-runtime}/{,*}/*.ts* - -export { - commitLocalUpdate, - commitRelayModernMutation as commitMutation, - fetchRelayModernQuery as fetchQuery, - GraphQLTaggedNode, - requestRelaySubscription as requestSubscription, -} from 'relay-runtime'; +// TypeScript Version: 3.0 import * as React from 'react'; -import * as RelayRuntimeTypes from 'relay-runtime'; +import { + Environment, + Variables, + Disposable, + Observer, + CacheConfig, + GraphQLTaggedNode, + RelayContext, + PageInfo, + OperationType, +} from 'relay-runtime'; -// ~~~~~~~~~~~~~~~~~~~~~ -// Utility types -// ~~~~~~~~~~~~~~~~~~~~~ +// ./ReactRelayTypes +export interface RelayProp { + environment: Environment; + refetch: undefined; // ensures no RelayRefetchProp is used with a fragment container + hasMore: undefined; // ensures no RelayPaginationProp is used with a fragment container +} + +export interface RelayRefetchProp { + environment: Environment; + refetch: ( + refetchVariables: Variables | ((fragmentVariables: Variables) => Variables), + renderVariables?: Variables | null, + observerOrCallback?: ObserverOrCallback | null, + options?: RefetchOptions + ) => Disposable; + hasMore: undefined; // ensures no RelayPaginationProp is used with a refetch container +} +export interface RefetchOptions { + force?: boolean; + fetchPolicy?: 'store-or-network' | 'network-only'; +} + +type ObserverOrCallback = Observer | ((error: Error | null | undefined) => void); + +export interface RelayPaginationProp { + readonly environment: Environment; + readonly hasMore: () => boolean; + readonly isLoading: () => boolean; + readonly loadMore: ( + pageSize: number, + observerOrCallback?: ObserverOrCallback | null, + options?: RefetchOptions | null + ) => Disposable | null | undefined; + readonly refetchConnection: ( + totalCount: number, + observerOrCallback?: ObserverOrCallback | null, + refetchVariables?: Variables | null + ) => Disposable | null | undefined; + refetch: undefined; // ensures no RelayRefetchProp is used with a pagination container +} export interface _RefType { ' $refType': T; @@ -42,160 +77,99 @@ export type FragmentOrRegularProp = T extends _RefType ? ReadonlyArray<_FragmentRefs> : T; -export type MappedFragmentProps = { [K in keyof T]: FragmentOrRegularProp }; +export type MappedFragmentProps = { + [K in keyof T]: FragmentOrRegularProp; +}; -export type RemoveRelayProp

= Pick>; +export { + DataID, + DeclarativeMutationConfig, + Disposable, + Environment, + GraphQLTaggedNode, + MutationType, + NormalizationSelector, + OperationDescriptor, + RangeOperation, + ReaderSelector, + RelayContext, + Snapshot, + Variables, + MutationTypes, + RangeOperations, + applyOptimisticMutation, + commitLocalUpdate, + commitMutation, + fetchQuery, + graphql, + requestSubscription, +} from 'relay-runtime'; -export interface ComponentRef { - componentRef?: (ref: any) => void; +export type DataFrom = 'NETWORK_ONLY' | 'STORE_THEN_NETWORK'; +declare class ReactRelayQueryRenderer extends React.Component<{ + cacheConfig?: CacheConfig | null; + dataFrom?: DataFrom; + environment: Environment; + query: GraphQLTaggedNode | null | undefined; + render: (renderProps: { + error: Error | null; + props: TOperation['response'] | null; + retry: (() => void) | null; + }) => React.ReactNode; + variables: TOperation['variables']; +}> {} +export { ReactRelayQueryRenderer as QueryRenderer }; + +export const ReactRelayContext: React.Context; + +interface GeneratedNodeMap { + [key: string]: GraphQLTaggedNode; } -export type RelayContainer

= React.ComponentType> & ComponentRef>; +export type ContainerProps = MappedFragmentProps>>; -// ~~~~~~~~~~~~~~~~~~~~~ -// Maybe Fix -// ~~~~~~~~~~~~~~~~~~~~~ -export type ConcreteFragmentDefinition = object; -export type ConcreteOperationDefinition = object; +export type Container = React.ComponentType & { componentRef?: (ref: any) => void }>; -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayProp -// ~~~~~~~~~~~~~~~~~~~~~ -// note: refetch and pagination containers augment this -export interface RelayProp { - environment: RelayRuntimeTypes.Environment; -} +export function createFragmentContainer( + Component: React.ComponentType, + fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap +): Container; -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayQL -// ~~~~~~~~~~~~~~~~~~~~~ -export function RelayQL(strings: string[], ...substitutions: any[]): RelayRuntimeTypes.RelayConcreteNode; - -// ~~~~~~~~~~~~~~~~~~~~~ -// ReactRelayTypes -// ~~~~~~~~~~~~~~~~~~~~~ -export interface GeneratedNodeMap { - [key: string]: RelayRuntimeTypes.GraphQLTaggedNode; -} - -/** - * Runtime function to correspond to the `graphql` tagged template function. - * All calls to this function should be transformed by the plugin. - */ -export interface GraphqlInterface { - (strings: string[] | TemplateStringsArray): RelayRuntimeTypes.GraphQLTaggedNode; - experimental(strings: string[] | TemplateStringsArray): RelayRuntimeTypes.GraphQLTaggedNode; -} -export const graphql: GraphqlInterface; - -// ~~~~~~~~~~~~~~~~~~~~~ -// ReactRelayQueryRenderer -// ~~~~~~~~~~~~~~~~~~~~~ - -export interface QueryRendererProps { - cacheConfig?: RelayRuntimeTypes.CacheConfig; - dataFrom?: 'NETWORK_ONLY' | 'STORE_THEN_NETWORK'; - environment: RelayRuntimeTypes.Environment; - query?: RelayRuntimeTypes.GraphQLTaggedNode | null; - render(readyState: ReadyState): React.ReactNode; - variables: T['variables']; - rerunParamExperimental?: RelayRuntimeTypes.RerunParam; -} -export interface ReadyState { - error: Error | undefined | null; - props: T | undefined | null; - retry?(): void; -} - -export class ReactRelayQueryRenderer extends React.Component< - QueryRendererProps -> {} -export class QueryRenderer< - T extends RelayRuntimeTypes.OperationBase = RelayRuntimeTypes.OperationDefaults -> extends ReactRelayQueryRenderer {} - -// ~~~~~~~~~~~~~~~~~~~~~ -// createFragmentContainer -// ~~~~~~~~~~~~~~~~~~~~~ - -export function createFragmentContainer

( - Component: React.ComponentType

, - fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap -): RelayContainer

; - -// ~~~~~~~~~~~~~~~~~~~~~ -// createPaginationContainer -// ~~~~~~~~~~~~~~~~~~~~~ -export interface PageInfo { - endCursor: string | undefined | null; - hasNextPage: boolean; - hasPreviousPage: boolean; - startCursor: string | undefined | null; -} -export interface ConnectionData { - edges?: ReadonlyArray; +interface ConnectionData { + edges?: ReadonlyArray | null; pageInfo?: Partial | null; } -export type RelayPaginationProp = RelayProp & { - hasMore(): boolean; - isLoading(): boolean; - loadMore( - pageSize: number, - callback?: ((error?: Error) => void) | null, - options?: RefetchOptions - ): RelayRuntimeTypes.Disposable | undefined | null; - refetchConnection( - totalCount: number, - callback: (error?: Error) => void, - refetchVariables?: RelayRuntimeTypes.Variables - ): RelayRuntimeTypes.Disposable | undefined | null; -}; -export function FragmentVariablesGetter( - prevVars: RelayRuntimeTypes.Variables, - totalCount: number -): RelayRuntimeTypes.Variables; -export interface ConnectionConfig

{ + +type FragmentVariablesGetter = (prevVars: Variables, totalCount: number) => Variables; + +export interface ConnectionConfig { direction?: 'backward' | 'forward'; - getConnectionFromProps?(props: P): ConnectionData | undefined | null; - getFragmentVariables?: typeof FragmentVariablesGetter; - getVariables( - props: { [propName: string]: any }, - paginationInfo: { count: number; cursor?: string }, - fragmentVariables: RelayRuntimeTypes.Variables - ): RelayRuntimeTypes.Variables; - query: RelayRuntimeTypes.GraphQLTaggedNode; + getConnectionFromProps?: (props: Props) => ConnectionData | null | undefined; + getFragmentVariables?: FragmentVariablesGetter; + getVariables: ( + props: Props, + paginationInfo: { count: number; cursor?: string | null }, + fragmentVariables: Variables + ) => Variables; + query: GraphQLTaggedNode; } -export function createPaginationContainer

( - Component: React.ComponentType

, - fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap, - connectionConfig: ConnectionConfig

-): RelayContainer

; -// ~~~~~~~~~~~~~~~~~~~~~ -// createRefetchContainer -// ~~~~~~~~~~~~~~~~~~~~~ -export interface RefetchOptions { - force?: boolean; - rerunParamExperimental?: RelayRuntimeTypes.RerunParam; -} -export type RelayRefetchProp = RelayProp & { - refetch( - refetchVariables: - | RelayRuntimeTypes.Variables - | ((fragmentVariables: RelayRuntimeTypes.Variables) => RelayRuntimeTypes.Variables), - renderVariables?: RelayRuntimeTypes.Variables, - callback?: (error?: Error) => void, - options?: RefetchOptions - ): RelayRuntimeTypes.Disposable; -}; -export function createRefetchContainer

( - Component: React.ComponentType

, - fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap, - taggedNode: RelayRuntimeTypes.GraphQLTaggedNode -): RelayContainer

; +export function createPaginationContainer( + Component: React.ComponentType< + Props & { + relay: RelayPaginationProp; + } + >, + fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap, + connectionConfig: ConnectionConfig +): Container; -// ~~~~~~~~~~~~~~~~~~~~~ -// Context -// ~~~~~~~~~~~~~~~~~~~~~ - -export const ReactRelayContext: React.Context>; +export function createRefetchContainer( + Component: React.ComponentType< + Props & { + relay: RelayRefetchProp; + } + >, + fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap, + taggedNode: GraphQLTaggedNode +): Container; diff --git a/types/react-relay/test/react-relay-classic-tests.tsx b/types/react-relay/test/react-relay-classic-tests.tsx deleted file mode 100644 index be1a741b13..0000000000 --- a/types/react-relay/test/react-relay-classic-tests.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import * as React from 'react'; -import * as Relay from 'react-relay/classic'; - -import { CompatContainer } from './react-relay-compat-tests'; - -interface Props { - text: string; - userId: string; -} - -export default class AddTweetMutation extends Relay.Mutation { - getMutation() { - return Relay.QL`mutation{addTweet}`; - } - - getFatQuery() { - return Relay.QL` - fragment on AddTweetPayload { - tweetEdge - user - } - `; - } - - getConfigs() { - return [ - { - type: 'RANGE_ADD', - parentName: 'user', - parentID: this.props.userId, - connectionName: 'tweets', - edgeName: 'tweetEdge', - rangeBehaviors: { - '': 'append', - }, - }, - ]; - } - - getVariables() { - return this.props; - } -} - -interface ArtwokRelayVariables { - artworkID: string; -} - -interface ArtworkProps extends Relay.RelayProps { - artwork: { - title: string; - }; -} - -class Artwork extends React.Component { - render() { - return {this.props.artwork.title}; - } -} - -const ArtworkContainer = Relay.createContainer(Artwork, { - fragments: { - artwork: () => Relay.QL` - fragment on Artwork { - title - ${CompatContainer.getFragment('whatever')} - } - `, - }, -}); - -class StubbedArtwork extends React.Component { - render() { - const props = { - artwork: { title: 'CHAMPAGNE FORMICA FLAG' }, - relay: { - route: { - name: 'champagne', - }, - variables: { - artworkID: 'champagne-formica-flag', - }, - setVariables: () => {}, - forceFetch: () => {}, - hasOptimisticUpdate: () => false, - getPendingTransactions: (): any => undefined, - commitUpdate: () => {}, - }, - }; - return ; - } -} diff --git a/types/react-relay/test/react-relay-compat-tests.tsx b/types/react-relay/test/react-relay-compat-tests.tsx deleted file mode 100644 index e70b5624d9..0000000000 --- a/types/react-relay/test/react-relay-compat-tests.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import * as React from 'react'; -import { - QueryRenderer as CompatQueryRenderer, - createFragmentContainer as createFragmentContainerCompat, - commitMutation as commitMutationCompat, - CompatEnvironment, - RelayPaginationProp as RelayPaginationPropCompat, -} from 'react-relay/compat'; - -import { configs, mutation, optimisticResponse } from './react-relay-tests'; - -// testting compat mutation with classic environment -function markNotificationAsReadCompat(environment: CompatEnvironment, source: string, storyID: string) { - const variables = { - input: { - source, - storyID, - }, - }; - - commitMutationCompat(environment, { - configs, - mutation, - optimisticResponse, - variables, - onCompleted: (response, errors) => { - console.log('Response received from server.'); - }, - onError: err => console.error(err), - updater: (store, data) => { - const field = store.get(storyID); - if (field) { - field.setValue(data.story, 'story'); - } - }, - }); -} - -interface CompatProps { - relay: RelayPaginationPropCompat; -} - -class CompatComponent extends React.Component { - markNotificationAsRead(source: string, storyID: string) { - markNotificationAsReadCompat(this.props.relay.environment, source, storyID); - } - - render() { - return

; - } -} - -export const CompatContainer = createFragmentContainerCompat(CompatComponent, {}); diff --git a/types/react-relay/test/react-relay-tests.tsx b/types/react-relay/test/react-relay-tests.tsx index 58cd39a612..f18199e7e3 100644 --- a/types/react-relay/test/react-relay-tests.tsx +++ b/types/react-relay/test/react-relay-tests.tsx @@ -1,4 +1,5 @@ // tslint:disable:interface-over-type-literal +// tslint:disable:use-default-type-parameter import * as React from 'react'; import { Environment, Network, RecordSource, Store, ConnectionHandler } from 'relay-runtime'; @@ -21,7 +22,7 @@ import { // Modern Environment // ~~~~~~~~~~~~~~~~~~~~~ function fetchQuery(operation: any, variables: any, cacheConfig: {}) { - return fetch('/graphql'); + return fetch('/graphql').then(response => response.json()); } const network = Network.create(fetchQuery); const source = new RecordSource(); @@ -76,7 +77,7 @@ const MyEmptyQueryRenderer = () => ( { if (error) { @@ -161,7 +162,7 @@ const Story = (() => { } `, }, - graphql.experimental` + graphql` query StoryRefetchQuery($id: ID!) { story(id: $id) { ...Story_story @@ -170,12 +171,58 @@ const Story = (() => { ` ); - function doesNotRequireRelayPropToBeProvided() { + function requiresTheRightProps() { const onLike = (id: string) => console.log(`Liked story #${id}`); const story: { ' $fragmentRefs': Story_story$ref } = {} as any; ; } + function requiresTheCorrectFragmentRef() { + const onLike = (id: string) => console.log(`Liked story #${id}`); + const feed: { ' $fragmentRefs': FeedStories_feed$ref } = {} as any; + // $ExpectError + ; + } + + function doesNotRequireRelayPropToBeProvidedByParent() { + const onLike = (id: string) => console.log(`Liked story #${id}`); + const story: { ' $fragmentRefs': Story_story$ref } = {} as any; + const relayProp: RelayRefetchProp = {} as any; + // $ExpectError + ; + } + + function requiresTheRelayPropInPropsInterface() { + // FIXME: This should throw a type error, but doesn't + // const FunctionComponent: React.FC<{}> = () => null; + // // $ExpectError + // createRefetchContainer(FunctionComponent, { story: graphql`` }, graphql``); + + class ClassComponent extends React.Component<{}> {} + // $ExpectError + createRefetchContainer(ClassComponent, { story: graphql`` }, graphql``); + } + + function requiresTheCorrectRelayPropTypeInPropsInterface() { + class ClassComponent1 extends React.Component<{ relay: RelayProp }> {} + // $ExpectError + createRefetchContainer(ClassComponent1, { story: graphql`` }, graphql``); + + class ClassComponent2 extends React.Component<{ relay: RelayPaginationProp }> {} + // $ExpectError + createRefetchContainer(ClassComponent2, { story: graphql`` }, graphql``); + + class ClassComponent3 extends React.Component<{ relay: undefined }> {} + // $ExpectError + createRefetchContainer(ClassComponent3, { story: graphql`` }, graphql``); + } + + function canTakeComponentRef() { + const onLike = (id: string) => console.log(`Liked story #${id}`); + const story: { ' $fragmentRefs': Story_story$ref } = {} as any; + console.log(ref)} />; + } + return StoryRefetchContainer; })(); @@ -211,7 +258,7 @@ const Feed = (() => { ignoreMe?: {}; } - const FeedStoryEdges: React.SFC<{ edges: FeedStory_edges }> = ({ edges }) => ( + const FeedStoryEdges: React.FC<{ edges: FeedStory_edges; relay: RelayProp }> = ({ edges }) => (
{edges.map(({ publishedAt }) => publishedAt).join(', ')}
); @@ -223,7 +270,7 @@ const Feed = (() => { `, }); - const FeedStories: React.SFC = ({ feed, onStoryLike, relay }) => { + const FeedStories: React.FC = ({ feed, onStoryLike, relay }) => { // TODO: Getting env here for no good reason other than needing to test it works. // If you have a good relavant example, please update! relay.environment; @@ -252,12 +299,51 @@ const Feed = (() => { `, }); - function doesNotRequireRelayPropToBeProvided() { + function requiresTheRightProps() { const onStoryLike = (id: string) => console.log(`Liked story #${id}`); const feed: { ' $fragmentRefs': FeedStories_feed$ref } = {} as any; ; } + function requiresTheCorrectFragmentRef() { + const onStoryLike = (id: string) => console.log(`Liked story #${id}`); + const story: { ' $fragmentRefs': Story_story$ref } = {} as any; + // $ExpectError + ; + } + + function doesNotRequireRelayPropToBeProvidedByParent() { + const onStoryLike = (id: string) => console.log(`Liked story #${id}`); + const feed: { ' $fragmentRefs': FeedStories_feed$ref } = {} as any; + const relayProp: RelayProp = {} as any; + // $ExpectError + ; + } + + function doesNotRequireTheRelayPropInPropsInterface() { + const FunctionComponent: React.FC<{}> = () => null; + createFragmentContainer(FunctionComponent, {}); + + class ClassComponent extends React.Component<{}> {} + createFragmentContainer(ClassComponent, {}); + } + + function requiresTheCorrectRelayPropTypeInPropsInterface() { + class ClassComponent1 extends React.Component<{ relay: RelayRefetchProp }> {} + // $ExpectError + createFragmentContainer(ClassComponent1, {}); + + class ClassComponent2 extends React.Component<{ relay: RelayPaginationProp }> {} + // $ExpectError + createFragmentContainer(ClassComponent2, {}); + } + + function canTakeComponentRef() { + const onStoryLike = (id: string) => console.log(`Liked story #${id}`); + const feed: { ' $fragmentRefs': FeedStories_feed$ref } = {} as any; + console.log(ref)} />; + } + return FeedFragmentContainer; })(); @@ -361,10 +447,53 @@ type UserFeed_user = { } ); - function doesNotRequireRelayPropToBeProvided() { + function requiresTheRightProps() { const user: { ' $fragmentRefs': UserFeed_user$ref } = {} as any; ; } + + function requiresTheCorrectFragmentRef() { + const story: { ' $fragmentRefs': Story_story$ref } = {} as any; + // $ExpectError + ; + } + + function doesNotRequireRelayPropToBeProvidedByParent() { + const user: { ' $fragmentRefs': UserFeed_user$ref } = {} as any; + const relayProp: RelayPaginationProp = {} as any; + // $ExpectError + ; + } + + function requiresTheRelayPropInPropsInterface() { + // FIXME: This should throw a type error, but doesn't + // const FunctionComponent: React.FC<{}> = () => null; + // // $ExpectError + // createPaginationContainer(FunctionComponent, {}, {} as any); + + class ClassComponent extends React.Component<{}> {} + // $ExpectError + createPaginationContainer(ClassComponent, {}, {} as any); + } + + function requiresTheCorrectRelayPropTypeInPropsInterface() { + class ClassComponent1 extends React.Component<{ relay: RelayProp }> {} + // $ExpectError + createPaginationContainer(ClassComponent1, {}, {} as any); + + class ClassComponent2 extends React.Component<{ relay: RelayRefetchProp }> {} + // $ExpectError + createPaginationContainer(ClassComponent2, {}, {} as any); + + class ClassComponent3 extends React.Component<{ relay: undefined }> {} + // $ExpectError + createPaginationContainer(ClassComponent3, {}, {} as any); + } + + function canTakeComponentRef() { + const user: { ' $fragmentRefs': UserFeed_user$ref } = {} as any; + console.log(ref)} />; + } }; // ~~~~~~~~~~~~~~~~~~~~~ @@ -492,12 +621,17 @@ requestSubscription( updater: store => { // Get the notification const rootField = store.getRootField('markReadNotification'); - const notification = !!rootField && rootField.getLinkedRecord('notification'); + const notification = !!rootField ? rootField.getLinkedRecord('notification') : null; // Add it to a connection const viewer = store.getRoot().getLinkedRecord('viewer'); - const notifications = ConnectionHandler.getConnection(viewer, 'notifications'); - const edge = ConnectionHandler.createEdge(store, notifications, notification, ''); - ConnectionHandler.insertEdgeAfter(notifications, edge); + const notifications = ConnectionHandler.getConnection(viewer!, 'notifications'); + const edge = ConnectionHandler.createEdge( + store, + notifications!, + notification!, + '' + ); + ConnectionHandler.insertEdgeAfter(notifications!, edge); }, } ); diff --git a/types/react-relay/tsconfig.json b/types/react-relay/tsconfig.json index 642df480df..451f6fbd3e 100644 --- a/types/react-relay/tsconfig.json +++ b/types/react-relay/tsconfig.json @@ -20,10 +20,6 @@ }, "files": [ "index.d.ts", - "classic.d.ts", - "compat.d.ts", - "test/react-relay-tests.tsx", - "test/react-relay-compat-tests.tsx", - "test/react-relay-classic-tests.tsx" + "test/react-relay-tests.tsx" ] } \ No newline at end of file diff --git a/types/react-relay/tslint.json b/types/react-relay/tslint.json index 6a82dd0467..c6c6df5352 100644 --- a/types/react-relay/tslint.json +++ b/types/react-relay/tslint.json @@ -1,7 +1,4 @@ { "extends": "dtslint/dt.json", - "rules": { - // TODO - "no-unnecessary-class": false - } + "rules": {} } diff --git a/types/relay-runtime/index.d.ts b/types/relay-runtime/index.d.ts index 047b87fd84..ddfc17bdb7 100644 --- a/types/relay-runtime/index.d.ts +++ b/types/relay-runtime/index.d.ts @@ -1,318 +1,821 @@ -// Type definitions for relay-runtime 1.3 +// Type definitions for relay-runtime 4.0 // Project: https://github.com/facebook/relay, https://facebook.github.io/relay // Definitions by: Matt Martin // Eloy DurĂ¡n +// Cameron Knight // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.9 +// TypeScript Version: 3.0 -// Prettified with: -// $ prettier --parser typescript --tab-width 4 --semi --trailing-comma es5 --write --print-width 120 \ -// types/{react-relay,relay-runtime}/{,*}/*.ts* - -/** - * SOURCE: - * Relay 1.3.0 - * https://github.com/facebook/relay/blob/b85a1d69bb72be4ace67179f55c2a54a8d761c8b/packages/react-relay/classic/environment/RelayCombinedEnvironmentTypes.js - */ -// ~~~~~~~~~~~~~~~~~~~~~ -// Maybe Fix -// ~~~~~~~~~~~~~~~~~~~~~ -export type RelayConcreteNode = any; -export type RelayMutationTransaction = any; -export type RelayMutationRequest = any; -export type RelayQueryRequest = any; -export type ConcreteFragmentDefinition = object; -export type ConcreteOperationDefinition = object; -export type ReaderFragment = object; - -/** - * FIXME: RelayContainer used to be typed with ReactClass, but - * ReactClass is broken and allows for access to any property. For example - * ReactClass.getFragment('foo') is valid even though ReactClass has no - * such getFragment() type definition. When ReactClass is fixed this causes a - * lot of errors in Relay code since methods like getFragment() are used often - * but have no definition in Relay's types. Suppressing for now. - */ -export type RelayContainer = any; - -// ~~~~~~~~~~~~~~~~~~~~~ -// Used in artifacts -// emitted by -// relay-compiler -// ~~~~~~~~~~~~~~~~~~~~~ - -// File: https://github.com/facebook/relay/blob/fe0e70f10bbcba1fff89911313ea69f24569464b/packages/relay-runtime/util/RelayConcreteNode.js -export type ConcreteFragment = any; -export type ConcreteRequest = any; -export type ConcreteBatchRequest = any; - -export function getRequest(taggedNode: GraphQLTaggedNode): ConcreteRequest; - -export type RequestNode = ConcreteRequest | ConcreteBatchRequest; - -export interface OperationBase { - variables: object; - response: object; -} -export interface OperationDefaults { - variables: Variables; - response: Variables; +// ./handlers/connection/RelayConnectionHandler +export interface ConnectionMetadata { + path: ReadonlyArray | null | undefined; + direction: string | null | undefined; // 'forward' | 'backward' | 'bidirectional' | null | undefined; + cursor: string | null | undefined; + count: string | null | undefined; } -// ~~~~~~~~~~~~~~~~~~~~~ -// Constants -// ~~~~~~~~~~~~~~~~~~~~~ -export const ROOT_ID: string; - -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayQL -// ~~~~~~~~~~~~~~~~~~~~~ -export type RelayQL = (strings: string[], ...substitutions: any[]) => RelayConcreteNode; - -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayModernGraphQLTag -// ~~~~~~~~~~~~~~~~~~~~~ -export interface GeneratedNodeMap { - [key: string]: GraphQLTaggedNode; +// ./handlers/connection/RelayConnectionInterface +export interface Record { + [key: string]: unknown; } -export type GraphQLTaggedNode = - | (() => ConcreteFragment | RequestNode) + +export interface EdgeRecord extends Record { + cursor: unknown; + node: Record; +} + +export interface PageInfo { + endCursor: string | null | undefined; + hasNextPage: boolean; + hasPreviousPage: boolean; + startCursor: string | null | undefined; +} + +// ./mutations/RelayDeclarativeMutationConfig +interface RangeAddConfig { + type: 'RANGE_ADD'; + parentName?: string; + parentID?: string; + connectionInfo?: ReadonlyArray<{ + key: string; + filters?: Variables; + rangeBehavior: string; + }>; + connectionName?: string; + edgeName: string; + rangeBehaviors?: RangeBehaviors; +} + +interface RangeDeleteConfig { + type: 'RANGE_DELETE'; + parentName?: string; + parentID?: string; + connectionKeys?: ReadonlyArray<{ + key: string; + filters?: Variables; + }>; + connectionName?: string; + deletedIDFieldName: string | ReadonlyArray; + pathToConnection: ReadonlyArray; +} + +interface NodeDeleteConfig { + type: 'NODE_DELETE'; + parentName?: string; + parentID?: string; + connectionName?: string; + deletedIDFieldName: string; +} + +// Unused in Relay Modern +interface LegacyFieldsChangeConfig { + type: 'FIELDS_CHANGE'; + fieldIDs: { [fieldName: string]: DataID | ReadonlyArray }; +} + +// Unused in Relay Modern +interface LegacyRequiredChildrenConfig { + type: 'REQUIRED_CHILDREN'; + children: ReadonlyArray; +} +export type DeclarativeMutationConfig = + | RangeAddConfig + | RangeDeleteConfig + | NodeDeleteConfig + | LegacyFieldsChangeConfig + | LegacyRequiredChildrenConfig; +export type MutationType = 'RANGE_ADD' | 'RANGE_DELETE' | 'NODE_DELETE' | 'FIELDS_CHANGE' | 'REQUIRED_CHILDREN'; +export type RangeOperation = 'append' | 'ignore' | 'prepend' | 'refetch' | 'remove'; +export type RangeBehaviors = + | ((connectionArgs: { [name: string]: unknown }) => RangeOperation) | { - modern(): ConcreteFragment | RequestNode; - classic(relayQL: RelayQL): ConcreteFragmentDefinition | ConcreteOperationDefinition; + [key: string]: RangeOperation; }; -// ~~~~~~~~~~~~~~~~~~~~~ -// General Usage -// ~~~~~~~~~~~~~~~~~~~~~ -export type DataID = string; -export interface Variables { - [name: string]: any; + +// ./mutations/applyRelayModernOptimisticMutation +export interface OptimisticMutationConfig { + configs?: ReadonlyArray | null; + mutation: GraphQLTaggedNode; + variables: Variables; + optimisticUpdater?: SelectorStoreUpdater | null; + optimisticResponse?: object; } + +// ./mutations/commitRelayModernMutation +export interface MutationConfig { + configs?: ReadonlyArray; + mutation: GraphQLTaggedNode; + variables: TOperation['variables']; + uploadables?: UploadableMap; + onCompleted?: + | ((response: TOperation['response'], errors: ReadonlyArray | null | undefined) => void) + | null; + onError?: ((error: Error) => void) | null; + optimisticUpdater?: SelectorStoreUpdater | null; + optimisticResponse?: TOperation['response'] | null; + updater?: SelectorStoreUpdater | null; +} + +// ./network/RelayNetworkLoggerTransaction +export interface RelayNetworkLog { + label: string; + values: ReadonlyArray; +} + +// ./network/RelayNetworkTypes +export type ExecuteFunction = ( + request: RequestParameters, + variables: Variables, + cacheConfig: CacheConfig, + uploadables?: UploadableMap | null +) => RelayObservable; + +export type FetchFunction = ( + request: RequestParameters, + variables: Variables, + cacheConfig: CacheConfig, + uploadables?: UploadableMap | null +) => ObservableFromValue; + +export type GraphQLResponse = + | { + data: PayloadData; + errors?: ReadonlyArray; + extensions?: PayloadExtensions; + } + | { + data?: PayloadData | null; + errors: ReadonlyArray; + extensions?: PayloadExtensions; + }; + +export interface LegacyObserver { + onCompleted?: () => void; + onError?: (error: Error) => void; + onNext?: (data: T) => void; +} + +interface Network { + execute: ExecuteFunction; +} +export { Network as INetwork }; + +export interface PayloadData { + [key: string]: unknown; +} + +export interface PayloadError { + message: string; + locations?: ReadonlyArray<{ + line: number; + column: number; + }>; + severity?: 'CRITICAL' | 'ERROR' | 'WARNING'; // Not officially part of the spec, but used at Facebook +} + +export type SubscribeFunction = ( + request: RequestParameters, + variables: Variables, + cacheConfig: CacheConfig, + observer?: LegacyObserver +) => RelayObservable | Disposable; + export type Uploadable = File | Blob; export interface UploadableMap { [key: string]: Uploadable; } -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayNetworkTypes -// Version: Relay 1.3.0 -// File: https://github.com/facebook/relay/blob/master/packages/relay-runtime/network/RelayNetworkTypes.js -// ~~~~~~~~~~~~~~~~~~~~~ - -export interface LegacyObserver { - onCompleted?(): void; - onError?(error: Error): void; - onNext?(data: T): void; -} -export interface PayloadError { - message: string; - locations?: Array<{ - line: number; - column: number; - }>; -} -/** - * A function that executes a GraphQL operation with request/response semantics. - * - * May return an Observable or Promise of a raw server response. - */ -export type FetchFunction = ( - operation: RequestNode, - variables: Variables, - cacheConfig: CacheConfig, - uploadables?: UploadableMap -) => ObservableFromValue; - -/** - * A function that executes a GraphQL subscription operation, returning one or - * more raw server responses over time. - * - * May return an Observable, otherwise must call the callbacks found in the - * fourth parameter. - */ -export type SubscribeFunction = ( - operation: RequestNode, - variables: Variables, - cacheConfig: CacheConfig, - observer: LegacyObserver -) => RelayObservable | Disposable; - -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayQueryResponseCache -// Version: Relay 1.3.0 -// File: https://github.com/facebook/relay/blob/master/packages/relay-runtime/network/RelayQueryResponseCache.js -// ~~~~~~~~~~~~~~~~~~~~~ - -/** - * A cache for storing query responses, featuring: - * - `get` with TTL - * - cache size limiting, with least-recently *updated* entries purged first - */ -export class QueryResponseCache { - constructor(options: { size: number; ttl: number }); - clear(): void; - get(queryID: string, variables: Variables): QueryPayload | null; - set(queryID: string, variables: Variables, payload: QueryPayload): void; +interface PayloadExtensions { + [key: string]: unknown; } -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayStoreTypes -// Version: Relay 1.3.0 -// File: https://github.com/facebook/relay/blob/master/packages/relay-runtime/store/RelayStoreTypes.js -// ~~~~~~~~~~~~~~~~~~~~~ -/** - * A function that receives a proxy over the store and may trigger side-effects - * (indirectly) by calling `set*` methods on the store or its record proxies. - */ -export type StoreUpdater = (store: RecordSourceProxy) => void; +// ./network/RelayObservable +export type ObservableFromValue = Subscribable | Promise | T; -/** - * Similar to StoreUpdater, but accepts a proxy tied to a specific selector in - * order to easily access the root fields of a query/mutation as well as a - * second argument of the response object of the mutation. - */ -export type SelectorStoreUpdater = ( - store: RecordSourceSelectorProxy, - // Actually RelayCombinedEnvironmentTypes#SelectorData, but mixed is - // inconvenient to access deeply in product code. - data: T -) => void; +export interface Observer { + readonly start?: (subscription: Subscription) => void; + readonly next?: (value: T) => void; + readonly error?: (error: Error) => void; + readonly complete?: () => void; + readonly unsubscribe?: (subscription: Subscription) => void; +} -/** - * Extends the RecordSourceProxy interface with methods for accessing the root - * fields of a Selector. - */ -export interface RecordSourceSelectorProxy { - create(dataID: DataID, typeName: string): RecordProxy; - delete(dataID: DataID): void; - get(dataID: DataID): RecordProxy | null; - getRoot(): RecordProxy; - getRootField(fieldName: string): RecordProxy | null; - getPluralRootField(fieldName: string): RecordProxy[] | null; +export interface Subscribable { + subscribe(observer: Observer | Sink): Subscription; +} + +interface Sink { + next(value: T): void; + error(error: Error, isUncaughtThrownError?: boolean): void; + complete(): void; + readonly closed: boolean; +} +type Source = (sink: Sink) => void | Subscription | (() => unknown); + +export interface Subscription { + unsubscribe(): void; + readonly closed: boolean; +} + +// ./network/createRelayNetworkLogger +export type GraphiQLPrinter = (request: RequestParameters, variables: Variables) => string; + +// ./query/RelayModernGraphQLTag +export type GraphQLTaggedNode = + | ReaderFragment + | ConcreteRequest + | (() => ReaderFragment | ConcreteRequest) + | { + modern: () => ReaderFragment | ConcreteRequest; + }; + +// ./store/RelayRecordState +export type RecordState = 'EXISTENT' | 'NONEXISTENT' | 'UNKNOWN'; + +// ./store/RelayStoreTypes +interface Environment + extends CEnvironment< + Environment, + ReaderFragment, + GraphQLTaggedNode, + ReaderSelectableNode, + NormalizationSelectableNode, + ConcreteRequest, + GraphQLResponse, + OwnedReaderSelector + > { + applyUpdate(optimisticUpdate: OptimisticUpdate): Disposable; + + commitUpdate(updater: StoreUpdater): void; + + commitPayload(operationDescriptor: OperationDescriptor, payload: PayloadData): void; + + getStore(): Store; + + lookup(selector: ReaderSelector, owner?: OperationDescriptor): CSnapshot; + + executeMutation(data: { + operation: OperationDescriptor; + optimisticUpdater?: SelectorStoreUpdater | null; + optimisticResponse?: object | null; + updater?: SelectorStoreUpdater | null; + uploadables?: UploadableMap | null; + }): RelayObservable; +} +export { Environment as IEnvironment }; + +export type FragmentMap = CFragmentMap; + +export type FragmentReference = never & { __tag: 'FragmentReference' }; + +export interface FragmentPointer { + __id: DataID; + __fragments: { [fragmentName: string]: Variables }; + __fragmentOwner: OperationDescriptor | null; +} + +export interface HandleFieldPayload { + readonly args: Variables; + readonly dataID: DataID; + readonly fieldKey: string; + readonly handle: string; + readonly handleKey: string; +} + +export interface MatchPointer { + __id: DataID; + __fragments: { [fragmentName: string]: Variables }; + __fragmentPropName: string; + __module: unknown; +} + +export type MissingFieldHandler = + | { + kind: 'scalar'; + handle: ( + field: NormalizationScalarField, + record: Record | null | undefined, + args: Variables, + store: ReadonlyRecordSourceProxy + ) => unknown; + } + | { + kind: 'linked'; + handle: ( + field: NormalizationLinkedField, + record: Record | null | undefined, + args: Variables, + store: ReadonlyRecordSourceProxy + ) => DataID | null | undefined; + } + | { + kind: 'pluralLinked'; + handle: ( + field: NormalizationLinkedField, + record: Record | null | undefined, + args: Variables, + store: ReadonlyRecordSourceProxy + ) => ReadonlyArray | null | undefined; + }; + +export interface OperationLoader { + get(reference: unknown): NormalizationSplitOperation | null | undefined; + + load(reference: unknown): Promise; +} + +export type OperationDescriptor = COperationDescriptor< + ReaderSelectableNode, + NormalizationSelectableNode, + ConcreteRequest +>; + +export type OptimisticUpdate = + | { + storeUpdater: StoreUpdater; + } + | { + selectorStoreUpdater: SelectorStoreUpdater | null | undefined; + operation: OperationDescriptor; + response: object | null | undefined; + } + | { + source: RecordSource; + fieldPayloads?: ReadonlyArray | null; + }; + +export interface OwnedReaderSelector { + owner: OperationDescriptor | null; + selector: ReaderSelector; } export interface RecordProxy { copyFieldsFrom(source: RecordProxy): void; getDataID(): DataID; - getLinkedRecord(name: string, args?: Variables): RecordProxy | null; - getLinkedRecords(name: string, args?: Variables): ReadonlyArray | null; - getOrCreateLinkedRecord(name: string, typeName: string, args?: Variables): RecordProxy; - getType(): string; - getValue(name: string, args?: Variables): any; - setLinkedRecord(record: RecordProxy, name: string, args?: Variables): RecordProxy; - setLinkedRecords( - records: Array | undefined | null, + getLinkedRecord(name: string, args?: Variables | null): RecordProxy | null | undefined; + getLinkedRecords( name: string, - args?: Variables + args?: Variables | null + ): ReadonlyArray | null | undefined; + getOrCreateLinkedRecord(name: string, typeName: string, args?: Variables | null): RecordProxy; + getType(): string; + getValue(name: string, args?: Variables | null): unknown; + setLinkedRecord(record: RecordProxy, name: string, args?: Variables | null): RecordProxy; + setLinkedRecords( + records: Array, + name: string, + args?: Variables | null ): RecordProxy; - setValue(value: any, name: string, args?: Variables): RecordProxy; + setValue(value: unknown, name: string, args?: Variables | null): RecordProxy; } export interface RecordSourceProxy { create(dataID: DataID, typeName: string): RecordProxy; delete(dataID: DataID): void; - get(dataID: DataID): RecordProxy | null; + get(dataID: DataID): RecordProxy | null | undefined; getRoot(): RecordProxy; } -export interface HandleFieldPayload { - // The arguments that were fetched. - args: Variables; - // The __id of the record containing the source/handle field. +export interface RecordSourceSelectorProxy { + create(dataID: DataID, typeName: string): RecordProxy; + delete(dataID: DataID): void; + get(dataID: DataID): RecordProxy | null | undefined; + getRoot(): RecordProxy; + getRootField(fieldName: string): RecordProxy | null | undefined; + getPluralRootField(fieldName: string): ReadonlyArray | null | undefined; +} + +export type RelayContext = CRelayContext; + +export type ReaderSelector = CReaderSelector; + +export type NormalizationSelector = CNormalizationSelector; + +export type SelectorStoreUpdater = (store: RecordSourceSelectorProxy, data: TData) => void; + +export type Snapshot = CSnapshot; + +export type StoreUpdater = (store: RecordSourceProxy) => void; + +interface ReadonlyRecordSourceProxy { + get(dataID: DataID): ReadonlyRecordProxy | null | undefined; + getRoot(): ReadonlyRecordProxy; +} + +interface ReadonlyRecordProxy { + getDataID(): DataID; + getLinkedRecord(name: string, args?: Variables | null): RecordProxy | null | undefined; + getLinkedRecords( + name: string, + args?: Variables | null + ): ReadonlyArray | null | undefined; + getType(): string; + getValue(name: string, args?: Variables | null): unknown; +} + +interface RecordSource { + get(dataID: DataID): Record | null | undefined; + getRecordIDs(): ReadonlyArray; + getStatus(dataID: DataID): RecordState; + has(dataID: DataID): boolean; + load(dataID: DataID, callback: (error: Error | null | undefined, record: Record | null | undefined) => void): void; + size(): number; +} +export { RecordSource as IRecordSource }; + +interface Store { + getSource(): RecordSource; + check(selector: NormalizationSelector): boolean; + lookup(selector: ReaderSelector, owner?: OperationDescriptor): Snapshot; + notify(): void; + publish(source: RecordSource): void; + retain(selector: NormalizationSelector): Disposable; + subscribe(snapshot: Snapshot, callback: (snapshot: Snapshot) => void): Disposable; + holdGC(): Disposable; +} + +export interface MutableRecordSource extends RecordSource { + clear(): void; + delete(dataID: DataID): void; + remove(dataID: DataID): void; + set(dataID: DataID, record: Record): void; +} + +type Scheduler = (callback: () => void) => void; + +// ./subscription/requestRelaySubscription +export interface GraphQLSubscriptionConfig { + configs?: ReadonlyArray; + subscription: GraphQLTaggedNode; + variables: Variables; + onCompleted?: () => void; + onError?: (error: Error) => void; + onNext?: (response: TSubscriptionPayload | null | undefined) => void; + updater?: SelectorStoreUpdater; +} + +// ./util/NormalizationNode +export type NormalizationArgument = NormalizationLiteral | NormalizationVariable; + +export type NormalizationArgumentDefinition = NormalizationLocalArgument | NormalizationRootArgument; + +export interface NormalizationDefer { + readonly if: string | null; + readonly kind: 'Defer'; + readonly label: string; + readonly metadata: { readonly [key: string]: unknown } | null | undefined; + readonly selections: ReadonlyArray; +} + +export type NormalizationField = NormalizationScalarField | NormalizationLinkedField | NormalizationMatchField; + +export interface NormalizationLinkedField { + readonly kind: string; // 'LinkedField'; + readonly alias: string | null | undefined; + readonly name: string; + readonly storageKey: string | null | undefined; + readonly args: ReadonlyArray; + readonly concreteType: string | null | undefined; + readonly plural: boolean; + readonly selections: ReadonlyArray; +} + +export interface NormalizationMatchField { + readonly kind: string; // 'MatchField'; + readonly alias: string | null | undefined; + readonly name: string; + readonly storageKey: string | null | undefined; + readonly args: ReadonlyArray; + readonly matchesByType: { + readonly [key: string]: { + readonly fragmentPropName: string; + readonly fragmentName: string; + }; + }; +} + +export interface NormalizationOperation { + readonly kind: string; // 'Operation'; + readonly name: string; + readonly argumentDefinitions: ReadonlyArray; + readonly selections: ReadonlyArray; +} + +export interface NormalizationScalarField { + readonly kind: string; // 'ScalarField'; + readonly alias: string | null | undefined; + readonly name: string; + readonly args: ReadonlyArray | null | undefined; + readonly storageKey: string | null | undefined; +} + +export type NormalizationSelection = + | NormalizationCondition + | NormalizationField + | NormalizationHandle + | NormalizationInlineFragment + | NormalizationMatchField; + +export interface NormalizationSplitOperation { + readonly kind: string; // 'SplitOperation'; + readonly name: string; + readonly metadata: { readonly [key: string]: unknown } | null | undefined; + readonly selections: ReadonlyArray; +} + +export interface NormalizationStream { + readonly if: string | null; + readonly kind: string; // 'Stream'; + readonly label: string; + readonly metadata: { readonly [key: string]: unknown } | null | undefined; + readonly selections: ReadonlyArray; +} + +interface NormalizationLiteral { + readonly kind: string; // 'Literal'; + readonly name: string; + readonly value: unknown; +} + +interface NormalizationVariable { + readonly kind: string; // 'Variable'; + readonly name: string; + readonly variableName: string; +} + +interface NormalizationLocalArgument { + readonly kind: string; // 'LocalArgument'; + readonly name: string; + readonly type: string; + readonly defaultValue: unknown; +} + +interface NormalizationRootArgument { + readonly kind: string; // 'RootArgument'; + readonly name: string; + readonly type: string | null | undefined; +} + +interface NormalizationCondition { + readonly kind: string; // 'Condition'; + readonly passingValue: boolean; + readonly condition: string; + readonly selections: ReadonlyArray; +} + +type NormalizationHandle = NormalizationScalarHandle | NormalizationLinkedHandle; + +interface NormalizationLinkedHandle { + readonly kind: string; // 'LinkedHandle'; + readonly alias: string | null | undefined; + readonly name: string; + readonly args: ReadonlyArray | null | undefined; + readonly handle: string; + readonly key: string; + readonly filters: ReadonlyArray | null | undefined; +} + +interface NormalizationScalarHandle { + readonly kind: string; // 'ScalarHandle'; + readonly alias: string | null | undefined; + readonly name: string; + readonly args: ReadonlyArray | null | undefined; + readonly handle: string; + readonly key: string; + readonly filters: ReadonlyArray | null | undefined; +} + +interface NormalizationInlineFragment { + readonly kind: string; // 'InlineFragment'; + readonly selections: ReadonlyArray; + readonly type: string; +} + +type NormalizationSelectableNode = + | NormalizationDefer + | NormalizationOperation + | NormalizationSplitOperation + | NormalizationStream; + +// ./util/ReaderNode +export type ReaderArgument = ReaderLiteral | ReaderVariable; + +export type ReaderArgumentDefinition = ReaderLocalArgument | ReaderRootArgument; + +export type ReaderField = ReaderScalarField | ReaderLinkedField | ReaderMatchField; + +export interface ReaderFragment { + readonly kind: string; // 'Fragment'; + readonly name: string; + readonly type: string; + readonly metadata: + | { + readonly connection?: ReadonlyArray; + readonly mask?: boolean; + readonly plural?: boolean; + readonly refetch?: ReaderRefetchMetadata; + } + | null + | undefined; + readonly argumentDefinitions: ReadonlyArray; + readonly selections: ReadonlyArray; +} + +export interface ReaderLinkedField { + readonly kind: string; // 'LinkedField'; + readonly alias: string | null | undefined; + readonly name: string; + readonly storageKey: string | null | undefined; + readonly args: ReadonlyArray; + readonly concreteType: string | null | undefined; + readonly plural: boolean; + readonly selections: ReadonlyArray; +} + +export interface ReaderMatchField { + readonly kind: string; // 'MatchField'; + readonly alias: string | null | undefined; + readonly name: string; + readonly storageKey: string | null | undefined; + readonly args: ReadonlyArray | null | undefined; + readonly matchesByType: { + readonly [key: string]: { + readonly fragmentPropName: string; + readonly fragmentName: string; + }; + }; +} + +export interface ReaderPaginationMetadata { + readonly backward: { + readonly count: string; + readonly cursor: string; + } | null; + readonly forward: { + readonly count: string; + readonly cursor: string; + } | null; + readonly path: ReadonlyArray; +} + +export interface ReaderRefetchableFragment extends ReaderFragment { + readonly metadata: { + readonly connection?: [ConnectionMetadata]; + readonly refetch: ReaderRefetchMetadata; + }; +} + +export interface ReaderScalarField { + readonly kind: string; // 'ScalarField'; + readonly alias: string | null | undefined; + readonly name: string; + readonly args: ReadonlyArray | null | undefined; + readonly storageKey: string | null | undefined; +} + +export type ReaderSelection = + | ReaderCondition + | ReaderField + | ReaderFragmentSpread + | ReaderInlineFragment + | ReaderMatchField; + +export interface ReaderSplitOperation { + readonly kind: string; // 'SplitOperation'; + readonly name: string; + readonly metadata: { readonly [key: string]: unknown } | null | undefined; + readonly selections: ReadonlyArray; +} + +interface ReaderLiteral { + readonly kind: string; // 'Literal'; + readonly name: string; + readonly value: unknown; +} + +interface ReaderVariable { + readonly kind: string; // 'Variable'; + readonly name: string; + readonly variableName: string; +} + +interface ReaderLocalArgument { + readonly kind: string; // 'LocalArgument'; + readonly name: string; + readonly type: string; + readonly defaultValue: unknown; +} + +interface ReaderRootArgument { + readonly kind: string; // 'RootArgument'; + readonly name: string; + readonly type: string | null | undefined; +} + +interface ReaderRefetchMetadata { + readonly connection: ReaderPaginationMetadata | null | undefined; + readonly operation: string | ConcreteRequest; + readonly fragmentPathInResult: ReadonlyArray; +} + +interface ReaderCondition { + readonly kind: string; // 'Condition'; + readonly passingValue: boolean; + readonly condition: string; + readonly selections: ReadonlyArray; +} + +interface ReaderFragmentSpread { + readonly kind: string; // 'FragmentSpread'; + readonly name: string; + readonly args: ReadonlyArray | null | undefined; +} + +interface ReaderInlineFragment { + readonly kind: string; // 'InlineFragment'; + readonly selections: ReadonlyArray; + readonly type: string; +} + +type ReaderSelectableNode = ReaderFragment | ReaderSplitOperation; + +interface ReaderPaginationFragment extends ReaderFragment { + readonly metadata: { + readonly connection: [ConnectionMetadata]; + readonly refetch: ReaderRefetchMetadata & { + connection: ReaderPaginationMetadata; + }; + }; +} + +// ./util/RelayCombinedEnvironmentTypes +export interface CEnvironment< + TEnvironment, + TFragment, + TGraphQLTaggedNode, + TReaderNode, + TNormalizationNode, + TRequest, + TPayload, + TReaderSelector +> { + check(selector: CNormalizationSelector): boolean; + + lookup( + selector: CReaderSelector + ): CSnapshot>; + + subscribe( + snapshot: CSnapshot>, + callback: ( + snapshot: CSnapshot> + ) => void + ): Disposable; + + retain(selector: CNormalizationSelector): Disposable; + + execute(config: { + operation: COperationDescriptor; + cacheConfig?: CacheConfig | null; + updater?: SelectorStoreUpdater | null; + }): RelayObservable; +} + +export interface CFragmentMap { + [key: string]: TFragment; +} + +export interface CNormalizationSelector { dataID: DataID; - // The (storage) key at which the original server data was written. - fieldKey: string; - // The name of the handle - handle: string; - // The (storage) key at which the handle's data should be written by the - // handler - handleKey: string; -} -export interface HandlerInterface { - update(store: RecordSourceProxy, fieldPayload: HandleFieldPayload): void; - [functionName: string]: (...args: any[]) => any; -} -export const ConnectionHandler: HandlerInterface; -export const ViewerHandler: HandlerInterface; - -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayCombinedEnvironmentTypes -// Version: Relay 1.3.0 -// File: https://github.com/facebook/relay/blob/b85a1d69bb72be4ace67179f55c2a54a8d761c8b/packages/react-relay/classic/environment/RelayCombinedEnvironmentTypes.js -// ~~~~~~~~~~~~~~~~~~~~~ -/** - * Settings for how a query response may be cached. - * - * - `force`: causes a query to be issued unconditionally, irrespective of the - * state of any configured response cache. - * - `poll`: causes a query to live update by polling at the specified interval - * in milliseconds. (This value will be passed to setTimeout.) - */ -export interface CacheConfig { - force?: boolean; - poll?: number; -} - -/** - * Represents any resource that must be explicitly disposed of. The most common - * use-case is as a return value for subscriptions, where calling `dispose()` - * would cancel the subscription. - */ -export interface Disposable { - dispose(): void; -} - -/** - * Arbitrary data e.g. received by a container as props. - */ -export interface Props { - [key: string]: any; -} - -/** - * A selector defines the starting point for a traversal into the graph for the - * purposes of targeting a subgraph. - */ -export interface CSelector { - dataID: DataID; - node: TNode; + node: TNormalizationNode; variables: Variables; } -/** - * A representation of a selector and its results at a particular point in time. - */ -export type CSnapshot = CSelector & { +export interface COperationDescriptor { + fragment: CReaderSelector; + node: TRequest; + root: CNormalizationSelector; + variables: Variables; +} + +export interface CReaderSelector { + dataID: DataID; + node: TReaderNode; + variables: Variables; +} + +export interface CRelayContext { + environment: TEnvironment; + variables: Variables; +} + +export interface CSnapshot extends CReaderSelector { data: SelectorData | null | undefined; seenRecords: RecordMap; -}; - -/** - * The results of a selector given a store/RecordSource. - */ -export interface SelectorData { - [key: string]: any; + isMissingData: boolean; + owner: TOwner | null; } -/** - * The results of reading the results of a FragmentMap given some input - * `Props`. - */ -export interface FragmentSpecResults { - [key: string]: any; -} - -/** - * A utility for resolving and subscribing to the results of a fragment spec - * (key -> fragment mapping) given some "props" that determine the root ID - * and variables to use when reading each fragment. When props are changed via - * `setProps()`, the resolver will update its results and subscriptions - * accordingly. Internally, the resolver: - * - Converts the fragment map & props map into a map of `Selector`s. - * - Removes any resolvers for any props that became null. - * - Creates resolvers for any props that became non-null. - * - Updates resolvers with the latest props. - */ export interface FragmentSpecResolver { /** * Stop watching for changes to the results of the fragments. @@ -334,768 +837,408 @@ export interface FragmentSpecResolver { * Override the variables used to read the results of the fragments. Call * `resolve()` to get the updated results. */ - setVariables(variables: Variables): void; -} - -export interface CFragmentMap { - [key: string]: TFragment; -} - -/** - * An operation selector describes a specific instance of a GraphQL operation - * with variables applied. - * - * - `root`: a selector intended for processing server results or retaining - * response data in the store. - * - `fragment`: a selector intended for use in reading or subscribing to - * the results of the the operation. - */ -export interface COperationSelector { - fragment: CSelector; - node: TOperation; - root: CSelector; - variables: Variables; -} - -/** - * The public API of Relay core. Represents an encapsulated environment with its - * own in-memory cache. - */ -export interface CEnvironment { - /** - * Read the results of a selector from in-memory records in the store. - */ - lookup(selector: CSelector): CSnapshot; + setVariables(variables: Variables, request?: ConcreteRequest): void; /** - * Subscribe to changes to the results of a selector. The callback is called - * when data has been committed to the store that would cause the results of - * the snapshot's selector to change. + * Subscribe to resolver updates. + * Overrides existing callback (if one has been specified). */ - subscribe(snapshot: CSnapshot, callback: (snapshot: CSnapshot) => void): Disposable; - - /** - * Ensure that all the records necessary to fulfill the given selector are - * retained in-memory. The records will not be eligible for garbage collection - * until the returned reference is disposed. - * - * Note: This is a no-op in the classic core. - */ - retain(selector: CSelector): Disposable; - - /** - * Send a query to the server with request/response semantics: the query will - * either complete successfully (calling `onNext` and `onCompleted`) or fail - * (calling `onError`). - * - * Note: Most applications should use `streamQuery` in order to - * optionally receive updated information over time, should that feature be - * supported by the network/server. A good rule of thumb is to use this method - * if you would otherwise immediately dispose the `streamQuery()` - * after receving the first `onNext` result. - */ - sendQuery(config: { - cacheConfig?: CacheConfig; - onCompleted?(): void; - onError?(error: Error): void; - onNext?(payload: TPayload): void; - operation: COperationSelector; - }): Disposable; - - /** - * Send a query to the server with request/subscription semantics: one or more - * responses may be returned (via `onNext`) over time followed by either - * the request completing (`onCompleted`) or an error (`onError`). - * - * Networks/servers that support subscriptions may choose to hold the - * subscription open indefinitely such that `onCompleted` is not called. - */ - streamQuery(config: { - cacheConfig?: CacheConfig; - onCompleted?(): void; - onError?(error: Error): void; - onNext?(payload: TPayload): void; - operation: COperationSelector; - }): Disposable; - - unstable_internal: CUnstableEnvironmentCore; + setCallback(callback: () => void): void; } -export interface CUnstableEnvironmentCore { - /** - * Create an instance of a FragmentSpecResolver. - * - * TODO: The FragmentSpecResolver *can* be implemented via the other methods - * defined here, so this could be moved out of core. It's convenient to have - * separate implementations until the experimental core is in OSS. - */ - createFragmentSpecResolver( - context: CRelayContext, - containerName: string, - fragments: CFragmentMap, - props: Props, - callback: () => void - ): FragmentSpecResolver; - - /** - * Creates an instance of an OperationSelector given an operation definition - * (see `getOperation`) and the variables to apply. The input variables are - * filtered to exclude variables that do not matche defined arguments on the - * operation, and default values are populated for null values. - */ - createOperationSelector(operation: TOperation, variables: Variables): COperationSelector; - - /** - * Given a graphql`...` tagged template, extract a fragment definition usable - * by this version of Relay core. Throws if the value is not a fragment. - */ - getFragment(node: TGraphQLTaggedNode): TFragment; - - /** - * Given a graphql`...` tagged template, extract an operation definition - * usable by this version of Relay core. Throws if the value is not an - * operation. - */ - getOperation(node: TGraphQLTaggedNode): TOperation; - - /** - * Determine if two selectors are equal (represent the same selection). Note - * that this function returns `false` when the two queries/fragments are - * different objects, even if they select the same fields. - */ - areEqualSelectors(a: CSelector, b: CSelector): boolean; - - /** - * Given the result `item` from a parent that fetched `fragment`, creates a - * selector that can be used to read the results of that fragment for that item. - * - * Example: - * - * Given two fragments as follows: - * - * ``` - * fragment Parent on User { - * id - * ...Child - * } - * fragment Child on User { - * name - * } - * ``` - * - * And given some object `parent` that is the results of `Parent` for id "4", - * the results of `Child` can be accessed by first getting a selector and then - * using that selector to `lookup()` the results against the environment: - * - * ``` - * const childSelector = getSelector(queryVariables, Child, parent); - * const childData = environment.lookup(childSelector).data; - * ``` - */ - getSelector(operationVariables: Variables, fragment: TFragment, prop: any): CSelector | null; - - /** - * Given the result `items` from a parent that fetched `fragment`, creates a - * selector that can be used to read the results of that fragment on those - * items. This is similar to `getSelector` but for "plural" fragments that - * expect an array of results and therefore return an array of selectors. - */ - getSelectorList(operationVariables: Variables, fragment: TFragment, props: any[]): Array> | null; - - /** - * Given a mapping of keys -> results and a mapping of keys -> fragments, - * extracts the selectors for those fragments from the results. - * - * The canonical use-case for this function are Relay Containers, which - * use this function to convert (props, fragments) into selectors so that they - * can read the results to pass to the inner component. - */ - getSelectorsFromObject( - operationVariables: Variables, - fragments: CFragmentMap, - props: Props - ): { - [key: string]: CSelector | Array> | null | undefined; - }; - - /** - * Given a mapping of keys -> results and a mapping of keys -> fragments, - * extracts a mapping of keys -> id(s) of the results. - * - * Similar to `getSelectorsFromObject()`, this function can be useful in - * determining the "identity" of the props passed to a component. - */ - getDataIDsFromObject( - fragments: CFragmentMap, - props: Props - ): { [key: string]: DataID | DataID[] | null | undefined }; - - /** - * Given a mapping of keys -> results and a mapping of keys -> fragments, - * extracts the merged variables that would be in scope for those - * fragments/results. - * - * This can be useful in determing what varaibles were used to fetch the data - * for a Relay container, for example. - */ - getVariablesFromObject(operationVariables: Variables, fragments: CFragmentMap, props: Props): Variables; +export interface FragmentSpecResults { + [key: string]: unknown; } -/** - * The type of the `relay` property set on React context by the React/Relay - * integration layer (e.g. QueryRenderer, FragmentContainer, etc). - */ -export interface CRelayContext { - environment: TEnvironment; - variables: Variables; +export interface Props { + [key: string]: unknown; } -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayTypes -/** - * Version: Relay 1.3.0 - * File: - * https://github.com/facebook/relay/blob/fa9f48ea209ee2402d433b59a84d1cbc046574e2/packages/react-relay/classic/tools/RelayTypes.js - */ -// ~~~~~~~~~~~~~~~~~~~~~ -export interface RerunParam { - param: string; - import: string; - max_runs: number; +interface RecordMap { + // theoretically, this should be `[dataID: DataID]`, but `DataID` is a string. + [dataID: string]: Record | undefined; } -export interface FIELDS_CHANGE { - type: 'FIELDS_CHANGE'; - fieldIDs: { [fieldName: string]: DataID | DataID[] }; -} -export interface RANGE_ADD { - type: 'RANGE_ADD'; - parentName?: string; - parentID?: string; - connectionInfo?: Array<{ - key: string; - filters?: Variables; - rangeBehavior: string; - }>; - connectionName?: string; - edgeName: string; - rangeBehaviors?: RangeBehaviors; -} -export interface NODE_DELETE { - type: 'NODE_DELETE'; - parentName?: string; - parentID?: string; - connectionName?: string; - deletedIDFieldName: string; -} -export interface RANGE_DELETE { - type: 'RANGE_DELETE'; - parentName?: string; - parentID?: string; - connectionKeys?: Array<{ - key: string; - filters?: Variables; - }>; - connectionName?: string; - deletedIDFieldName: string | string[]; - pathToConnection: string[]; -} -export interface REQUIRED_CHILDREN { - type: 'REQUIRED_CHILDREN'; - children: RelayConcreteNode[]; -} -export type RelayMutationConfig = FIELDS_CHANGE | RANGE_ADD | NODE_DELETE | RANGE_DELETE | REQUIRED_CHILDREN; - -export interface RelayMutationTransactionCommitCallbacks { - onFailure?: RelayMutationTransactionCommitFailureCallback; - onSuccess?: RelayMutationTransactionCommitSuccessCallback; -} -export type RelayMutationTransactionCommitFailureCallback = ( - transaction: RelayMutationTransaction, - preventAutoRollback: () => void -) => void; -export type RelayMutationTransactionCommitSuccessCallback = (response: { [key: string]: any }) => void; -export interface NetworkLayer { - sendMutation(request: RelayMutationRequest): Promise | null; - sendQueries(requests: RelayQueryRequest[]): Promise | null; - supports(...options: string[]): boolean; -} -export interface QueryResult { - error?: Error; - ref_params?: { [name: string]: any }; - response: QueryPayload; -} -export interface ReadyState { - aborted: boolean; - done: boolean; - error: Error | null; - events: ReadyStateEvent[]; - ready: boolean; - stale: boolean; -} -export type RelayContainerErrorEventType = 'CACHE_RESTORE_FAILED' | 'NETWORK_QUERY_ERROR'; -export type RelayContainerLoadingEventType = - | 'ABORT' - | 'CACHE_RESTORED_REQUIRED' - | 'CACHE_RESTORE_START' - | 'NETWORK_QUERY_RECEIVED_ALL' - | 'NETWORK_QUERY_RECEIVED_REQUIRED' - | 'NETWORK_QUERY_START' - | 'STORE_FOUND_ALL' - | 'STORE_FOUND_REQUIRED'; -export type ReadyStateChangeCallback = (readyState: ReadyState) => void; -export interface ReadyStateEvent { - type: RelayContainerLoadingEventType | RelayContainerErrorEventType; - error?: Error; -} -export interface Abortable { - abort(): void; +export interface SelectorData { + [key: string]: unknown; } -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayInternalTypes -/** - * Version: Relay 1.3.0 - * File: - * https://github.com/facebook/relay/blob/master/packages/react-relay/classic/tools/RelayInternalTypes.js - */ -// ~~~~~~~~~~~~~~~~~~~~~ -export interface QueryPayload { - [key: string]: any; -} -export interface RelayQuerySet { - [queryName: string]: any; -} -export type RangeBehaviorsFunction = (connectionArgs: { - [argName: string]: any; -}) => 'APPEND' | 'IGNORE' | 'PREPEND' | 'REFETCH' | 'REMOVE'; -export interface RangeBehaviorsObject { - [key: string]: 'APPEND' | 'IGNORE' | 'PREPEND' | 'REFETCH' | 'REMOVE'; -} -export type RangeBehaviors = RangeBehaviorsFunction | RangeBehaviorsObject; - -// ~~~~~~~~~~~~~~~~~~~~~ -// Maybe Fix -// ~~~~~~~~~~~~~~~~~~~~~ -export type RelayDebugger = any; -export type OptimisticUpdate = any; -export type OperationSelector = COperationSelector; -export type Selector = CSelector; -export type PayloadData = any; -export type Snapshot = CSnapshot; -export type RelayResponsePayload = any; -export type MutableRecordSource = RecordSource; - -/** - * A function that returns an Observable representing the response of executing - * a GraphQL operation. - */ -export type ExecuteFunction = ( - operation: object, - variables: Variables, - cacheConfig: CacheConfig, - uploadables?: UploadableMap -) => Promise; -export interface RelayNetwork { - execute: ExecuteFunction; +// ./util/RelayConcreteNode +export interface ConcreteRequest { + readonly kind: string; // 'Request'; + readonly fragment: ReaderFragment; + readonly operation: NormalizationOperation; + readonly params: RequestParameters; } -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayDefaultHandlerProvider -// ~~~~~~~~~~~~~~~~~~~~~ -export type HandlerProvider = (name: string) => HandlerInterface | null; +export type GeneratedNode = ConcreteRequest | ReaderFragment | NormalizationSplitOperation; -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayModernEnvironment -// ~~~~~~~~~~~~~~~~~~~~~ -export interface EnvironmentConfig { - configName?: string; - handlerProvider?: HandlerProvider; - network: Network; - store: Store; +export interface RequestParameters { + readonly name: string; + readonly operationKind: string; // 'mutation' | 'query' | 'subscription'; + readonly id: string | null | undefined; + readonly text: string | null | undefined; + readonly metadata: { [key: string]: unknown }; } -export class Environment { + +// ./util/RelayRuntimeTypes +export interface CacheConfig { + force?: boolean | null; + poll?: number | null; + liveConfigId?: string | null; + metadata?: { [key: string]: unknown }; + transactionId?: string | null; +} + +export type DataID = string; + +export interface Disposable { + dispose(): void; +} + +export interface OperationType { + readonly variables: Variables; + readonly response: unknown; +} + +export interface Variables { + [name: string]: any; +} + +// Core API + +// ./RelayModernEnvironment +interface EnvironmentConfig { + readonly configName?: string; + readonly handlerProvider?: HandlerProvider; + readonly operationLoader?: OperationLoader; + readonly network: Network; + readonly store: Store; + readonly missingFieldHandlers?: ReadonlyArray; +} +declare class RelayModernEnvironment implements Environment { + readonly configName: string | null | undefined; constructor(config: EnvironmentConfig); getStore(): Store; - getDebugger(): RelayDebugger; + getNetwork(): Network; applyUpdate(optimisticUpdate: OptimisticUpdate): Disposable; revertUpdate(update: OptimisticUpdate): void; replaceUpdate(update: OptimisticUpdate, newUpdate: OptimisticUpdate): void; - applyMutation(config: { - operation: OperationSelector; - optimisticUpdater?: SelectorStoreUpdater; + applyMutation(data: { + operation: OperationDescriptor; + optimisticUpdater?: SelectorStoreUpdater | null; optimisticResponse?: object; }): Disposable; - check(readSelector: Selector): boolean; - commitPayload(operationSelector: OperationSelector, payload: PayloadData): void; + check(readSelector: NormalizationSelector): boolean; + commitPayload(operationDescriptor: OperationDescriptor, payload: PayloadData): void; commitUpdate(updater: StoreUpdater): void; - lookup(readSelector: Selector): Snapshot; + lookup(readSelector: ReaderSelector, owner?: OperationDescriptor): Snapshot; subscribe(snapshot: Snapshot, callback: (snapshot: Snapshot) => void): Disposable; - retain(selector: Selector): Disposable; - execute(config: { - operation: OperationSelector; - cacheConfig?: CacheConfig; - updater?: SelectorStoreUpdater; - }): RelayObservable; - executeMutation(config: { - operation: OperationSelector; - optimisticUpdater?: SelectorStoreUpdater; - optimisticResponse?: object; - updater?: SelectorStoreUpdater; - uploadables?: UploadableMap; - }): RelayObservable; + retain(selector: NormalizationSelector): Disposable; + execute(data: { + operation: OperationDescriptor; + cacheConfig?: CacheConfig | null; + updater?: SelectorStoreUpdater | null; + }): RelayObservable; + executeMutation({ + operation, + optimisticResponse, + optimisticUpdater, + updater, + uploadables, + }: { + operation: OperationDescriptor; + optimisticUpdater?: SelectorStoreUpdater | null; + optimisticResponse?: object | null; + updater?: SelectorStoreUpdater | null; + uploadables?: UploadableMap | null; + }): RelayObservable; } +export { RelayModernEnvironment as Environment }; -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayInMemoryRecordSource -// ~~~~~~~~~~~~~~~~~~~~~ -export interface RelayInMemoryRecordSource { - [key: string]: any; -} -export interface RecordMap { - [dataID: string]: RelayInMemoryRecordSource | null | undefined; -} +type HandlerProvider = (name: string) => Handler | null | undefined; -// ~~~~~~~~~~~~~~~~~~~~~ -// Network -// ~~~~~~~~~~~~~~~~~~~~~ -export class Network { - /** - * Creates an implementation of the `Network` interface defined in - * `RelayNetworkTypes` given `fetch` and `subscribe` functions. - */ - static create(fetchFn: FetchFunction, subscribeFn?: SubscribeFunction): RelayNetwork; -} +// ./network/RelayNetwork +declare const RelayNetwork: { + create(fetchFn: FetchFunction, subscribeFn?: SubscribeFunction): Network; +}; +export { RelayNetwork as Network }; -// ~~~~~~~~~~~~~~~~~~~~~ -// Network -// ~~~~~~~~~~~~~~~~~~~~~ -export class RecordSource { +// ./network/RelayObservable +declare class RelayObservable implements Subscribable { + // Use RelayObservable.create(source); + private constructor(source: never); + + static create(source: Source): RelayObservable; + + static onUnhandledError(callback: (error: Error, isUncaughtThrownError: boolean) => void): void; + + static from(obj: ObservableFromValue): RelayObservable; + + static fromLegacy( + callback: (observer: LegacyObserver) => Disposable | RelayObservable + ): RelayObservable; + + catch(fn: (error: Error) => RelayObservable): RelayObservable; + + do(observer: Observer): RelayObservable; + + finally(fn: () => unknown): RelayObservable; + + ifEmpty(alternate: RelayObservable): RelayObservable; + + subscribe(observer: Observer | Sink): Subscription; + + subscribeLegacy(legacyObserver: LegacyObserver): Disposable; + + map(fn: (value: T) => U): RelayObservable; + + mergeMap(fn: (value: T) => ObservableFromValue): RelayObservable; + + poll(pollInterval: number): RelayObservable; + + toPromise(): Promise; +} +export { RelayObservable as Observable }; + +// ./networks/RelayQueryResponseCache +declare class RelayQueryResponseCache { + constructor(config: { size: number; ttl: number }); + clear(): void; + get(queryID: string, variables: Variables): GraphQLResponse | null; + set(queryID: string, variables: Variables, payload: GraphQLResponse): void; +} +export { RelayQueryResponseCache as QueryResponseCache }; + +// ./store/RelayInMemoryRecordSource +declare class RelayInMemoryRecordSource implements MutableRecordSource { constructor(records?: RecordMap); clear(): void; delete(dataID: DataID): void; - get(dataID: DataID): RelayInMemoryRecordSource | null; - getRecordIDs(): DataID[]; - getStatus(dataID: DataID): 'EXISTENT' | 'NONEXISTENT' | 'UNKNOWN'; + get(dataID: DataID): Record | null | undefined; + getRecordIDs(): ReadonlyArray; + getStatus(dataID: DataID): RecordState; has(dataID: DataID): boolean; - load(dataID: DataID, callback: (error: Error | null, record: RelayInMemoryRecordSource | null) => void): void; + load(dataID: DataID, callback: (error: Error | null | undefined, record: Record | null | undefined) => void): void; remove(dataID: DataID): void; - set(dataID: DataID, record: RelayInMemoryRecordSource): void; + set(dataID: DataID, record: Record): void; size(): number; - toJSON(): RecordMap; } +export { RelayInMemoryRecordSource as RecordSource }; -// ~~~~~~~~~~~~~~~~~~~~~ -// ModernStore -// ~~~~~~~~~~~~~~~~~~~~~ -export class Store { - constructor(source: RecordSource); - getSource(): MutableRecordSource; - check(selector: Selector): boolean; - retain(selector: Selector): Disposable; - lookup(selector: Selector): Snapshot; +// ./store/RelayModernStore +declare class RelayModernStore implements Store { + constructor(source: MutableRecordSource, gcScheduler?: Scheduler, operationLoader?: OperationLoader | null); + getSource(): RecordSource; + check(selector: NormalizationSelector): boolean; + retain(selector: NormalizationSelector): Disposable; + lookup(selector: ReaderSelector, owner?: OperationDescriptor): Snapshot; notify(): void; publish(source: RecordSource): void; subscribe(snapshot: Snapshot, callback: (snapshot: Snapshot) => void): Disposable; + holdGC(): Disposable; } +export { RelayModernStore as Store }; -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayRecordSourceInspector -// ~~~~~~~~~~~~~~~~~~~~~ -/** - * An internal class to provide a console-friendly string representation of a - * RelayInMemoryRecordSource. - */ -export class RecordSummary { - id: DataID; - type: string | null | undefined; - static createFromRecord(id: DataID, record: any): RecordSummary; - constructor(id: DataID, type: string | null | undefined); - toString(): string; +// ./store/RelayModernSelector via ./store/RelayCore +export function areEqualSelectors(thisSelector: OwnedReaderSelector, thatSelector: OwnedReaderSelector): boolean; + +export function getDataIDsFromObject( + fragments: { [key: string]: ReaderFragment }, + object: { [key: string]: unknown } +): { [key: string]: DataID | ReadonlyArray | null | undefined }; + +export function getSelector( + operationVariables: Variables, + fragment: ReaderFragment, + item: unknown +): OwnedReaderSelector | null | undefined; + +export function getSelectorList( + operationVariables: Variables, + fragment: ReaderFragment, + items: ReadonlyArray +): ReadonlyArray | null | undefined; + +export function getSelectorsFromObject( + operationVariables: Variables, + fragments: { [key: string]: ReaderFragment }, + object: { [key: string]: unknown } +): { + [key: string]: OwnedReaderSelector | ReadonlyArray | null | undefined; +}; + +export function getVariablesFromObject( + operationVariables: Variables, + fragments: { [key: string]: ReaderFragment }, + object: { [key: string]: unknown } +): Variables; + +// ./store/RelayModernOperationDescriptor via ./store/RelayCore +export function createOperationDescriptor(request: ConcreteRequest, variables: Variables): OperationDescriptor; + +// ./store/RelayCore +export function createFragmentSpecResolver( + context: RelayContext, + containerName: string, + fragments: FragmentMap, + props: Props, + callback?: () => void +): FragmentSpecResolver; + +// ./query/RelayModernGraphQLTag +export function getFragment(taggedNode: GraphQLTaggedNode): ReaderFragment; +export function getFragmentOwner( + fragmentNode: ReaderFragment, + fragmentRef: FragmentPointer | ReadonlyArray | null | undefined +): OperationDescriptor | null; +export function getFragmentOwners( + fragmentNodes: { [key: string]: ReaderFragment }, + fragmentRefs: { + [key: string]: FragmentPointer | ReadonlyArray | null | undefined; + } +): { [key: string]: OperationDescriptor | null }; +export function getPaginationFragment(taggedNode: GraphQLTaggedNode): ReaderPaginationFragment | null; +export function getRefetchableFragment(taggedNode: GraphQLTaggedNode): ReaderRefetchableFragment | null; +export function getRequest(taggedNode: GraphQLTaggedNode): ConcreteRequest; +export function graphql(strings: ReadonlyArray): GraphQLTaggedNode; + +// ./store/RelayStoreUtils +export function getStorageKey( + field: NormalizationField | NormalizationHandle | ReaderField, + variables: Variables +): string; + +// Declarative mutation API +// ./mutations/RelayDeclarativeMutationConfig +export const MutationTypes: { + RANGE_ADD: 'RANGE_ADD'; + RANGE_DELETE: 'RANGE_DELETE'; + NODE_DELETE: 'NODE_DELETE'; + FIELDS_CHANGE: 'FIELDS_CHANGE'; + REQUIRED_CHILDREN: 'REQUIRED_CHILDREN'; +}; + +export const RangeOperations: { + APPEND: 'append'; + IGNORE: 'ignore'; + PREPEND: 'prepend'; + REFETCH: 'refetch'; // legacy only + REMOVE: 'remove'; // legacy only +}; + +export const FRAGMENTS_KEY: string; +export const FRAGMENT_OWNER_KEY: string; +export const ID_KEY: string; +export const REF_KEY: string; +export const REFS_KEY: string; +export const ROOT_ID: string; +export const ROOT_TYPE: string; +export const TYPENAME_KEY: string; + +// Extensions +// ./handlers/RelayDefaultHandlerProvider +declare function RelayDefaultHandlerProvider(handle: string): Handler; +export { RelayDefaultHandlerProvider as DefaultHandlerProvider }; + +// ./handlers/connection/RelayConnectionHandler +interface RelayConnectionHandler { + buildConnectionEdge( + store: RecordSourceProxy, + connection: RecordProxy, + edge: RecordProxy | null | undefined + ): RecordProxy | null | undefined; + createEdge(store: RecordSourceProxy, record: RecordProxy, node: RecordProxy, edgeType: string): RecordProxy; + deleteNode(record: RecordProxy, nodeID: DataID): void; + getConnection(record: ReadonlyRecordProxy, key: string, filters?: Variables | null): RecordProxy | null | undefined; + insertEdgeAfter(record: RecordProxy, newEdge: RecordProxy, cursor?: string | null): void; + insertEdgeBefore(record: RecordProxy, newEdge: RecordProxy, cursor?: string | null): void; + update(store: RecordSourceProxy, payload: HandleFieldPayload): void; } -/** - * Internal class for inspecting a single RelayInMemoryRecordSource. - */ -export class RecordInspector { - constructor(sourceInspector: RelayRecordSourceInspector, record: RelayInMemoryRecordSource); - /** - * Get the cache id of the given record. For types that implement the `Node` - * interface (or that have an `id`) this will be `id`, for other types it will be - * a synthesized identifier based on the field path from the nearest ancestor - * record that does have an `id`. - */ - getDataID(): DataID; +declare const RelayConnectionHandler: RelayConnectionHandler; +export { RelayConnectionHandler as ConnectionHandler }; - /** - * Returns a list of the fields that have been fetched on the current record. - */ - getFields(): string[]; - - /** - * Returns the type of the record. - */ - getType(): string; - - /** - * Returns a copy of the internal representation of the record. - */ - inspect(): any; - - /** - * Returns the value of a scalar field. May throw if the given field is - * present but not actually scalar. - */ - getValue(name: string, args?: Variables): any; - - /** - * Returns an inspector for the given scalar "linked" field (a field whose - * value is another RelayInMemoryRecordSource instead of a scalar). May throw if the field is - * present but not a scalar linked record. - */ - getLinkedRecord(name: string, args?: Variables): RecordInspector | null; - - /** - * Returns an array of inspectors for the given plural "linked" field (a field - * whose value is an array of Records instead of a scalar). May throw if the - * field is present but not a plural linked record. - */ - getLinkedRecords(name: string, args?: Variables): RecordInspector[] | null; +// ./handlers/viewer/RelayViewerHandler +interface RelayViewerHandler { + readonly VIEWER_ID: string; + update(store: RecordSourceProxy, payload: HandleFieldPayload): void; } +declare const RelayViewerHandler: RelayViewerHandler; +export { RelayViewerHandler as ViewerHandler }; -export class RelayRecordSourceInspector { - constructor(source: RecordSource); - static getForEnvironment(environment: Environment): RelayRecordSourceInspector; - /** - * Returns an inspector for the record with the given id, or null/undefined if - * that record is deleted/unfetched. - */ - get(dataID: DataID): RecordInspector | null; - /** - * Returns a list of ": " for each record in the store that has an - * `id`. - */ - getNodes(): RecordSummary[]; - /** - * Returns a list of ": " for all records in the store including - * those that do not have an `id`. - */ - getRecords(): RecordSummary[]; +// Helpers (can be implemented via the above API) - /** - * Returns an inspector for the synthesized "root" object, allowing access to - * e.g. the `viewer` object or the results of other fields on the "Query" - * type. - */ - getRoot(): RecordInspector; -} +// ./mutations/applyRelayModernOptimisticMutation +declare function applyRelayModernOptimisticMutation( + environment: Environment, + config: OptimisticMutationConfig +): Disposable; +export { applyRelayModernOptimisticMutation as applyOptimisticMutation }; -// note RecordSourceInspector is only available in dev environment -export class RecordSourceInspector extends RelayRecordSourceInspector {} - -// ~~~~~~~~~~~~~~~~~~~~~ -// RelayObservable -// ~~~~~~~~~~~~~~~~~~~~~ -export interface Subscription { - unsubscribe(): void; - readonly closed: boolean; -} -export interface Observer { - start?(subscription: Subscription): any; - next?(nextThing: T): any; - error?(error: Error): any; - complete?(): any; - unsubscribe?(subscription: Subscription): any; -} -export type Source = () => any; // tslint:disable-line:no-unnecessary-generics -export interface Subscribable { - subscribe(observer: Observer): Subscription; -} -export type ObservableFromValue = RelayObservable | Promise | T; -export class RelayObservable implements Subscribable { - _source: Source; - - constructor(source: Source); - - /** - * When an unhandled error is detected, it is reported to the host environment - * (the ESObservable spec refers to this method as "HostReportErrors()"). - * - * The default implementation in development builds re-throws errors in a - * separate frame, and from production builds does nothing (swallowing - * uncaught errors). - * - * Called during application initialization, this method allows - * application-specific handling of uncaught errors. Allowing, for example, - * integration with error logging or developer tools. - */ - static onUnhandledError(callback: (error: Error) => any): void; - - /** - * Accepts various kinds of data sources, and always returns a RelayObservable - * useful for accepting the result of a user-provided FetchFunction. - */ - static from(obj: ObservableFromValue): RelayObservable; - - /** - * Creates a RelayObservable, given a function which expects a legacy - * Relay Observer as the last argument and which returns a Disposable. - * - * To support migration to Observable, the function may ignore the - * legacy Relay observer and directly return an Observable instead. - */ - static fromLegacy( - callback: (legacyObserver: LegacyObserver) => Disposable | RelayObservable - ): RelayObservable; - - /** - * Returns a new Observable which returns the same values as this one, but - * modified so that the provided Observer is called to perform a side-effects - * for all events emitted by the source. - * - * Any errors that are thrown in the side-effect Observer are unhandled, and - * do not affect the source Observable or its Observer. - * - * This is useful for when debugging your Observables or performing other - * side-effects such as logging or performance monitoring. - */ - do(observer: Observer): RelayObservable; - - /** - * Returns a new Observable which returns the same values as this one, but - * modified so that the finally callback is performed after completion, - * whether normal or due to error or unsubscription. - * - * This is useful for cleanup such as resource finalization. - */ - finally(fn: () => any): RelayObservable; - - /** - * Returns a new Observable which is identical to this one, unless this - * Observable completes before yielding any values, in which case the new - * Observable will yield the values from the alternate Observable. - * - * If this Observable does yield values, the alternate is never subscribed to. - * - * This is useful for scenarios where values may come from multiple sources - * which should be tried in order, i.e. from a cache before a network. - */ - ifEmpty(alternate: RelayObservable): RelayObservable; - - /** - * Observable's primary API: returns an unsubscribable Subscription to the - * source of this Observable. - */ - subscribe(observer: Observer): Subscription; - - /** - * Supports subscription of a legacy Relay Observer, returning a Disposable. - */ - subscribeLegacy(legacyObserver: LegacyObserver): Disposable; - - /** - * Returns a new Observerable where each value has been transformed by - * the mapping function. - */ - map(fn: (thing: T) => U): RelayObservable; - - /** - * Returns a new Observable where each value is replaced with a new Observable - * by the mapping function, the results of which returned as a single - * concattenated Observable. - */ - concatMap(fn: (thing: T) => ObservableFromValue): RelayObservable; - - /** - * Returns a new Observable which first mirrors this Observable, then when it - * completes, waits for `pollInterval` milliseconds before re-subscribing to - * this Observable again, looping in this manner until unsubscribed. - * - * The returned Observable never completes. - */ - poll(pollInterval: number): RelayObservable; - - /** - * Returns a Promise which resolves when this Observable yields a first value - * or when it completes with no value. - */ - toPromise(): Promise; -} - -export type Observable = RelayObservable; - -// ~~~~~~~~~~~~~~~~~~~~~ -// commitLocalUpdate -// ~~~~~~~~~~~~~~~~~~~~~ -// exposed through RelayModern, not Runtime directly +// ./mutations/commitLocalUpdate export function commitLocalUpdate(environment: Environment, updater: StoreUpdater): void; -// ~~~~~~~~~~~~~~~~~~~~~ -// commitRelayModernMutation -// ~~~~~~~~~~~~~~~~~~~~~ -// exposed through RelayModern, not Runtime directly -export interface MutationConfig { - configs?: RelayMutationConfig[]; - mutation: GraphQLTaggedNode; - variables: T['variables']; - uploadables?: UploadableMap; - onCompleted?(response: T['response'], errors: PayloadError[] | null | undefined): void; - onError?(error?: Error): void; - optimisticUpdater?: SelectorStoreUpdater; - optimisticResponse?: T['response']; - updater?: SelectorStoreUpdater; -} -export function commitRelayModernMutation( +// ./mutations/commitRelayModernMutation +declare function commitRelayModernMutation( environment: Environment, - // tslint:disable-next-line:no-unnecessary-generics - config: MutationConfig + // tslint:disable-next-line no-unnecessary-generics + config: MutationConfig ): Disposable; +export { commitRelayModernMutation as commitMutation }; -// ~~~~~~~~~~~~~~~~~~~~~ -// applyRelayModernOptimisticMutation -// ~~~~~~~~~~~~~~~~~~~~~ -// exposed through RelayModern, not Runtime directly -export interface OptimisticMutationConfig { - configs?: RelayMutationConfig[]; - mutation: GraphQLTaggedNode; - variables: Variables; - optimisticUpdater?: SelectorStoreUpdater; - optimisticResponse?: object; -} - -// ~~~~~~~~~~~~~~~~~~~~~ -// fetchRelayModernQuery -// ~~~~~~~~~~~~~~~~~~~~~ -// exposed through RelayModern, not Runtime directly -/** - * A helper function to fetch the results of a query. Note that results for - * fragment spreads are masked: fields must be explicitly listed in the query in - * order to be accessible in the result object. - * - * NOTE: This module is primarily intended for integrating with classic APIs. - * Most product code should use a Renderer or Container. - * - * TODO(t16875667): The return type should be `Promise`, but - * that's not really helpful as `SelectorData` is essentially just `mixed`. We - * can probably leverage generated flow types here to return the real expected - * shape. - */ -export function fetchRelayModernQuery( - environment: any, // FIXME - $FlowFixMe in facebook source code +// ./query/fetchRelayModernQuery +declare function fetchRelayModernQuery( + environment: RelayModernEnvironment, taggedNode: GraphQLTaggedNode, - variables: Variables, - cacheConfig?: CacheConfig -): Promise; // FIXME - $FlowFixMe in facebook source code + variables: T['variables'], + cacheConfig?: CacheConfig | null +): Promise; +export { fetchRelayModernQuery as fetchQuery }; -// ~~~~~~~~~~~~~~~~~~~~~ -// requestRelaySubscription -// ~~~~~~~~~~~~~~~~~~~~~ -// exposed through RelayModern, not Runtime directly -export interface GraphQLSubscriptionConfig { - configs?: RelayMutationConfig[]; - subscription: GraphQLTaggedNode; - variables: Variables; - onCompleted?(): void; - onError?(error: Error): void; - onNext?(response: object | null | undefined): void; - updater?(store: RecordSourceSelectorProxy): void; +// ./store/isRelayModernEnvironment +export function isRelayModernEnvironment(environment: any): environment is RelayModernEnvironment; + +// ./subscription/requestRelaySubscription +declare function requestRelaySubscription(environment: Environment, config: GraphQLSubscriptionConfig<{}>): Disposable; +export { requestRelaySubscription as requestSubscription }; + +// Configuration interface for legacy or special uses +// ./handlers/connection/RelayConnectionInterface +export const ConnectionInterface: { + get(): { + CLIENT_MUTATION_ID: 'clientMutationId'; + CURSOR: 'cursor'; + EDGES_HAVE_SOURCE_FIELD: boolean; + EDGES: 'edges'; + END_CURSOR: 'endCursor'; + HAS_NEXT_PAGE: 'hasNextPage'; + HAS_PREV_PAGE: 'hasPreviousPage'; + NODE: 'node'; + PAGE_INFO_TYPE: 'PageInfo'; + PAGE_INFO: 'pageInfo'; + START_CURSOR: 'startCursor'; + }; +}; + +// Utilities +interface Handler { + update: (store: RecordSourceProxy, fieldPayload: HandleFieldPayload) => void; } -export function requestRelaySubscription(environment: Environment, config: GraphQLSubscriptionConfig): Disposable; +type ProfileHandler = (name: string, state?: any) => (error?: Error) => void; +export interface RelayProfiler { + instrumentMethods(object: object, names: { [key: string]: string }): void; + instrument any>(name: string, originalFunction: T): T; + attachAggregateHandler(name: string, handler: Handler): void; + detachAggregateHandler(name: string, handler: Handler): void; + profile(name: string, state?: any): { stop: (error?: Error) => void }; + attachProfileHandler(name: string, handler: ProfileHandler): void; + detachProfileHandler(name: string, handler: ProfileHandler): void; +} +export const RelayProfiler: RelayProfiler; + +// Internal API +export function deepFreeze(value: T): T; + +export const RelayFeatureFlags: { + MERGE_FETCH_AND_FRAGMENT_VARS: boolean; + PREFER_FRAGMENT_OWNER_OVER_CONTEXT: boolean; +}; diff --git a/types/relay-runtime/relay-runtime-tests.tsx b/types/relay-runtime/relay-runtime-tests.tsx index 4931822ab0..e10c36fc4e 100644 --- a/types/relay-runtime/relay-runtime-tests.tsx +++ b/types/relay-runtime/relay-runtime-tests.tsx @@ -5,7 +5,6 @@ import { Store, ConnectionHandler, ViewerHandler, - RecordSourceInspector, commitLocalUpdate, QueryResponseCache, ROOT_ID, @@ -65,7 +64,7 @@ function handlerProvider(handle: any) { // Source // ~~~~~~~~~~~~~~~~~~~~~ -const inspector = new RecordSourceInspector(source); +store.publish(source); // ~~~~~~~~~~~~~~~~~~~~~ // commitLocalUpdate diff --git a/types/relay-runtime/tslint.json b/types/relay-runtime/tslint.json index f0f7a6f17a..10d875b8db 100644 --- a/types/relay-runtime/tslint.json +++ b/types/relay-runtime/tslint.json @@ -1,7 +1,4 @@ { "extends": "dtslint/dt.json", - "rules": { - // TODO - "no-unnecessary-class": false - } + "rules": {} }