diff --git a/.vscode/settings.json b/.vscode/settings.json index 88b69ad58fc..f24d70ae734 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,6 @@ { "editor.detectIndentation": false, "editor.insertSpaces": false, - "editor.tabSize": 4, "prettier.requireConfig": true, "typescript.tsdk": "node_modules/typescript/lib", "formattingToggle.affects": [ diff --git a/packages/api-graphql/__tests__/fixtures/modeled/amplifyconfiguration.ts b/packages/api-graphql/__tests__/fixtures/modeled/amplifyconfiguration.ts index b3235d910ef..c6a6beed9d8 100644 --- a/packages/api-graphql/__tests__/fixtures/modeled/amplifyconfiguration.ts +++ b/packages/api-graphql/__tests__/fixtures/modeled/amplifyconfiguration.ts @@ -1580,6 +1580,32 @@ const amplifyConfig = { }, }, }, + subscriptions: { + onPostLiked: { + name: 'onPostLiked', + isArray: false, + type: { + model: 'Post', + }, + isRequired: false, + }, + onPostUpdated: { + name: 'onPostUpdated', + isArray: false, + type: { + model: 'Post', + }, + isRequired: false, + arguments: { + postId: { + name: 'postId', + isArray: false, + type: 'String', + isRequired: false, + }, + }, + }, + }, }, }; export default amplifyConfig; diff --git a/packages/api-graphql/__tests__/fixtures/modeled/schema.ts b/packages/api-graphql/__tests__/fixtures/modeled/schema.ts index 29d44425342..7786ac079b3 100644 --- a/packages/api-graphql/__tests__/fixtures/modeled/schema.ts +++ b/packages/api-graphql/__tests__/fixtures/modeled/schema.ts @@ -83,9 +83,9 @@ const schema = a.schema({ viewCount: a.integer(), status: a.enum(['draft', 'pending', 'published']), }) - .secondaryIndexes([ - a.index('title'), - a.index('description').sortKeys(['viewCount']), + .secondaryIndexes(index => [ + index('title'), + index('description').sortKeys(['viewCount']), ]), Product: a .model({ @@ -120,7 +120,7 @@ const schema = a.schema({ argumentContent: a.string().required(), }) .returns(a.ref('EchoResult')) - .function('echoFunction') + .handler(a.handler.function('echoFunction')) .authorization([a.allow.public()]), // custom query returning a primitive type @@ -130,7 +130,7 @@ const schema = a.schema({ inputString: a.string().required(), }) .returns(a.string()) - .function('echoFunction') + .handler(a.handler.function('echoFunction')) .authorization([a.allow.public()]), echoNestedCustomTypes: a .query() @@ -138,7 +138,7 @@ const schema = a.schema({ input: a.string().required(), }) .returns(a.ref('ProductTrackingMeta')) - .function('echoFunction') + .handler(a.handler.function('echoFunction')) .authorization([a.allow.public()]), echoModelHasNestedTypes: a .query() @@ -146,7 +146,7 @@ const schema = a.schema({ input: a.string().required(), }) .returns(a.ref('Product')) - .function('echoFunction') + .handler(a.handler.function('echoFunction')) .authorization([a.allow.public()]), // custom mutation returning a non-model type PostLikeResult: a.customType({ @@ -158,7 +158,7 @@ const schema = a.schema({ postId: a.id().required(), }) .returns(a.ref('PostLikeResult')) - .function('echoFunction') + .handler(a.handler.function('echoFunction')) .authorization([a.allow.private()]), // custom mutation returning a model type @@ -182,9 +182,21 @@ const schema = a.schema({ postId: a.id().required(), }) .returns(a.ref('Post')) - .function('echoFunction') + .handler(a.handler.function('echoFunction')) .authorization([a.allow.private()]), + onPostLiked: a + .subscription() + .for(a.ref('likePostReturnPost')) + .returns(a.ref('Post')) + .handler(a.handler.custom({ entry: './jsResolver_base.js' })), + + onPostUpdated: a + .subscription() + .for(a.ref('Post').mutations(['update'])) + .arguments({ postId: a.string() }) + .returns(a.ref('Post')) + .handler(a.handler.custom({ entry: './jsResolver_base.js' })), //#endregion }); diff --git a/packages/api-graphql/__tests__/internals/generateClient.test.ts b/packages/api-graphql/__tests__/internals/generateClient.test.ts index 7b8b4274d15..2a85fbc69d6 100644 --- a/packages/api-graphql/__tests__/internals/generateClient.test.ts +++ b/packages/api-graphql/__tests__/internals/generateClient.test.ts @@ -10,7 +10,6 @@ import { expectSubWithlibraryConfigHeaders, } from '../utils/expects'; import { Observable, from } from 'rxjs'; -import * as internals from '../../src/internals'; const serverManagedFields = { id: 'some-id', @@ -1996,7 +1995,9 @@ describe('generateClient', () => { const spy = jest.fn(() => from([graphqlMessage])); (raw.GraphQLAPI as any).appSyncRealTime = { subscribe: spy }; - client.models.Note.onCreate().subscribe({ + const onC = client.models.Note.onCreate(); + + onC.subscribe({ next(value) { expect(spy).toHaveBeenCalledWith( expect.objectContaining({ @@ -5181,6 +5182,8 @@ describe('generateClient', () => { beforeEach(() => { jest.clearAllMocks(); jest.resetAllMocks(); + jest.restoreAllMocks(); + Amplify.configure(configFixture as any); jest @@ -5392,6 +5395,121 @@ describe('generateClient', () => { expect(comments[0]).toEqual(expect.objectContaining(listCommentItem)); }); + test('can subscribe to custom subscription', done => { + const postToSend = { + __typename: 'Post', + ...serverManagedFields, + content: 'a lovely post', + }; + + const graphqlMessage = { + data: { + onPostLiked: postToSend, + }, + }; + + const client = generateClient({ amplify: Amplify }); + + const spy = jest.fn(() => from([graphqlMessage])); + (raw.GraphQLAPI as any).appSyncRealTime = { subscribe: spy }; + + const spyGql = jest.spyOn(raw.GraphQLAPI as any, 'graphql'); + + const expectedOperation = 'subscription'; + const expectedFieldAndSelectionSet = + 'onPostLiked {id content owner createdAt updatedAt}'; + + const sub = client.subscriptions.onPostLiked().subscribe({ + next(value) { + expect(value).toEqual(expect.objectContaining(postToSend)); + + expect(spyGql).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + query: expect.stringContaining(expectedOperation), + variables: {}, + }), + expect.anything(), + ); + expect(spyGql).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + query: expect.stringContaining(expectedFieldAndSelectionSet), + variables: {}, + }), + expect.anything(), + ); + done(); + }, + error(error) { + expect(error).toBeUndefined(); + done('bad news!'); + }, + }); + + sub.unsubscribe(); + }); + + test('can subscribe to custom subscription with args', done => { + const postToSend = { + __typename: 'Post', + ...serverManagedFields, + postId: 'abc123', + content: 'a lovely post', + }; + + const graphqlMessage = { + data: { + onPostLiked: postToSend, + }, + }; + + const client = generateClient({ amplify: Amplify }); + + const spy = jest.fn(() => from([graphqlMessage])); + (raw.GraphQLAPI as any).appSyncRealTime = { subscribe: spy }; + + const spyGql = jest.spyOn(raw.GraphQLAPI as any, 'graphql'); + + const expectedOperation = 'subscription($postId: String)'; + const expectedFieldAndSelectionSet = + 'onPostUpdated(postId: $postId) {id content owner createdAt updatedAt}'; + + const sub = client.subscriptions + .onPostUpdated({ postId: 'abc123' }) + .subscribe({ + next(value) { + expect(value).toEqual(expect.objectContaining(postToSend)); + + expect(spyGql).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + query: expect.stringContaining(expectedOperation), + + variables: { postId: 'abc123' }, + }), + expect.anything(), + ); + expect(spyGql).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + query: expect.stringContaining(expectedFieldAndSelectionSet), + + variables: { postId: 'abc123' }, + }), + expect.anything(), + ); + done(); + }, + error(error) { + expect(error).toBeUndefined(); + done('bad news!'); + }, + }); + + sub.unsubscribe(); + }); + test('includes client level headers', async () => { const spy = mockApiResponse({ data: { diff --git a/packages/api-graphql/__tests__/internals/server/generateClientWithAmplifyInstance.test.ts b/packages/api-graphql/__tests__/internals/server/generateClientWithAmplifyInstance.test.ts index 50967b36395..1b5370711db 100644 --- a/packages/api-graphql/__tests__/internals/server/generateClientWithAmplifyInstance.test.ts +++ b/packages/api-graphql/__tests__/internals/server/generateClientWithAmplifyInstance.test.ts @@ -425,7 +425,7 @@ describe('server generateClient', () => { return result; }); - const mockContextSpec = {}; + const mockContextSpec = { token: { value: Symbol('test') } }; const result = await client.queries.echo(mockContextSpec, { argumentContent: 'echo argumentContent value', diff --git a/packages/api-graphql/package.json b/packages/api-graphql/package.json index 54338beb6c8..5071b0c6ab1 100644 --- a/packages/api-graphql/package.json +++ b/packages/api-graphql/package.json @@ -72,7 +72,7 @@ }, "homepage": "https://aws-amplify.github.io/", "devDependencies": { - "@aws-amplify/data-schema": "^0.13.9", + "@aws-amplify/data-schema": "^0.14.1", "@rollup/plugin-typescript": "11.1.5", "rollup": "^4.9.6", "typescript": "5.0.2" @@ -87,7 +87,7 @@ "dependencies": { "@aws-amplify/api-rest": "4.0.21", "@aws-amplify/core": "6.0.21", - "@aws-amplify/data-schema-types": "^0.7.6", + "@aws-amplify/data-schema-types": "^0.7.11", "@aws-sdk/types": "3.387.0", "graphql": "15.8.0", "rxjs": "^7.8.1", diff --git a/packages/api-graphql/src/internals/APIClient.ts b/packages/api-graphql/src/internals/APIClient.ts index 01bb0d92146..1231fb42b2e 100644 --- a/packages/api-graphql/src/internals/APIClient.ts +++ b/packages/api-graphql/src/internals/APIClient.ts @@ -19,7 +19,6 @@ import { ListArgs, QueryArgs, V6Client, - V6ClientSSRRequest, __authMode, __authToken, __headers, @@ -138,9 +137,7 @@ export function initializeModel( options?: LazyLoadOptions, ) => { if (record[targetNames[0]]) { - return ( - client as V6ClientSSRRequest> - ).models[relatedModelName].get( + return (client as any).models[relatedModelName].get( contextSpec, { [relatedModelPKFieldName]: record[targetNames[0]], @@ -160,9 +157,7 @@ export function initializeModel( options?: LazyLoadOptions, ) => { if (record[targetNames[0]]) { - return (client as V6Client>).models[ - relatedModelName - ].get( + return (client as any).models[relatedModelName].get( { [relatedModelPKFieldName]: record[targetNames[0]], ...sortKeyValues, @@ -213,15 +208,16 @@ export function initializeModel( options?: LazyLoadOptions, ) => { if (record[parentPk]) { - return ( - client as V6ClientSSRRequest> - ).models[relatedModelName].list(contextSpec, { - filter: { and: hasManyFilter }, - limit: options?.limit, - nextToken: options?.nextToken, - authMode: options?.authMode || authMode, - authToken: options?.authToken || authToken, - }); + return (client as any).models[relatedModelName].list( + contextSpec, + { + filter: { and: hasManyFilter }, + limit: options?.limit, + nextToken: options?.nextToken, + authMode: options?.authMode || authMode, + authToken: options?.authToken || authToken, + }, + ); } return []; @@ -231,9 +227,7 @@ export function initializeModel( options?: LazyLoadOptions, ) => { if (record[parentPk]) { - return (client as V6Client>).models[ - relatedModelName - ].list({ + return (client as any).models[relatedModelName].list({ filter: { and: hasManyFilter }, limit: options?.limit, nextToken: options?.nextToken, @@ -265,15 +259,16 @@ export function initializeModel( options?: LazyLoadOptions, ) => { if (record[parentPk]) { - return ( - client as V6ClientSSRRequest> - ).models[relatedModelName].list(contextSpec, { - filter: { and: hasManyFilter }, - limit: options?.limit, - nextToken: options?.nextToken, - authMode: options?.authMode || authMode, - authToken: options?.authToken || authToken, - }); + return (client as any).models[relatedModelName].list( + contextSpec, + { + filter: { and: hasManyFilter }, + limit: options?.limit, + nextToken: options?.nextToken, + authMode: options?.authMode || authMode, + authToken: options?.authToken || authToken, + }, + ); } return []; @@ -283,9 +278,7 @@ export function initializeModel( options?: LazyLoadOptions, ) => { if (record[parentPk]) { - return (client as V6Client>).models[ - relatedModelName - ].list({ + return (client as any).models[relatedModelName].list({ filter: { and: hasManyFilter }, limit: options?.limit, nextToken: options?.nextToken, diff --git a/packages/api-graphql/src/internals/generateClient.ts b/packages/api-graphql/src/internals/generateClient.ts index 19b7dcadd75..736f6de94ae 100644 --- a/packages/api-graphql/src/internals/generateClient.ts +++ b/packages/api-graphql/src/internals/generateClient.ts @@ -4,6 +4,7 @@ import { Hub } from '@aws-amplify/core'; import { CustomMutations, CustomQueries, + CustomSubscriptions, EnumTypes, ModelTypes, } from '@aws-amplify/data-schema-types'; @@ -23,6 +24,7 @@ import { isApiGraphQLConfig } from './utils/runtimeTypeGuards/isApiGraphQLProvid import { generateCustomMutationsProperty, generateCustomQueriesProperty, + generateCustomSubscriptionsProperty, } from './generateCustomOperationsProperty'; import { ClientGenerationParams } from './types'; import { isConfigureEventWithResourceConfig } from './utils/runtimeTypeGuards/isConfigureEventWithResourceConfig'; @@ -51,6 +53,7 @@ export function generateClient = never>( 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; @@ -63,6 +66,10 @@ export function generateClient = never>( client, apiGraphqlConfig, ); + client.subscriptions = generateCustomSubscriptionsProperty( + client, + apiGraphqlConfig, + ); } else { // This happens when the `Amplify.configure()` call gets evaluated after the `generateClient()` call. // @@ -101,6 +108,10 @@ const generateModelsPropertyOnAmplifyConfigure = (clientRef: any) => { clientRef, apiGraphQLConfig, ); + clientRef.subscriptions = generateCustomSubscriptionsProperty( + clientRef, + apiGraphQLConfig, + ); } }); }; diff --git a/packages/api-graphql/src/internals/generateCustomOperationsProperty.ts b/packages/api-graphql/src/internals/generateCustomOperationsProperty.ts index d6dadbe38e5..95d1470a82f 100644 --- a/packages/api-graphql/src/internals/generateCustomOperationsProperty.ts +++ b/packages/api-graphql/src/internals/generateCustomOperationsProperty.ts @@ -1,6 +1,10 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { CustomMutations, CustomQueries } from '@aws-amplify/data-schema-types'; +import { + CustomMutations, + CustomQueries, + CustomSubscriptions, +} from '@aws-amplify/data-schema-types'; import { GraphQLProviderConfig, ModelIntrospectionSchema, @@ -10,16 +14,23 @@ import { V6Client, __amplify } from '../types'; import { customOpFactory } from './operations/custom'; -type OpTypes = 'queries' | 'mutations'; +type OpTypes = 'queries' | 'mutations' | 'subscriptions'; type CustomOpsProperty< T extends Record, OpType extends OpTypes, -> = OpType extends 'queries' ? CustomQueries : CustomMutations; +> = OpType extends 'queries' + ? CustomQueries + : OpType extends 'mutations' + ? CustomMutations + : OpType extends 'subscriptions' + ? CustomSubscriptions + : never; const operationTypeMap = { queries: 'query', mutations: 'mutation', + subscriptions: 'subscription', } as const; export function generateCustomOperationsProperty< @@ -88,3 +99,14 @@ export function generateCustomQueriesProperty>( 'queries', ); } + +export function generateCustomSubscriptionsProperty>( + client: V6Client>, + config: GraphQLProviderConfig['GraphQL'], +) { + return generateCustomOperationsProperty( + client, + config, + 'subscriptions', + ); +} diff --git a/packages/api-graphql/src/internals/operations/custom.ts b/packages/api-graphql/src/internals/operations/custom.ts index 1ce0a5bc7ec..a5c4ac8b69e 100644 --- a/packages/api-graphql/src/internals/operations/custom.ts +++ b/packages/api-graphql/src/internals/operations/custom.ts @@ -5,6 +5,7 @@ import { CustomOperation, ModelIntrospectionSchema, } from '@aws-amplify/core/internals/utils'; +import { map } from 'rxjs'; import { authModeParams, @@ -18,14 +19,36 @@ import { import { AuthModeParams, ClientWithModels, - GraphQLOptionsV6, GraphQLResult, + GraphqlSubscriptionResult, ListArgs, QueryArgs, V6Client, V6ClientSSRRequest, } from '../../types'; +type CustomOperationOptions = AuthModeParams & ListArgs; + +// these are the 4 possible sets of arguments custom operations methods can receive +type OpArgs = + // SSR Request Client w Args defined + | [AmplifyServer.ContextSpec, QueryArgs, CustomOperationOptions] + // SSR Request Client without Args defined + | [AmplifyServer.ContextSpec, CustomOperationOptions] + // Client or SSR Cookies Client w Args defined + | [QueryArgs, CustomOperationOptions] + // Client or SSR Cookies Client without Args defined + | [CustomOperationOptions]; + +/** + * Type guard for checking whether a Custom Operation argument is a contextSpec object + */ +const argIsContextSpec = ( + arg: OpArgs[number], +): arg is AmplifyServer.ContextSpec => { + return typeof (arg as AmplifyServer.ContextSpec)?.token?.value === 'symbol'; +}; + /** * Builds an operation function, embedded with all client and context data, that * can be attached to a client as a custom query or mutation. @@ -85,27 +108,50 @@ import { export function customOpFactory( client: ClientWithModels, modelIntrospection: ModelIntrospectionSchema, - operationType: 'query' | 'mutation', + operationType: 'query' | 'mutation' | 'subscription', operation: CustomOperation, useContext: boolean, ) { - const opWithContext = async ( - contextSpec: AmplifyServer.ContextSpec & GraphQLOptionsV6, - arg?: QueryArgs, - options?: AuthModeParams & ListArgs, - ) => { - return _op( - client, - modelIntrospection, - operationType, - operation, - arg, - options, - contextSpec, - ); - }; + // .arguments() are defined for the custom operation in the schema builder + // and are present in the model introspection schema + const argsDefined = operation.arguments !== undefined; + + const op = (...args: OpArgs) => { + // options is always the last argument + const options = args[args.length - 1] as CustomOperationOptions; + + let contextSpec: AmplifyServer.ContextSpec | undefined; + let arg: QueryArgs | undefined; + + if (useContext) { + if (argIsContextSpec(args[0])) { + contextSpec = args[0]; + } else { + throw new Error( + `Invalid first argument passed to ${operation.name}. Expected contextSpec`, + ); + } + } + + if (argsDefined) { + if (useContext) { + arg = args[1] as QueryArgs; + } else { + arg = args[0] as QueryArgs; + } + } + + if (operationType === 'subscription') { + return _opSubscription( + // subscriptions are only enabled on the clientside + client as V6Client>, + modelIntrospection, + operation, + arg, + options, + ); + } - const op = async (arg?: QueryArgs, options?: AuthModeParams & ListArgs) => { return _op( client, modelIntrospection, @@ -113,10 +159,11 @@ export function customOpFactory( operation, arg, options, + contextSpec, ); }; - return useContext ? opWithContext : op; + return op; } /** @@ -160,6 +207,9 @@ function hasStringField( * @returns "outer" arguments string */ function outerArguments(operation: CustomOperation): string { + if (operation.arguments === undefined) { + return ''; + } const args = Object.entries(operation.arguments) .map(([k, v]) => { const baseType = v.type + (v.isRequired ? '!' : ''); @@ -194,6 +244,9 @@ function outerArguments(operation: CustomOperation): string { * @returns "outer" arguments string */ function innerArguments(operation: CustomOperation): string { + if (operation.arguments === undefined) { + return ''; + } const args = Object.keys(operation.arguments) .map(k => `${k}: $${k}`) .join(', '); @@ -259,6 +312,9 @@ function operationVariables( args: QueryArgs = {}, ): Record { const variables = {} as Record; + if (operation.arguments === undefined) { + return variables; + } for (const argDef of Object.values(operation.arguments)) { if (typeof args[argDef.name] !== 'undefined') { variables[argDef.name] = args[argDef.name]; @@ -366,3 +422,71 @@ async function _op( } } } + +/** + * Executes an operation from the given model intro schema against a client, returning + * a fully instantiated model when relevant. + * + * @param client The client to operate `graphql()` calls through. + * @param modelIntrospection The model intro schema to construct requests from. + * @param operation The specific operation name, args, return type details. + * @param args The arguments to provide to the operation as variables. + * @param options Request options like headers, etc. + * @returns Result from the graphql request, model-instantiated when relevant. + */ +function _opSubscription( + client: V6Client>, + modelIntrospection: ModelIntrospectionSchema, + operation: CustomOperation, + args?: QueryArgs, + options?: AuthModeParams & ListArgs, +) { + const operationType = 'subscription'; + const { name: operationName } = operation; + const auth = authModeParams(client, options); + const headers = getCustomHeaders(client, options?.headers); + const outerArgsString = outerArguments(operation); + const innerArgsString = innerArguments(operation); + const selectionSet = operationSelectionSet(modelIntrospection, operation); + + const returnTypeModelName = hasStringField(operation.type, 'model') + ? operation.type.model + : undefined; + + const query = ` + ${operationType.toLocaleLowerCase()}${outerArgsString} { + ${operationName}${innerArgsString} ${selectionSet} + } + `; + + const variables = operationVariables(operation, args); + + const observable = client.graphql( + { + ...auth, + query, + variables, + }, + headers, + ) as GraphqlSubscriptionResult; + + return observable.pipe( + map(value => { + const [key] = Object.keys(value.data); + const data = (value.data as any)[key]; + + const [initialized] = returnTypeModelName + ? initializeModel( + client as V6Client>, + returnTypeModelName, + [data], + modelIntrospection, + auth.authMode, + auth.authToken, + ) + : [data]; + + return initialized; + }), + ); +} diff --git a/packages/api-graphql/src/internals/server/generateModelsProperty.ts b/packages/api-graphql/src/internals/server/generateModelsProperty.ts index f2b33e165d0..547d4cb6759 100644 --- a/packages/api-graphql/src/internals/server/generateModelsProperty.ts +++ b/packages/api-graphql/src/internals/server/generateModelsProperty.ts @@ -15,13 +15,16 @@ import { getFactory } from '../operations/get'; import { getSecondaryIndexesFromSchemaModel } from '../clientUtils'; export function generateModelsProperty< - _T extends Record = never, + T extends Record = never, ClientType extends | V6ClientSSRRequest> | V6ClientSSRCookies> = V6ClientSSRCookies< Record >, ->(client: ClientType, params: ServerClientGenerationParams): ClientType { +>( + client: ClientType, + params: ServerClientGenerationParams, +): ModelTypes | ModelTypes { const models = {} as any; const { config } = params; const useContext = params.amplify === null; diff --git a/packages/api-graphql/src/internals/utils/clientProperties/generateModelsProperty.ts b/packages/api-graphql/src/internals/utils/clientProperties/generateModelsProperty.ts index 93bec7b4a6e..a01c8732a15 100644 --- a/packages/api-graphql/src/internals/utils/clientProperties/generateModelsProperty.ts +++ b/packages/api-graphql/src/internals/utils/clientProperties/generateModelsProperty.ts @@ -18,7 +18,7 @@ import { getSecondaryIndexesFromSchemaModel } from '../../clientUtils'; export function generateModelsProperty = never>( client: V6Client>, apiGraphQLConfig: GraphQLProviderConfig['GraphQL'], -): ModelTypes { +): ModelTypes | ModelTypes { const models = {} as any; const modelIntrospection: ModelIntrospectionSchema | undefined = diff --git a/packages/api-graphql/src/types/index.ts b/packages/api-graphql/src/types/index.ts index 9dd7c51c9f7..e65dbe44c0e 100644 --- a/packages/api-graphql/src/types/index.ts +++ b/packages/api-graphql/src/types/index.ts @@ -5,6 +5,7 @@ import { CustomHeaders, CustomMutations, CustomQueries, + CustomSubscriptions, EnumTypes, ModelTypes, } from '@aws-amplify/data-schema-types'; @@ -394,6 +395,7 @@ export type V6Client = never> = ExcludeNeverFields<{ enums: EnumTypes; queries: CustomQueries; mutations: CustomMutations; + subscriptions: CustomSubscriptions; }>; export type V6ClientSSRRequest = never> = diff --git a/packages/core/src/singleton/API/types.ts b/packages/core/src/singleton/API/types.ts index 5a9e4b5de41..fb4bcf8f222 100644 --- a/packages/core/src/singleton/API/types.ts +++ b/packages/core/src/singleton/API/types.ts @@ -108,6 +108,7 @@ export interface ModelIntrospectionSchema { enums: SchemaEnums; queries?: CustomOperations; mutations?: CustomOperations; + subscriptions?: CustomOperations; } /** @@ -154,7 +155,7 @@ export interface CustomOperation { type: FieldType; isArray: boolean; isRequired: boolean; - arguments: CustomOperationArguments; + arguments?: CustomOperationArguments; } export type CustomOperationArguments = Record; diff --git a/yarn.lock b/yarn.lock index ebad4b49012..5fbce33ef43 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,19 +15,20 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@aws-amplify/data-schema-types@*", "@aws-amplify/data-schema-types@^0.7.6": - version "0.7.6" - resolved "https://registry.yarnpkg.com/@aws-amplify/data-schema-types/-/data-schema-types-0.7.6.tgz#7953e3c2eb22aba2bc9e4cc34a7b9023345a1b12" - integrity sha512-g5LmvLEJ5BDtfxRT6QK/+HhTfGGADbF7gbxtWPbhP9hRYwDai0A9ARJ6qETLPzUE/1vXtURlJV+MLutsDrIkPA== +"@aws-amplify/data-schema-types@*", "@aws-amplify/data-schema-types@^0.7.11": + version "0.7.11" + resolved "https://registry.yarnpkg.com/@aws-amplify/data-schema-types/-/data-schema-types-0.7.11.tgz#d6c4b5be551fa0600f6bbf2b512f19e39a20e481" + integrity sha512-K16p1NF1entoNBDQUnH/wK3exmOg+AtF96uFaj3SxQDOBad+wBnzVHZNWaoemlX2ISnuH/fXbuFvB5D7w76zbQ== dependencies: rxjs "^7.8.1" -"@aws-amplify/data-schema@^0.13.9": - version "0.13.9" - resolved "https://registry.yarnpkg.com/@aws-amplify/data-schema/-/data-schema-0.13.9.tgz#ee9be4e97b9f16d8225792758c8bf451b1814ddb" - integrity sha512-M1Wc5D4Sr5YT+Vq6FSPL7mDYW1Atnj5eHxRTGXoDG7w7G4Zs5Lq0nE8MQSx6gIuq3Js3WSjNoxUhBvaerX+Lgw== +"@aws-amplify/data-schema@^0.14.1": + version "0.14.1" + resolved "https://registry.yarnpkg.com/@aws-amplify/data-schema/-/data-schema-0.14.1.tgz#4208054e2c6c230a9abcc4607e3c38494dad3a38" + integrity sha512-V7Gx/HpNf7mOW90XBQMb94/whrysQ+NJCamb7aKSglXqWMVnc0zamFSkt2L+N0+avG+hEJaE+vH3157HfMYamA== dependencies: "@aws-amplify/data-schema-types" "*" + "@types/aws-lambda" "^8.10.134" "@aws-crypto/crc32@3.0.0": version "3.0.0" @@ -4850,6 +4851,11 @@ resolved "https://registry.yarnpkg.com/@types/archy/-/archy-0.0.32.tgz#8b572741dad9172dfbf289397af1bb41296d3e40" integrity sha512-5ZZ5+YGmUE01yejiXsKnTcvhakMZ2UllZlMsQni53Doc1JWhe21ia8VntRoRD6fAEWw08JBh/z9qQHJ+//MrIg== +"@types/aws-lambda@^8.10.134": + version "8.10.136" + resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.136.tgz#12a2af86b9123f4e4549992b27e1bf0dcf60d9f9" + integrity sha512-cmmgqxdVGhxYK9lZMYYXYRJk6twBo53ivtXjIUEFZxfxe4TkZTZBK3RRWrY2HjJcUIix0mdifn15yjOAat5lTA== + "@types/babel__core@^7.1.14": version "7.20.5" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017"