// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { Hub } from '@aws-amplify/core'; import { CustomMutations, CustomQueries, CustomSubscriptions, EnumTypes, ModelTypes, addSchemaToClient, } from '@aws-amplify/data-schema/runtime'; import { V6Client, __amplify, __apiKey, __authMode, __authToken, __endpoint, __headers, getInternals, } from '../types'; import { isApiGraphQLConfig } from './utils/runtimeTypeGuards/isApiGraphQLProviderConfig'; import { isConfigureEventWithResourceConfig } from './utils/runtimeTypeGuards/isConfigureEventWithResourceConfig'; import { cancel, graphql, isCancelError } from './v6'; import { ClientGenerationParams } from './types'; /** * @private * * Creates a client that can be used to make GraphQL requests, using a provided `AmplifyClassV6` * compatible context object for config and auth fetching. * * @param params * @returns */ export function generateClient< T extends Record = never, Options extends ClientGenerationParams = ClientGenerationParams, >(params: Options): V6Client { const client = { [__amplify]: params.amplify, [__authMode]: params.authMode, [__authToken]: params.authToken, [__apiKey]: 'apiKey' in params ? params.apiKey : undefined, [__endpoint]: 'endpoint' in params ? params.endpoint : undefined, [__headers]: params.headers, graphql, cancel, isCancelError, models: emptyProperty as ModelTypes, enums: emptyProperty as EnumTypes, queries: emptyProperty as CustomQueries, mutations: emptyProperty as CustomMutations, subscriptions: emptyProperty as CustomSubscriptions, } as any; const apiGraphqlConfig = params.amplify.getConfig().API?.GraphQL; if (client[__endpoint]) { if (!client[__authMode]) { throw new Error( 'generateClient() requires an explicit `authMode` when `endpoint` is provided.', ); } if (client[__authMode] === 'apiKey' && !client[__apiKey]) { throw new Error( "generateClient() requires an explicit `apiKey` when `endpoint` is provided and `authMode = 'apiKey'`.", ); } } if (!client[__endpoint]) { if (isApiGraphQLConfig(apiGraphqlConfig)) { addSchemaToClient(client, apiGraphqlConfig, getInternals); } else { // This happens when the `Amplify.configure()` call gets evaluated after the `generateClient()` call. // // Cause: when the `generateClient()` and the `Amplify.configure()` calls are located in // different source files, script bundlers may randomly arrange their orders in the production // bundle. // // With the current implementation, the `client.models` instance created by `generateClient()` // will be rebuilt on every `Amplify.configure()` call that's provided with a valid GraphQL // provider configuration. // // TODO: revisit, and reverify this approach when enabling multiple clients for multi-endpoints // configuration. generateModelsPropertyOnAmplifyConfigure(client); } } return client as any; } const generateModelsPropertyOnAmplifyConfigure = (clientRef: any) => { Hub.listen('core', coreEvent => { if (!isConfigureEventWithResourceConfig(coreEvent.payload)) { return; } const apiGraphQLConfig = coreEvent.payload.data.API?.GraphQL; if (isApiGraphQLConfig(apiGraphQLConfig)) { addSchemaToClient(clientRef, apiGraphQLConfig, getInternals); } }); }; const emptyProperty = new Proxy( {}, { get() { throw new Error( 'Client could not be generated. This is likely due to `Amplify.configure()` not being called prior to `generateClient()` or because the configuration passed to `Amplify.configure()` is missing GraphQL provider configuration.', ); }, }, );