UNPKG

@aws-amplify/api

Version:

Api category of aws-amplify

129 lines (120 loc) • 5.18 kB
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { V6Client } from '@aws-amplify/api-graphql'; import { CommonPublicClientOptions, DefaultCommonClientOptions, generateClient as internalGenerateClient, } from '@aws-amplify/api-graphql/internals'; import { AMPLIFY_CONTEXT_BRAND, AmplifyContext, ResourcesConfig, createAmplifyContextToken, getGlobalContext, hasGlobalContext, isAmplifyContext, } from '@aws-amplify/core'; // Empty config returned by the lazy global-context fallback before // `Amplify.configure()` has run. Mirrors the previous `Amplify` singleton // fallback whose `getConfig()` returned `{}` pre-configure, so `generateClient()` // called before configuration still yields a client whose `models` rebuild on // the subsequent configure Hub event (rather than throwing). const EMPTY_RESOURCES_CONFIG: ResourcesConfig = {}; /** * A lazy {@link AmplifyContext} that resolves the *current* global context on * every access instead of capturing a snapshot at client-generation time. * * `generateClient()` returns a long-lived client whose `graphql()` operations * read config/auth off the stored context per call. Binding a snapshot of * `getGlobalContext()` at generation time would go stale if the app calls * `Amplify.configure()` again — each configure installs a NEW frozen global * context. Delegating through getters keeps reconfiguration honored, preserving * the live-read behavior the previous `Amplify` singleton fallback provided via * `bridgeAmplifyClass`'s getters. Reads before configuration degrade to an empty * config instead of throwing (see {@link EMPTY_RESOURCES_CONFIG}). */ const lazyGlobalContext: AmplifyContext = { get resourcesConfig() { return hasGlobalContext() ? getGlobalContext().resourcesConfig : EMPTY_RESOURCES_CONFIG; }, get libraryOptions() { return hasGlobalContext() ? getGlobalContext().libraryOptions : {}; }, // Stable identity handle for this lazy handle itself (see // AmplifyContextToken). Deliberately NOT delegated to the global context: // the token identifies this long-lived wrapper, and reading it must not // throw pre-configure. token: createAmplifyContextToken(), fetchAuthSession: options => getGlobalContext().fetchAuthSession(options), clearCredentials: () => getGlobalContext().clearCredentials(), getTokens: options => getGlobalContext().getTokens(options), }; // Brand the lazy context so `internalGenerateClient` recognizes it as an // AmplifyContext (via `isAmplifyContext`) and does NOT attempt to bridge it as // an `AmplifyClass` instance. Object.defineProperty(lazyGlobalContext, AMPLIFY_CONTEXT_BRAND, { value: true, enumerable: false, configurable: false, writable: false, }); Object.freeze(lazyGlobalContext); /** * Generates an API client bound to a specific {@link AmplifyContext} instead of * the global `Amplify` singleton. Use this overload when you need to scope a * client to an explicit context (e.g. multi-tenant or server-side rendering * scenarios) rather than the shared singleton configuration. * * @param ctx - The {@link AmplifyContext} the client should resolve its * configuration and auth from. * @param options - Optional client options. * @returns {@link V6Client} * @throws {@link Error} - Throws error when client cannot be generated due to configuration issues. * * @example * ```ts * import { generateClient } from 'aws-amplify/api'; * // `listTodos` is a generated GraphQL query document (from your API's codegen output). * * const client = generateClient(ctx); * const result = await client.graphql({ query: listTodos }); * ``` */ export function generateClient< T extends Record<any, any> = never, Options extends CommonPublicClientOptions = DefaultCommonClientOptions, >(ctx: AmplifyContext, options?: Options): V6Client<T, Options>; /** * Generates an API client that can work with models or raw GraphQL * * @returns {@link V6Client} * @throws {@link Error} - Throws error when client cannot be generated due to configuration issues. */ export function generateClient< T extends Record<any, any> = never, Options extends CommonPublicClientOptions = DefaultCommonClientOptions, >(options?: Options): V6Client<T, Options>; export function generateClient< T extends Record<any, any> = never, Options extends CommonPublicClientOptions = DefaultCommonClientOptions, >( ctxOrOptions?: AmplifyContext | Options, maybeOptions?: Options, ): V6Client<T, Options> { // When the first argument is a branded AmplifyContext, bind the client to it // and treat the second argument as the options. Otherwise fall back to the // lazy global context (resolved fresh per operation, honoring reconfigure) // and treat the first argument as the options. `isAmplifyContext` is inlined // in each ternary so its type guard narrows `ctxOrOptions` in place. const amplify = isAmplifyContext(ctxOrOptions) ? ctxOrOptions : lazyGlobalContext; const options = isAmplifyContext(ctxOrOptions) ? maybeOptions : ctxOrOptions; return internalGenerateClient({ ...(options ?? {}), amplify, }) as unknown as V6Client<T, Options>; }