import { type DeepReadOnlyObject, type UnwrapArray, type UnionToIntersection, type Prettify } from '@aws-amplify/data-schema-types'; import type { Observable } from 'rxjs'; import type { ConversationRoute } from '../../ai/ConversationType'; import type { ClientSchemaByEntityType, ClientSchemaByEntityTypeBaseShape } from '../../ClientSchema'; import type { ExtractNestedTypes } from '../../ClientSchema/utilities/'; import type { Select, StringFilter, NumericFilter, BooleanFilters, SubscriptionStringFilter, SubscriptionNumericFilter, SubscriptionBooleanFilters } from '../../util'; import { AmplifyServer } from '../bridge-types'; export { __modelMeta__, ExtractModelMeta, } from '@aws-amplify/data-schema-types'; type Model = Record; /** * Currently this omits any object-type fields. Update this when we add custom types/enums. */ type NonRelationshipFields = { [Field in keyof M as UnwrapArray extends Record ? never : Field]: M[Field]; }; type WithOptionalsAsNullishOnly = T extends Array ? Array> : T extends (...args: any) => any ? T : T extends object ? { [K in keyof T]-?: WithOptionalsAsNullishOnly; } : Exclude; /** * Selection set-aware CRUDL operation return value type * * @returns model type with default selection set; otherwise generates return type from custom sel. set. Optionality is removed from both return types. */ type ReturnValue>> = Paths extends undefined | never[] ? WithOptionalsAsNullishOnly : WithOptionalsAsNullishOnly>; /** * This mapped type traverses the SelectionSetReturnValue result and the original FlatModel, restoring array types * that were flattened in DeepPickFromPath * * @typeParam Result - this is the result of applying the selection set path to FlatModel; return type of UnionToIntersection> * @typeParam FlatModel - the reference model shape; return type of ResolvedModel * * Note: we wrap `Result` and `FlatModel` in NonNullable, because recursive invocations of this mapped type * can result in the type arguments containing `{} | null | undefined` which breaks indexed access, e.g. Result[K] * * Using NonNullable<> directly inside the mapped type is significantly more performant here than attempting to pre-compute in the type params, * e.g., `type RestoreArrays, NonNullableFlatModel = NonNullable> = {...}` */ type RestoreArrays = { [K in keyof NonNullable]: K extends keyof NonNullable ? Array extends NonNullable[K] ? HandleArrayNullability[K], NonNullable[K]> : NonNullable[K] extends Record ? RestoreArrays[K], NonNullable[K]> : NonNullable[K] : never; }; /** * This mapped type gets called by RestoreArrays and it restores the expected * nullability in array fields (e.g. nullable vs. required value & nullable vs. required array) */ type HandleArrayNullability = Array extends Result ? Result : NonNullable extends Array ? null extends FlatModel ? null extends InnerValue ? // value and array are nullable - a.ref('SomeType').array() Array> | null> | null : // value required; array nullable - a.ref('SomeType').required().array() Array>> | null : null extends InnerValue ? Array> | null> : Array>> : never; /** * Generates flattened, readonly return type using specified custom sel. set */ type CustomSelectionSetReturnValue = Prettify>, FlatModel>>>; /** * Picks object properties that match provided dot-separated Path * * @typeParam FlatModel * @typeParam Path - string union of dot-separated paths * * @returns union of object slices * * @example * ### Given * ```ts * FlatModel = { title: string; description?: string | null; comments: { content: string; readonly id: string; readonly createdAt: string; readonly updatedAt: string; }[]; readonly id: string; readonly createdAt: string; readonly updatedAt: string; } Path = 'title' | 'comments.id' | 'comments.content' * ``` * ### Returns * ```ts * { title: string } | { comments: { id: string} } | { comments: { content: string} } * ``` * * @privateRemarks * * Intersections on arrays have unexpected behavior in TypeScript: * see: https://github.com/microsoft/TypeScript/issues/41874 and https://github.com/microsoft/TypeScript/issues/39693 * * To work around this limitation, DeepPickFromPath flattens Arrays of Models (e.g. { comments: { id: string}[] } => { comments: { id: string} }) * Arrays are then restored downstream in RestoreArrays */ type DeepPickFromPath = FlatModel extends undefined ? DeepPickFromPath, Path> | undefined : FlatModel extends null ? DeepPickFromPath, Path> | null : FlatModel extends any[] ? DeepPickFromPath, Path> : Path extends `${infer Head}.${infer Tail}` ? Head extends keyof FlatModel ? Tail extends '*' ? { [k in Head]: FlatModel[Head] extends Record ? NonRelationshipFields> : NonRelationshipFields>; } : { [k in Head]: DeepPickFromPath; } : never : Path extends keyof FlatModel ? { [K in Path]: FlatModel[Path]; } : never; /** * This mapped type gets called by DeepPickFromPath when user uses selection * set on a query to a many-to-many relationship join table. It flattens the Arrays of Models referenced in the join table. * * (e.g. { customer: { orders: Order[]} } => { customer: { orders: Order} }) */ type FlattenArrays = { [K in keyof T]: UnwrapArray; }; /** * Generates custom selection set type with up to 6 levels of nested fields * * @returns string[] where each string is a field in the model * recurses over nested objects - such as relationships and custom types - generating a `field.*` type value to select all fields in that nested type, * as well as a dot-delimited set of fields for fine-grained selection of particular fields in the nested type (see example below) * * @example * ```ts * FlatModel = { * id: string * title: string * comments: { * id:: string * content: string * }[] * } *``` * * ### Result * ``` * 'id' | 'title' | 'comments.*' | 'comments.id' | 'comments.content' * ``` * * @privateRemarks * * explicit recursion depth pattern ref: https://github.com/microsoft/TypeScript/blob/main/src/lib/es2019.array.d.ts#L1-L5 * * this pattern puts an upper bound on the levels of recursion in our mapped type * * it guards against infinite recursion when generating the selection set type for deeply-nested models * and especially for bi-directional relationships which are infinitely recursable by their nature * */ type ModelPathInner, Depth extends number = 5, // think of this as the initialization expr. in a for loop (e.g. `let depth = 5`) RecursionLoop extends number[] = [-1, 0, 1, 2, 3, 4], Field = keyof FlatModel> = { done: Field extends string ? `${Field}.*` : never; recur: Field extends string ? NonNullable> extends Record ? `${Field}.${ModelPathInner>, RecursionLoop[Depth]>}` | `${Field}.*` : `${Field}` : never; }[Depth extends -1 ? 'done' : 'recur']; export type ModelPath> = ModelPathInner; export type SelectionSet>, FlatModel extends Record = Model extends ClientSchemaByEntityTypeBaseShape['models'][string] ? Model['__meta']['flatModel'] : Record> = Model extends ClientSchemaByEntityTypeBaseShape['models'][string] ? WithOptionalsAsNullishOnly> : any; /** * See: https://spec.graphql.org/draft/#sec-Errors */ export interface GraphQLFormattedError { /** * A short, human-readable summary of the problem that **SHOULD NOT** change * from occurrence to occurrence of the problem, except for purposes of * localization. */ readonly message: string; /** * The AppSync exception category. Indicates the source of the error. */ readonly errorType: string; /** * Additional error metadata that can be surfaced via error handling resolver utils: * * JS - https://docs.aws.amazon.com/appsync/latest/devguide/built-in-util-js.html#utility-helpers-in-error-js * * VTL - https://docs.aws.amazon.com/appsync/latest/devguide/utility-helpers-in-util.html#utility-helpers-in-error */ readonly errorInfo: null | { [key: string]: unknown; }; /** * If an error can be associated to a particular point in the requested * GraphQL document, it should contain a list of locations. */ readonly locations?: ReadonlyArray; /** * If an error can be associated to a particular field in the GraphQL result, * it _must_ contain an entry with the key `path` that details the path of * the response field which experienced the error. This allows clients to * identify whether a null result is intentional or caused by a runtime error. */ readonly path?: ReadonlyArray; /** * Reserved for implementors to extend the protocol however they see fit, * and hence there are no additional restrictions on its contents. */ readonly extensions?: { [key: string]: unknown; }; } /** * Represents a location in a Source. */ export interface SourceLocation { readonly line: number; readonly column: number; } export type SingularReturnValue = Promise<{ data: T | null; errors?: GraphQLFormattedError[]; extensions?: { [key: string]: any; }; }>; export type ListReturnValue = Promise<{ data: Array; nextToken?: string | null; errors?: GraphQLFormattedError[]; extensions?: { [key: string]: any; }; }>; export type ObservedReturnValue = Observable; export type ObserveQueryReturnValue = Observable<{ items: T[]; isSynced: boolean; }>; export type LazyLoader = (options?: IsArray extends true ? { authMode?: AuthMode; authToken?: string; limit?: number; nextToken?: string | null; headers?: CustomHeaders; } : { authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }) => IsArray extends true ? ListReturnValue>> : SingularReturnValue>; export type AuthMode = 'apiKey' | 'iam' | 'identityPool' | 'oidc' | 'userPool' | 'lambda' | 'none'; type LogicalFilters = { and?: ModelFilter | ModelFilter[]; or?: ModelFilter | ModelFilter[]; not?: ModelFilter; }; type ModelFilter = LogicalFilters & { [K in keyof Model['type'] as Model['type'][K] extends LazyLoader ? never : K]?: boolean extends Model['type'][K] ? BooleanFilters : number extends Model['type'][K] ? NumericFilter : StringFilter; }; type LogicalSubscriptionFilters = { and?: ModelSubscriptionFilter | ModelSubscriptionFilter[]; or?: ModelSubscriptionFilter | ModelSubscriptionFilter[]; not?: ModelSubscriptionFilter; }; type ModelSubscriptionFilter = LogicalSubscriptionFilters & { [K in keyof Model['type'] as Model['type'][K] extends LazyLoader ? never : K]?: boolean extends Model['type'][K] ? SubscriptionBooleanFilters : number extends Model['type'][K] ? SubscriptionNumericFilter : SubscriptionStringFilter; }; export type ModelSortDirection = 'ASC' | 'DESC'; type ListCpkOptions = unknown extends Model['__meta']['listOptionsPkParams'] ? unknown : Model['__meta']['listOptionsPkParams'] & { sortDirection?: ModelSortDirection; }; interface ClientSecondaryIndexField { input: object; } type IndexQueryMethods = { [K in keyof Select]: IndexQueryMethod[K], Context>; }; type IndexQueryMethod = Model['__meta']['flatModel']> = Context extends 'CLIENT' | 'COOKIES' ? > = never[]>(input: Method['input'], options?: { filter?: ModelFilter; sortDirection?: ModelSortDirection; limit?: number; nextToken?: string | null; selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }) => ListReturnValue>> : > = never[]>(contextSpec: AmplifyServer.ContextSpec, input: Method['input'], options?: { filter?: ModelFilter; sortDirection?: ModelSortDirection; limit?: number; nextToken?: string | null; selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }) => ListReturnValue>>; type ModelTypesClient = Model['__meta']['flatModel']> = IndexQueryMethods & Omit<{ create> = never[]>(model: Model['createType'], options?: { selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): SingularReturnValue>>; update> = never[]>(model: Model['updateType'], options?: { selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): SingularReturnValue>>; delete> = never[]>(identifier: Model['deleteType'], options?: { selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): SingularReturnValue>>; get> = never[]>(identifier: Model['identifier'], options?: { selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): SingularReturnValue>>; list> = never[]>(options?: ListCpkOptions & { filter?: ModelFilter; limit?: number; nextToken?: string | null; selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): ListReturnValue>>; onCreate> = never[]>(options?: { filter?: ModelSubscriptionFilter; selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): ObservedReturnValue>>; onUpdate> = never[]>(options?: { filter?: ModelSubscriptionFilter; selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): ObservedReturnValue>>; onDelete> = never[]>(options?: { filter?: ModelSubscriptionFilter; selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): ObservedReturnValue>>; observeQuery[] = never[]>(options?: { filter?: ModelFilter; selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; }): ObserveQueryReturnValue>>; }, keyof Model['__meta']['disabledOperations']>; type ModelTypesSSRCookies = Model['__meta']['flatModel']> = IndexQueryMethods & Omit<{ create> = never[]>(model: Model['createType'], options?: { selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): SingularReturnValue>>; update> = never[]>(model: Model['updateType'], options?: { selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): SingularReturnValue>>; delete> = never[]>(identifier: Model['deleteType'], options?: { selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): SingularReturnValue>>; get> = never[]>(identifier: Model['identifier'], options?: { selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): SingularReturnValue>>; list> = never[]>(options?: ListCpkOptions & { filter?: ModelFilter; sortDirection?: ModelSortDirection; limit?: number; nextToken?: string | null; selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): ListReturnValue>>; }, keyof Model['__meta']['disabledOperations']>; type ModelTypesSSRRequest = Model['__meta']['flatModel']> = IndexQueryMethods & Omit<{ create> = never[]>(contextSpec: AmplifyServer.ContextSpec, model: Model['createType'], options?: { selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): SingularReturnValue>>; update> = never[]>(contextSpec: AmplifyServer.ContextSpec, model: Model['updateType'], options?: { selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): SingularReturnValue>>; delete> = never[]>(contextSpec: AmplifyServer.ContextSpec, identifier: Model['deleteType'], options?: { selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): SingularReturnValue>>; get> = never[]>(contextSpec: AmplifyServer.ContextSpec, identifier: Model['identifier'], options?: { selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): SingularReturnValue>>; list> = never[]>(contextSpec: AmplifyServer.ContextSpec, options?: ListCpkOptions & { filter?: ModelFilter; sortDirection?: ModelSortDirection; limit?: number; nextToken?: string | null; selectionSet?: SelectionSet; authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }): ListReturnValue>>; }, keyof Model['__meta']['disabledOperations']>; type ContextType = 'CLIENT' | 'COOKIES' | 'REQUEST'; export type ModelTypes, Context extends ContextType = 'CLIENT', Schema extends ClientSchemaByEntityType = ClientSchemaByEntityType> = { [ModelName in keyof Schema['models']]: Context extends 'CLIENT' ? ModelTypesClient : Context extends 'COOKIES' ? ModelTypesSSRCookies : Context extends 'REQUEST' ? ModelTypesSSRRequest : never; }; export type CustomQueries, Context extends ContextType = 'CLIENT', Schema extends ClientSchemaByEntityType = ClientSchemaByEntityType> = CustomOperations; export type CustomMutations, Context extends ContextType = 'CLIENT', Schema extends ClientSchemaByEntityType = ClientSchemaByEntityType> = CustomOperations; export type CustomSubscriptions, Context extends ContextType = 'CLIENT', Schema extends ClientSchemaByEntityType = ClientSchemaByEntityType> = CustomOperations; type CustomOperationMethodOptions = { authMode?: AuthMode; authToken?: string; headers?: CustomHeaders; }; /** * Generates Custom Operations function params based on whether .arguments() were specified in the schema builder */ type CustomOperationFnParams | never> = [ Args ] extends [never] ? [CustomOperationMethodOptions?] : [Args, CustomOperationMethodOptions?]; export type CustomOperations = { [OpName in keyof OperationDefs]: { CLIENT: (...params: CustomOperationFnParams) => OperationDefs[OpName]['operationType'] extends 'Subscription' ? ObservedReturnValue : SingularReturnValue; COOKIES: (...params: CustomOperationFnParams) => SingularReturnValue; REQUEST: (contextSpec: AmplifyServer.ContextSpec, ...params: CustomOperationFnParams) => SingularReturnValue; }[Context]; }; /** * The utility type that is used to infer the type (interface) of the generated * `client.enums` property. * * @example * // The schema: * { * TodoStatus: a.enum(['Planned' | 'InProgress' | 'Completed']), * } * * // The inferred interface of the `client.enums`: * { * TodoStatus: { * values: () => Array<'Planned' | 'InProgress' | 'Completed'>; * } * } */ export type EnumTypes> = { [EnumName in keyof AllEnumTypesRecursively]: { values: () => Array[EnumName]['type']>; }; }; type AllEnumTypesRecursively> = ClientSchemaByEntityType['enums'] & Select>, { __entityType: 'enum'; }>; /** * Request options that are passed to custom header functions. * `method` and `headers` are not included in custom header functions passed to * subscriptions. */ export type RequestOptions = { url: string; queryString: string; method?: string; }; /** * Custom headers that can be passed either to the client or to individual * model operations, either as a static object or a function that returns a * promise. */ export type CustomHeaders = Record | ((requestOptions?: RequestOptions) => Promise>); export type ClientExtensions = never> = { models: ModelTypes; enums: EnumTypes; queries: CustomQueries; mutations: CustomMutations; subscriptions: CustomSubscriptions; conversations: ConversationRoutes; generations: Generations; }; export type ClientExtensionsSSRRequest = never> = { models: ModelTypes; enums: EnumTypes; queries: CustomQueries; mutations: CustomMutations; }; export type ClientExtensionsSSRCookies = never> = { models: ModelTypes; enums: EnumTypes; queries: CustomQueries; mutations: CustomMutations; }; export type ConversationRoutes, Schema extends ClientSchemaByEntityType = ClientSchemaByEntityType> = { [ConversationName in keyof Schema['conversations']]: ConversationRoute; }; export type Generations, Schema extends ClientSchemaByEntityType = ClientSchemaByEntityType> = CustomOperations;