diff --git a/amplify-migration-apps/product-catalog/Query.listProducts.postDataLoad.1.res.vtl b/amplify-migration-apps/product-catalog/Query.listProducts.postDataLoad.1.res.vtl
new file mode 100644
index 00000000000..fa9ee985c6e
--- /dev/null
+++ b/amplify-migration-apps/product-catalog/Query.listProducts.postDataLoad.1.res.vtl
@@ -0,0 +1,14 @@
+#set($items = $ctx.prev.result.items)
+#foreach($item in $items)
+ #set($stock = 0)
+ #if($item.stock)
+ #set($stock = $item.stock)
+ #end
+ #set($price = 0)
+ #if($item.price)
+ #set($price = $item.price)
+ #end
+ #set($total = $price * $stock)
+ $util.qr($item.put("totalValue", $total))
+#end
+$util.toJson($ctx.prev.result)
diff --git a/amplify-migration-apps/product-catalog/Query.listProducts.res.vtl b/amplify-migration-apps/product-catalog/Query.listProducts.res.vtl
new file mode 100644
index 00000000000..d1cbb2ec701
--- /dev/null
+++ b/amplify-migration-apps/product-catalog/Query.listProducts.res.vtl
@@ -0,0 +1,11 @@
+## Add 10% discount to all products
+#foreach($item in $ctx.result.items)
+ #if($item.price)
+ #set($discount = $item.price * 0.10)
+ #set($discountedPrice = $item.price - $discount)
+ $util.qr($item.put("discountedPrice", $discountedPrice))
+ $util.qr($item.put("savings", $discount))
+ #end
+#end
+
+$util.toJson($ctx.result)
diff --git a/amplify-migration-apps/product-catalog/README.md b/amplify-migration-apps/product-catalog/README.md
index 7e42f22d01a..e6fa684409e 100644
--- a/amplify-migration-apps/product-catalog/README.md
+++ b/amplify-migration-apps/product-catalog/README.md
@@ -344,6 +344,18 @@ On the AppSync AWS Console, locate the ID of Gen1 API, it will be named `product
+ export async function handler(event) {
```
+```diff
+- const crypto = require('@aws-crypto/sha256-js');
+- const { defaultProvider } = require('@aws-sdk/credential-provider-node');
+- const { SignatureV4 } = require('@aws-sdk/signature-v4');
+- const { HttpRequest } = require('@aws-sdk/protocol-http');
+- const Sha256 = crypto.Sha256;
++ import { Sha256 } from '@aws-crypto/sha256-js';
++ import { defaultProvider } from '@aws-sdk/credential-provider-node';
++ import { SignatureV4 } from '@aws-sdk/signature-v4';
++ import { HttpRequest } from '@aws-sdk/protocol-http';
+```
+
**Edit in `./src/main.tsx`:**
```diff
diff --git a/amplify-migration-apps/product-catalog/configure.sh b/amplify-migration-apps/product-catalog/configure.sh
index b4f6510f709..44ae517146f 100755
--- a/amplify-migration-apps/product-catalog/configure.sh
+++ b/amplify-migration-apps/product-catalog/configure.sh
@@ -9,4 +9,6 @@ cp -f lowstockproducts.js ./amplify/backend/function/lowstockproducts/src/index.
cp -f lowstockproducts.package.json ./amplify/backend/function/lowstockproducts/src/package.json
cp -f onimageuploaded.js ./amplify/backend/function/${s3_trigger_function_name}/src/index.js
cp -f onimageuploaded.package.json ./amplify/backend/function/${s3_trigger_function_name}/src/package.json
-cp -f custom-roles.json ./amplify/backend/api/productcatalog/custom-roles.json
\ No newline at end of file
+cp -f custom-roles.json ./amplify/backend/api/productcatalog/custom-roles.json
+cp -f Query.listProducts.res.vtl ./amplify/backend/api/productcatalog/resolvers/Query.listProducts.res.vtl
+cp -f Query.listProducts.postDataLoad.1.res.vtl ./amplify/backend/api/productcatalog/resolvers/Query.listProducts.postDataLoad.1.res.vtl
diff --git a/amplify-migration-apps/product-catalog/schema.graphql b/amplify-migration-apps/product-catalog/schema.graphql
index 68493ba9e31..a77f0d27cd0 100644
--- a/amplify-migration-apps/product-catalog/schema.graphql
+++ b/amplify-migration-apps/product-catalog/schema.graphql
@@ -4,10 +4,7 @@ enum UserRole {
VIEWER
}
-type User @model @auth(rules: [
- { allow: private, provider: iam },
- { allow: owner, ownerField: "id" }
-]) {
+type User @model @auth(rules: [{ allow: private, provider: iam }, { allow: owner, ownerField: "id" }]) {
id: ID!
email: String!
name: String!
@@ -33,12 +30,10 @@ type Product @model @auth(rules: [{ allow: private, provider: iam }]) {
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
comments: [Comment] @hasMany(indexName: "byProduct", fields: ["id"])
+ totalValue: Float
}
-type Comment @model @auth(rules: [
- { allow: private, provider: iam },
- { allow: owner, ownerField: "authorId" }
-]) {
+type Comment @model @auth(rules: [{ allow: private, provider: iam }, { allow: owner, ownerField: "authorId" }]) {
id: ID!
productId: ID! @index(name: "byProduct")
authorId: String!
@@ -59,8 +54,7 @@ type LowStockResponse {
}
type Query {
- checkLowStock: LowStockResponse @function(name: "lowstockproducts-${env}") @auth(rules: [
- { allow: private, provider: iam },
- { allow: public, provider: apiKey }
- ])
+ checkLowStock: LowStockResponse
+ @function(name: "lowstockproducts-${env}")
+ @auth(rules: [{ allow: private, provider: iam }, { allow: public, provider: apiKey }])
}
diff --git a/amplify-migration-apps/product-catalog/src/App.tsx b/amplify-migration-apps/product-catalog/src/App.tsx
index c3a0d58606e..c62c0cf2989 100644
--- a/amplify-migration-apps/product-catalog/src/App.tsx
+++ b/amplify-migration-apps/product-catalog/src/App.tsx
@@ -1208,17 +1208,40 @@ function App({ signOut, user }: AppProps) {
{product.brand}
)}
- {product.stock !== undefined && product.stock !== null && (
+ {(product as any).stockStatus && (
0 ? '#dcfce7' : '#fef3c7',
- color: (product.stock || 0) > 0 ? '#166534' : '#92400e',
+ backgroundColor:
+ (product as any).stockStatus === 'OUT_OF_STOCK'
+ ? '#fef2f2'
+ : (product as any).stockStatus === 'LOW_STOCK'
+ ? '#fef3c7'
+ : '#dcfce7',
+ color:
+ (product as any).stockStatus === 'OUT_OF_STOCK'
+ ? '#dc2626'
+ : (product as any).stockStatus === 'LOW_STOCK'
+ ? '#92400e'
+ : '#166534',
fontWeight: '600',
borderRadius: '6px',
padding: '0.25rem 0.75rem',
}}
>
- {(product.stock || 0) > 0 ? `${product.stock} in stock` : 'Out of stock'}
+ {(product as any).stockStatus.replace('_', ' ')}
+
+ )}
+ {(product as any).totalValue && (
+
+ Total: ${(product as any).totalValue}
)}
diff --git a/amplify-migration-apps/product-catalog/src/graphql/queries.ts b/amplify-migration-apps/product-catalog/src/graphql/queries.ts
index 7537a612694..d3f731014ab 100644
--- a/amplify-migration-apps/product-catalog/src/graphql/queries.ts
+++ b/amplify-migration-apps/product-catalog/src/graphql/queries.ts
@@ -53,8 +53,11 @@ export const listProducts = /* GraphQL */ `query ListProducts(
images
createdBy
updatedBy
+ discountedPrice
+ savings
createdAt
updatedAt
+ totalValue
__typename
}
nextToken
diff --git a/packages/amplify-cli/src/commands/gen2-migration/generate/backend/synthesizer.ts b/packages/amplify-cli/src/commands/gen2-migration/generate/backend/synthesizer.ts
index 61c78629844..e147a5453bf 100644
--- a/packages/amplify-cli/src/commands/gen2-migration/generate/backend/synthesizer.ts
+++ b/packages/amplify-cli/src/commands/gen2-migration/generate/backend/synthesizer.ts
@@ -28,6 +28,7 @@ export interface BackendRenderParameters {
importFrom: string;
additionalAuthProviders?: AdditionalAuthProvider[];
restApis?: RestApiDefinition[];
+ hasResolvers?: boolean;
};
auth?: {
importFrom: string;
@@ -2415,6 +2416,258 @@ export class BackendSynthesizer {
});
}
+ // Override resolver templates from data/resolvers folder
+ if (renderArgs.data?.hasResolvers) {
+ // Add required imports for resolver overrides
+ imports.push(this.createImportStatement([factory.createIdentifier('readdirSync'), factory.createIdentifier('readFileSync')], 'fs'));
+ imports.push(this.createImportStatement([factory.createIdentifier('join'), factory.createIdentifier('dirname')], 'path'));
+ imports.push(this.createImportStatement([factory.createIdentifier('fileURLToPath')], 'url'));
+
+ // Generate __dirname equivalent for ES modules
+ const dirnameStatement = factory.createVariableStatement(
+ [],
+ factory.createVariableDeclarationList(
+ [
+ factory.createVariableDeclaration(
+ '__dirname',
+ undefined,
+ undefined,
+ factory.createCallExpression(factory.createIdentifier('dirname'), undefined, [
+ factory.createCallExpression(factory.createIdentifier('fileURLToPath'), undefined, [
+ factory.createPropertyAccessExpression(factory.createIdentifier('import'), factory.createIdentifier('meta.url')),
+ ]),
+ ]),
+ ),
+ ],
+ ts.NodeFlags.Const,
+ ),
+ );
+ nodes.push(dirnameStatement);
+
+ // Get resolvers directory path
+ const resolversDirStatement = factory.createVariableStatement(
+ [],
+ factory.createVariableDeclarationList(
+ [
+ factory.createVariableDeclaration(
+ 'resolversDir',
+ undefined,
+ undefined,
+ factory.createCallExpression(factory.createIdentifier('join'), undefined, [
+ factory.createIdentifier('__dirname'),
+ factory.createStringLiteral('data/resolvers'),
+ ]),
+ ),
+ ],
+ ts.NodeFlags.Const,
+ ),
+ );
+ nodes.push(resolversDirStatement);
+
+ // Filter for .res.vtl files
+ const resolverFilesStatement = factory.createVariableStatement(
+ [],
+ factory.createVariableDeclarationList(
+ [
+ factory.createVariableDeclaration(
+ 'resolverFiles',
+ undefined,
+ undefined,
+ factory.createCallExpression(
+ factory.createPropertyAccessExpression(
+ factory.createCallExpression(factory.createIdentifier('readdirSync'), undefined, [
+ factory.createIdentifier('resolversDir'),
+ ]),
+ factory.createIdentifier('filter'),
+ ),
+ undefined,
+ [
+ factory.createArrowFunction(
+ undefined,
+ undefined,
+ [factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier('f'))],
+ undefined,
+ factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
+ factory.createCallExpression(
+ factory.createPropertyAccessExpression(factory.createIdentifier('f'), factory.createIdentifier('endsWith')),
+ undefined,
+ [factory.createStringLiteral('.res.vtl')],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ts.NodeFlags.Const,
+ ),
+ );
+ nodes.push(resolverFilesStatement);
+
+ // Process each resolver file
+ const forOfStatement = factory.createForOfStatement(
+ undefined,
+ factory.createVariableDeclarationList(
+ [factory.createVariableDeclaration('file', undefined, undefined, undefined)],
+ ts.NodeFlags.Const,
+ ),
+ factory.createIdentifier('resolverFiles'),
+ factory.createBlock(
+ [
+ // Extract type and field names from filename (e.g., Query.listProducts.res.vtl)
+ factory.createVariableStatement(
+ [],
+ factory.createVariableDeclarationList(
+ [
+ factory.createVariableDeclaration(
+ factory.createArrayBindingPattern([
+ factory.createBindingElement(undefined, undefined, 'typeName'),
+ factory.createBindingElement(undefined, undefined, 'fieldName'),
+ ]),
+ undefined,
+ undefined,
+ factory.createCallExpression(
+ factory.createPropertyAccessExpression(
+ factory.createCallExpression(
+ factory.createPropertyAccessExpression(factory.createIdentifier('file'), factory.createIdentifier('replace')),
+ undefined,
+ [factory.createStringLiteral('.res.vtl'), factory.createStringLiteral('')],
+ ),
+ factory.createIdentifier('split'),
+ ),
+ undefined,
+ [factory.createStringLiteral('.')],
+ ),
+ ),
+ ],
+ ts.NodeFlags.Const,
+ ),
+ ),
+ // Build pipeline function ID (e.g., QueryListProductsDataResolverFn)
+ factory.createVariableStatement(
+ [],
+ factory.createVariableDeclarationList(
+ [
+ factory.createVariableDeclaration(
+ 'functionId',
+ undefined,
+ undefined,
+ factory.createTemplateExpression(factory.createTemplateHead(''), [
+ factory.createTemplateSpan(factory.createIdentifier('typeName'), factory.createTemplateMiddle('')),
+ factory.createTemplateSpan(
+ factory.createBinaryExpression(
+ factory.createCallExpression(
+ factory.createPropertyAccessExpression(
+ factory.createCallExpression(
+ factory.createPropertyAccessExpression(
+ factory.createIdentifier('fieldName'),
+ factory.createIdentifier('charAt'),
+ ),
+ undefined,
+ [factory.createNumericLiteral('0')],
+ ),
+ factory.createIdentifier('toUpperCase'),
+ ),
+ undefined,
+ [],
+ ),
+ factory.createToken(ts.SyntaxKind.PlusToken),
+ factory.createCallExpression(
+ factory.createPropertyAccessExpression(
+ factory.createIdentifier('fieldName'),
+ factory.createIdentifier('slice'),
+ ),
+ undefined,
+ [factory.createNumericLiteral('1')],
+ ),
+ ),
+ factory.createTemplateTail('DataResolverFn'),
+ ),
+ ]),
+ ),
+ ],
+ ts.NodeFlags.Const,
+ ),
+ ),
+ // Get the pipeline function configuration
+ factory.createVariableStatement(
+ [],
+ factory.createVariableDeclarationList(
+ [
+ factory.createVariableDeclaration(
+ 'pipelineFunction',
+ undefined,
+ undefined,
+ factory.createElementAccessExpression(
+ factory.createPropertyAccessExpression(
+ factory.createIdentifier('backend.data.resources.cfnResources'),
+ factory.createIdentifier('cfnFunctionConfigurations'),
+ ),
+ factory.createIdentifier('functionId'),
+ ),
+ ),
+ ],
+ ts.NodeFlags.Const,
+ ),
+ ),
+ // Override the response mapping template if pipeline function exists
+ factory.createIfStatement(
+ factory.createIdentifier('pipelineFunction'),
+ factory.createBlock(
+ [
+ // Read the VTL template content
+ factory.createVariableStatement(
+ [],
+ factory.createVariableDeclarationList(
+ [
+ factory.createVariableDeclaration(
+ 'template',
+ undefined,
+ undefined,
+ factory.createCallExpression(factory.createIdentifier('readFileSync'), undefined, [
+ factory.createCallExpression(factory.createIdentifier('join'), undefined, [
+ factory.createIdentifier('resolversDir'),
+ factory.createIdentifier('file'),
+ ]),
+ factory.createStringLiteral('utf8'),
+ ]),
+ ),
+ ],
+ ts.NodeFlags.Const,
+ ),
+ ),
+ // Clear the S3 template location to use inline template
+ factory.createExpressionStatement(
+ factory.createBinaryExpression(
+ factory.createPropertyAccessExpression(
+ factory.createIdentifier('pipelineFunction'),
+ factory.createIdentifier('responseMappingTemplateS3Location'),
+ ),
+ factory.createToken(ts.SyntaxKind.EqualsToken),
+ factory.createIdentifier('undefined'),
+ ),
+ ),
+ // Set the inline response mapping template
+ factory.createExpressionStatement(
+ factory.createBinaryExpression(
+ factory.createPropertyAccessExpression(
+ factory.createIdentifier('pipelineFunction'),
+ factory.createIdentifier('responseMappingTemplate'),
+ ),
+ factory.createToken(ts.SyntaxKind.EqualsToken),
+ factory.createIdentifier('template'),
+ ),
+ ),
+ ],
+ true,
+ ),
+ ),
+ ],
+ true,
+ ),
+ );
+ nodes.push(forOfStatement);
+ }
+
// returns backend.ts file
return factory.createNodeArray([...imports, newLineIdentifier, ...errors, newLineIdentifier, backendStatement, ...nodes], true);
}
diff --git a/packages/amplify-cli/src/commands/gen2-migration/generate/codegen-head/data_definition_fetcher.ts b/packages/amplify-cli/src/commands/gen2-migration/generate/codegen-head/data_definition_fetcher.ts
index e261c0ca2c0..becd04e43c5 100644
--- a/packages/amplify-cli/src/commands/gen2-migration/generate/codegen-head/data_definition_fetcher.ts
+++ b/packages/amplify-cli/src/commands/gen2-migration/generate/codegen-head/data_definition_fetcher.ts
@@ -4,8 +4,12 @@ import glob from 'glob';
import assert from 'node:assert';
import { DataDefinition } from '../core/migration-pipeline';
-import { AdditionalAuthProvider } from '../generators/data';
+import { AdditionalAuthProvider, getProjectName } from '../generators/data';
import { pathManager } from '@aws-amplify/amplify-cli-core';
+import { BackendEnvironmentResolver } from './backend_environment_selector';
+import { BackendDownloader } from './backend_downloader';
+import { fileOrDirectoryExists } from './directory_exists';
+import { AppSyncClient, GetGraphqlApiCommand } from '@aws-sdk/client-appsync';
// Source - amplify-category-api/packages/amplify-graphql-transformer-core/src/graphql-api.ts
interface Gen1AuthConfig {
@@ -103,10 +107,10 @@ export interface CorsConfiguration {
maxAge?: number;
}
-import { BackendEnvironmentResolver } from './backend_environment_selector';
-import { BackendDownloader } from './backend_downloader';
-import { fileOrDirectoryExists } from './directory_exists';
-import { AppSyncClient, GetGraphqlApiCommand } from '@aws-sdk/client-appsync';
+// Add locally in the fetcher
+export interface ResolverConfig {
+ hasResolvers: boolean;
+}
/**
* Fetches and processes data definitions from Amplify Gen1 projects for migration to Gen2.
@@ -130,6 +134,22 @@ export class DataDefinitionFetcher {
*/
constructor(private backendEnvironmentResolver: BackendEnvironmentResolver, private ccbFetcher: BackendDownloader) {}
+ /**
+ * Checks if GraphQL API has resolvers directory with VTL files
+ */
+ private hasResolvers = (): boolean => {
+ const rootDir = pathManager.findProjectRoot();
+ const projectName = getProjectName();
+
+ const resolversPath = path.join(rootDir, 'amplify', 'backend', 'api', projectName, 'resolvers');
+
+ if (!require('fs').existsSync(resolversPath)) return false;
+
+ const files = require('fs').readdirSync(resolversPath);
+
+ return files.some((file: string) => file.endsWith('.vtl'));
+ };
+
/**
* Reads and parses a JSON file.
*
@@ -462,6 +482,10 @@ export class DataDefinitionFetcher {
const additionalAuthProviders = apiId ? await this.getAdditionalAuthProvidersFromConsole(apiId) : [];
const logging = apiId ? await this.getLoggingConfigFromConsole(apiId) : undefined;
+ // Handle resolver checking
+ const hasResolvers = this.hasResolvers();
+ const resolvers: ResolverConfig | undefined = hasResolvers ? { hasResolvers: true } : undefined;
+
return {
tableMappings: undefined,
schema,
@@ -469,6 +493,7 @@ export class DataDefinitionFetcher {
additionalAuthProviders: additionalAuthProviders.length > 0 ? additionalAuthProviders : undefined,
logging,
restApis: restApis.length > 0 ? restApis : undefined,
+ resolvers,
};
}
diff --git a/packages/amplify-cli/src/commands/gen2-migration/generate/core/migration-pipeline.ts b/packages/amplify-cli/src/commands/gen2-migration/generate/core/migration-pipeline.ts
index eb1c24b33c5..c2d0206b5d6 100644
--- a/packages/amplify-cli/src/commands/gen2-migration/generate/core/migration-pipeline.ts
+++ b/packages/amplify-cli/src/commands/gen2-migration/generate/core/migration-pipeline.ts
@@ -58,8 +58,10 @@ import {
} from '../generators/storage';
import { DataDefinition, DataTableMapping, generateDataSource } from '../generators/data/index';
+import { getProjectName } from '../generators/data';
import { DataModelTableAccess } from '../codegen-head/data_model_access_parser';
import { ApiTriggerDetector } from '../adapters/functions/api-trigger-detector';
+import { pathManager } from '@aws-amplify/amplify-cli-core';
import { FunctionDefinition, renderFunctions } from '../generators/functions/index';
import assert from 'assert';
@@ -116,6 +118,29 @@ export interface Gen2RenderingOptions {
/** Custom file writer function for testing or alternative output methods */
fileWriter?: (content: string, path: string) => Promise;
}
+/**
+ * Copies resolver files from Gen1 to Gen2 structure
+ */
+const copyResolverFiles = (outputDir: string): Renderer => ({
+ render: async () => {
+ const rootDir = pathManager.findProjectRoot();
+ const projectName = getProjectName();
+ const resolversPath = path.join(rootDir, 'amplify', 'backend', 'api', projectName, 'resolvers');
+ const targetPath = path.join(outputDir, 'amplify', 'data', 'resolvers');
+
+ if (require('fs').existsSync(resolversPath)) {
+ const files = require('fs').readdirSync(resolversPath);
+ const vtlFiles = files.filter((file: string) => file.endsWith('.vtl'));
+
+ for (const file of vtlFiles) {
+ const srcFile = path.join(resolversPath, file);
+ const destFile = path.join(targetPath, file);
+ require('fs').copyFileSync(srcFile, destFile);
+ }
+ }
+ },
+});
+
/**
* Creates a file writer function for the specified path
* @param path - File path to write to
@@ -487,6 +512,10 @@ export const createGen2Renderer = ({
// Process data (GraphQL/DynamoDB) configuration - only if table mappings exist for the environment
if (data) {
renderers.push(new EnsureDirectory(path.join(outputDir, 'amplify', 'data')));
+ if (data.resolvers?.hasResolvers) {
+ renderers.push(new EnsureDirectory(path.join(outputDir, 'amplify', 'data', 'resolvers')));
+ renderers.push(copyResolverFiles(outputDir));
+ }
renderers.push(
new TypescriptNodeArrayRenderer(
async () => generateDataSource(backendEnvironmentName, data),
@@ -497,6 +526,7 @@ export const createGen2Renderer = ({
importFrom: './data/resource',
additionalAuthProviders: data.additionalAuthProviders,
restApis: data.restApis,
+ hasResolvers: data.resolvers?.hasResolvers,
};
}
diff --git a/packages/amplify-cli/src/commands/gen2-migration/generate/generators/data/index.ts b/packages/amplify-cli/src/commands/gen2-migration/generate/generators/data/index.ts
index 6473d3f0686..e9a4d954833 100644
--- a/packages/amplify-cli/src/commands/gen2-migration/generate/generators/data/index.ts
+++ b/packages/amplify-cli/src/commands/gen2-migration/generate/generators/data/index.ts
@@ -3,7 +3,8 @@ import { renderResourceTsFile } from '../../resource/resource';
import { AppSyncClient, paginateListGraphqlApis } from '@aws-sdk/client-appsync';
import type { ConstructFactory, AmplifyFunction } from '@aws-amplify/plugin-types';
import type { AuthorizationModes, DataLoggingOptions } from '@aws-amplify/backend-data';
-import { RestApiDefinition } from '../../codegen-head/data_definition_fetcher';
+import { RestApiDefinition, ResolverConfig } from '../../codegen-head/data_definition_fetcher';
+
export interface AdditionalAuthProvider {
authenticationType: 'API_KEY' | 'AWS_IAM' | 'OPENID_CONNECT' | 'AMAZON_COGNITO_USER_POOLS' | 'AWS_LAMBDA';
userPoolConfig?: {
@@ -46,7 +47,7 @@ const extractModelsFromSchema = (schema: string): string[] => {
return models;
};
-const getProjectName = (): string | undefined => {
+export const getProjectName = (): string | undefined => {
try {
const fs = require('fs');
const path = require('path');
@@ -102,6 +103,8 @@ export type DataDefinition = {
logging?: DataLoggingOptions;
/* REST API definitions */
restApis?: RestApiDefinition[];
+ /* Resolver configuration */
+ resolvers?: ResolverConfig;
};
/** Key name for the migrated table mappings property in the generated data resource */