// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { AmplifyClassV6, ResourcesConfig } from '@aws-amplify/core'; import { BaseClient, ClientExtensions, ClientExtensionsSSRCookies, ClientExtensionsSSRRequest, ClientInternals, CustomHeaders, ModelSortDirection, } from '@aws-amplify/data-schema/runtime'; import { DocumentNode, GraphQLError, Source } from 'graphql'; import { Observable } from 'rxjs'; import { DocumentType, GraphQLAuthMode, } from '@aws-amplify/core/internals/utils'; import { AmplifyServer } from '@aws-amplify/core/internals/adapter-core'; import { CommonPublicClientOptions } from '../internals/types'; export { OperationTypeNode } from 'graphql'; export { CONTROL_MSG, ConnectionState } from './PubSub'; export { SelectionSet } from '@aws-amplify/data-schema/runtime'; export type { CommonPublicClientOptions }; /** * Loose/Unknown options for raw GraphQLAPICategory `graphql()`. */ export interface GraphQLOptions { query: string | DocumentNode; endpoint?: string; variables?: Record; authMode?: GraphQLAuthMode; authToken?: string; apiKey?: string; /** * @deprecated This property should not be used */ userAgentSuffix?: string; } export interface GraphQLResult { data: T; errors?: GraphQLError[]; extensions?: Record; } // Opaque type used for determining the graphql query type declare const queryType: unique symbol; export type GraphQLQuery = T & { readonly [queryType]: 'query' }; export type GraphQLSubscription = T & { readonly [queryType]: 'subscription'; }; /** * Accepts a code generated model type and returns a supertype that * can accept return values from the relevant graphql operations. * * For example: * * ```typescript * import { GraphQLReturnType } from 'aws-amplify/api'; * import { MyModel } from './API'; * import { getMyModel } from './graphql/queries'; * * const [item, setItem] = useState>(); * setItem(await client.graphql({ query: getMyModel }).data.getMyModel!) * ``` * * Trying to assign the result of a `getMyModel` operation directly to a * `MyModel` variables won't necessarily work, because normally-required related * models might not be part of the selection set. * * This util simply makes related model properties optional recursively. */ export type GraphQLReturnType = T extends Record ? { [K in keyof T]?: GraphQLReturnType; } : T; /** * Describes a paged list result from AppSync, which can either * live at the top query or property (e.g., related model) level. */ interface PagedList { __typename: TYPENAME; nextToken?: string | null | undefined; items: T[]; } /** * Recursively looks through a result type and removes nulls and * and undefined from `PagedList` types. * * Although a graphql response might contain empty values in an * array, this will only be the case when we also have errors, * which will then be *thrown*. */ type WithListsFixed = T extends PagedList ? PagedList, NAME> : T extends Record ? { [K in keyof T]: WithListsFixed; } : T; /** * Returns an updated response type to always return a value. */ type NeverEmpty = { [K in keyof T]-?: Exclude, undefined | null>; }; /** * Replaces all list result types in a query result with types to exclude * nulls and undefined from list member unions. * * If empty members are present, there will also be errors present, * and the response will instead be *thrown*. */ type FixedQueryResult = Exclude extends PagedList ? { [K in keyof T]-?: WithListsFixed>; } : T; /** * The return value from a `graphql({query})` call when `query` is a subscription. * * ```ts * // |-- You are here * // v * const subResult: GraphqlSubscriptionResult = client.graphql({ * query: onCreateWidget * }); * * const sub = subResult.subscribe({ * // * // |-- You are here * // v * next(message: GraphqlSubscriptionMessage) { * handle(message.value); // <-- type OnCreateWidgetSubscription * } * }) * ``` */ export type GraphqlSubscriptionResult = Observable< GraphqlSubscriptionMessage >; /** * The shape of messages passed to `next()` from a graphql subscription. E.g., * * ```ts * const sub = client.graphql({ * query: onCreateWidget, * }).subscribe({ * // * // |-- You are here * // v * next(message: GraphqlSubscriptionMessage) { * handle(message.value); // <-- type OnCreateWidgetSubscription * } * }) * ``` */ export interface GraphqlSubscriptionMessage { data: T; } export interface AWSAppSyncRealTimeProviderOptions { appSyncGraphqlEndpoint?: string; authenticationType?: GraphQLAuthMode; query?: string; variables?: Record; apiKey?: string; region?: string; libraryConfigHeaders?(): () => Promise | Headers>; additionalHeaders?: CustomHeaders; } export interface AWSAppSyncRealTimeProvider { subscribe( options?: AWSAppSyncRealTimeProviderOptions, ): Observable>; } export enum GraphQLAuthError { NO_API_KEY = 'No api-key configured', NO_CURRENT_USER = 'No current user', NO_CREDENTIALS = 'No credentials', NO_FEDERATED_JWT = 'No federated jwt', NO_AUTH_TOKEN = 'No auth token specified', } /** * GraphQLSource or string, the type of the parameter for calling graphql.parse * @see: https://graphql.org/graphql-js/language/#parse */ export type GraphQLOperation = Source | string; /** * API V6 `graphql({options})` type that can leverage branded graphql `query` * objects and fallback types. */ export type GraphQLOptionsV6< FALLBACK_TYPES = unknown, TYPED_GQL_STRING extends string = string, Options extends CommonPublicClientOptions = object, > = Options['endpoint'] extends string ? Options['apiKey'] extends string ? { query: TYPED_GQL_STRING | DocumentNode; variables?: GraphQLVariablesV6; authMode?: GraphQLAuthMode; apiKey?: string; authToken?: string; /** * @deprecated This property should not be used */ userAgentSuffix?: string; } : | { query: TYPED_GQL_STRING | DocumentNode; variables?: GraphQLVariablesV6; authMode?: never; apiKey?: never; authToken?: string; /** * @deprecated This property should not be used */ userAgentSuffix?: string; } | { query: TYPED_GQL_STRING | DocumentNode; variables?: GraphQLVariablesV6; authMode: 'apiKey'; apiKey: string; authToken?: string; /** * @deprecated This property should not be used */ userAgentSuffix?: string; } | { query: TYPED_GQL_STRING | DocumentNode; variables?: GraphQLVariablesV6; authMode: Exclude; apiKey?: never; authToken?: string; /** * @deprecated This property should not be used */ userAgentSuffix?: string; } : { query: TYPED_GQL_STRING | DocumentNode; variables?: GraphQLVariablesV6; authMode?: GraphQLAuthMode; apiKey?: string; authToken?: string; /** * @deprecated This property should not be used */ userAgentSuffix?: string; }; /** * Result type for `graphql()` operations that don't include any specific * type information. The result could be either a `Promise` or `Subscription`. * * Invoking code should either cast the result or use `?` and `!` operators to * navigate the result objects. */ export type UnknownGraphQLResponse = | Promise> | GraphqlSubscriptionResult; /** * The expected type for `variables` in a V6 `graphql()` operation with * respect to the given `FALLBACK_TYPES` and `TYPED_GQL_STRING`. */ export type GraphQLVariablesV6< FALLBACK_TYPES = unknown, TYPED_GQL_STRING extends string = string, > = TYPED_GQL_STRING extends GeneratedQuery ? IN : TYPED_GQL_STRING extends GeneratedMutation ? IN : TYPED_GQL_STRING extends GeneratedSubscription ? IN : FALLBACK_TYPES extends GraphQLOperationType ? IN : any; /** * The expected return type with respect to the given `FALLBACK_TYPE` * and `TYPED_GQL_STRING`. */ export type GraphQLResponseV6< FALLBACK_TYPE = unknown, TYPED_GQL_STRING extends string = string, > = TYPED_GQL_STRING extends GeneratedQuery ? Promise>> : TYPED_GQL_STRING extends GeneratedMutation ? Promise>> : TYPED_GQL_STRING extends GeneratedSubscription ? GraphqlSubscriptionResult> : FALLBACK_TYPE extends GraphQLQuery ? Promise> : FALLBACK_TYPE extends GraphQLSubscription ? GraphqlSubscriptionResult : FALLBACK_TYPE extends GraphQLOperationType< infer _, infer CUSTOM_OUT > ? CUSTOM_OUT : UnknownGraphQLResponse; /** * The shape customers can use to provide `T` to `graphql()` to specify both * `IN` and `OUT` types (the type of `variables` and the return type, respectively). * * I.E., * * ```ts * type MyVariablesType = { ... }; * type MyResultType = { ... }; * type MyOperationType = { variables: MyVariablesType, result: MyResultType }; * * const result: MyResultType = graphql("graphql string", { * variables: { * // MyVariablesType * } * }) * ``` */ export interface GraphQLOperationType< IN extends Record, OUT extends Record, > { variables: IN; result: OUT; } /** * Nominal type for branding generated graphql query operation strings with * input and output types. * * E.g., * * ```ts * export const getWidget = `...` as GeneratedQuery< * GetWidgetQueryVariables, * GetWidgetQuery * >; * ``` * * This allows `graphql()` to extract `InputType` and `OutputType` to correctly * assign types to the `variables` and result objects. */ export type GeneratedQuery = string & { __generatedQueryInput: InputType; __generatedQueryOutput: OutputType; }; /** * Nominal type for branding generated graphql mutation operation strings with * input and output types. * * E.g., * * ```ts * export const createWidget = `...` as GeneratedQuery< * CreateWidgetMutationVariables, * CreateWidgetMutation * >; * ``` * * This allows `graphql()` to extract `InputType` and `OutputType` to correctly * assign types to the `variables` and result objects. */ export type GeneratedMutation = string & { __generatedMutationInput: InputType; __generatedMutationOutput: OutputType; }; /** * Nominal type for branding generated graphql mutation operation strings with * input and output types. * * E.g., * * ```ts * export const createWidget = `...` as GeneratedMutation< * CreateWidgetMutationVariables, * CreateWidgetMutation * >; * ``` * * This allows `graphql()` to extract `InputType` and `OutputType` to correctly * assign types to the `variables` and result objects. */ export type GeneratedSubscription = string & { __generatedSubscriptionInput: InputType; __generatedSubscriptionOutput: OutputType; }; export const __amplify = Symbol('amplify'); export const __authMode = Symbol('authMode'); export const __authToken = Symbol('authToken'); export const __apiKey = Symbol('apiKey'); export const __headers = Symbol('headers'); export const __endpoint = Symbol('endpoint'); export function getInternals(client: BaseClient): ClientInternals & { apiKey?: string; endpoint?: string; } { const c = client as any; return { amplify: c[__amplify], apiKey: c[__apiKey], authMode: c[__authMode], authToken: c[__authToken], endpoint: c[__endpoint], headers: c[__headers], } as any; } export type ClientWithModels = | V6Client | V6ClientSSRRequest | V6ClientSSRCookies; export type V6Client< T extends Record = never, Options extends CommonPublicClientOptions = object, > = { graphql: GraphQLMethod; cancel(promise: Promise, message?: string): boolean; isCancelError(error: any): boolean; } & ClientExtensions; export type V6ClientSSRRequest< T extends Record = never, Options extends CommonPublicClientOptions = object, > = { graphql: GraphQLMethodSSR; cancel(promise: Promise, message?: string): boolean; isCancelError(error: any): boolean; } & ClientExtensionsSSRRequest; export type V6ClientSSRCookies< T extends Record = never, Options extends CommonPublicClientOptions = object, > = { graphql: GraphQLMethod; cancel(promise: Promise, message?: string): boolean; isCancelError(error: any): boolean; } & ClientExtensionsSSRCookies; export type GraphQLMethod = < FALLBACK_TYPES = unknown, TYPED_GQL_STRING extends string = string, >( options: GraphQLOptionsV6, additionalHeaders?: CustomHeaders | undefined, ) => GraphQLResponseV6; export type GraphQLMethodSSR = < FALLBACK_TYPES = unknown, TYPED_GQL_STRING extends string = string, >( contextSpec: AmplifyServer.ContextSpec, options: GraphQLOptionsV6, additionalHeaders?: CustomHeaders | undefined, ) => GraphQLResponseV6; /** * @private * * The knobs available for configuring `server/generateClient` internally. */ export interface ServerClientGenerationParams { amplify: | null // null expected when used with `generateServerClient` // closure expected with `generateServerClientUsingCookies` | ((fn: (amplify: AmplifyClassV6) => Promise) => Promise); // global env-sourced config use for retrieving modelIntro config: ResourcesConfig; } export type QueryArgs = Record; export interface ListArgs extends Record { selectionSet?: string[]; filter?: Record; sortDirection?: ModelSortDirection; headers?: CustomHeaders; } export interface AuthModeParams extends Record { authMode?: GraphQLAuthMode; authToken?: string; } export type GenerateServerClientParams = { config: ResourcesConfig; } & CommonPublicClientOptions;