diff --git a/.changeset/tough-bats-eat.md b/.changeset/tough-bats-eat.md new file mode 100644 index 0000000000..4ada203d01 --- /dev/null +++ b/.changeset/tough-bats-eat.md @@ -0,0 +1,16 @@ +--- +'@aws-amplify/backend-output-schemas': minor +'@aws-amplify/backend-output-storage': patch +'@aws-amplify/integration-tests': patch +'@aws-amplify/storage-construct-alpha': patch +'@aws-amplify/backend-function': patch +'@aws-amplify/backend-graphql': patch +'@aws-amplify/backend-storage': patch +'@aws-amplify/auth-construct-alpha': patch +'create-amplify': patch +'@aws-amplify/client-config': minor +'@aws-amplify/backend-auth': patch +'@aws-amplify/backend': patch +--- + +Refactor OutputStorageStrategy into stateless shared dependency diff --git a/.eslint_dictionary.js b/.eslint_dictionary.js index ddf45130a6..99c27252b7 100644 --- a/.eslint_dictionary.js +++ b/.eslint_dictionary.js @@ -77,6 +77,7 @@ export default [ 'stdout', 'subcommand', 'subcommands', + 'submodule', 'timestamps', 'tmpdir', 'toggleable', diff --git a/package-lock.json b/package-lock.json index 5ed3476284..9a42b11410 100644 --- a/package-lock.json +++ b/package-lock.json @@ -417,6 +417,10 @@ "resolved": "packages/backend-output-schemas", "link": true }, + "node_modules/@aws-amplify/backend-output-storage": { + "resolved": "packages/backend-output-storage", + "link": true + }, "node_modules/@aws-amplify/backend-secret": { "resolved": "packages/backend-secret", "link": true @@ -11902,6 +11906,7 @@ "version": "11.1.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -12520,6 +12525,7 @@ "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, "engines": { "node": ">= 4" } @@ -13409,6 +13415,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, "dependencies": { "universalify": "^2.0.0" }, @@ -15141,6 +15148,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, "engines": { "node": ">=6" } @@ -15860,6 +15868,7 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -15874,6 +15883,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -15884,7 +15894,8 @@ "node_modules/semver/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/send": { "version": "0.18.0", @@ -17434,6 +17445,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, "engines": { "node": ">= 10.0.0" } @@ -18121,6 +18133,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "dev": true, "engines": { "node": ">= 14" } @@ -18252,7 +18265,8 @@ "name": "@aws-amplify/auth-construct-alpha", "version": "0.2.0-alpha.5", "dependencies": { - "@aws-amplify/backend-output-schemas": "^0.2.0-alpha.2" + "@aws-amplify/backend-output-schemas": "^0.2.0-alpha.2", + "@aws-amplify/backend-output-storage": "^0.1.0" }, "peerDependencies": { "@aws-amplify/plugin-types": "^0.1.1-alpha.4", @@ -18265,6 +18279,7 @@ "version": "0.1.1-alpha.3", "dependencies": { "@aws-amplify/backend-output-schemas": "^0.2.0-alpha.2", + "@aws-amplify/backend-output-storage": "^0.1.0", "@aws-amplify/backend-secret": "^0.1.0" }, "devDependencies": { @@ -18346,6 +18361,13 @@ "zod": "^3.21.4" } }, + "packages/backend-output-storage": { + "name": "@aws-amplify/backend-output-storage", + "version": "0.1.0", + "peerDependencies": { + "aws-cdk-lib": "^2.80.0" + } + }, "packages/backend-secret": { "name": "@aws-amplify/backend-secret", "version": "0.1.0", @@ -18364,6 +18386,7 @@ "name": "@aws-amplify/backend-storage", "version": "0.1.1-alpha.2", "dependencies": { + "@aws-amplify/backend-output-storage": "^0.1.0", "@aws-amplify/storage-construct-alpha": "^0.1.1-alpha.2" }, "devDependencies": { @@ -18768,7 +18791,8 @@ "name": "@aws-amplify/storage-construct-alpha", "version": "0.1.1-alpha.3", "dependencies": { - "@aws-amplify/backend-output-schemas": "^0.2.0-alpha.2" + "@aws-amplify/backend-output-schemas": "^0.2.0-alpha.2", + "@aws-amplify/backend-output-storage": "^0.1.0" }, "devDependencies": { "@aws-amplify/plugin-types": "^0.1.1-alpha.3" diff --git a/packages/auth-construct/API.md b/packages/auth-construct/API.md index c827064552..7bd3c5915b 100644 --- a/packages/auth-construct/API.md +++ b/packages/auth-construct/API.md @@ -9,7 +9,6 @@ import { AuthOutput } from '@aws-amplify/backend-output-schemas/auth'; import { AuthResources } from '@aws-amplify/plugin-types'; import { aws_cognito } from 'aws-cdk-lib'; import { BackendOutputStorageStrategy } from '@aws-amplify/plugin-types'; -import { BackendOutputWriter } from '@aws-amplify/plugin-types'; import { Construct } from 'constructs'; import { CustomAttributeConfig } from 'aws-cdk-lib/aws-cognito'; import { IFunction } from 'aws-cdk-lib/aws-lambda'; @@ -17,13 +16,12 @@ import { ResourceProvider } from '@aws-amplify/plugin-types'; import { StandardAttributes } from 'aws-cdk-lib/aws-cognito'; // @public -export class AmplifyAuth extends Construct implements BackendOutputWriter, ResourceProvider { +export class AmplifyAuth extends Construct implements ResourceProvider { constructor(scope: Construct, id: string, props?: AuthProps); addTrigger: (event: TriggerEvent, handler: IFunction | AmplifyFunction) => void; static attribute: (name: keyof aws_cognito.StandardAttributes) => AuthStandardAttribute; static customAttribute: AuthCustomAttributeFactory; readonly resources: AuthResources; - storeOutput: (outputStorageStrategy: BackendOutputStorageStrategy) => void; } // @public @@ -72,6 +70,7 @@ export type AuthProps = { userAttributes?: AuthUserAttribute[]; multifactor?: MFA; accountRecovery?: aws_cognito.AccountRecovery; + outputStorageStrategy?: BackendOutputStorageStrategy; }; // @public diff --git a/packages/auth-construct/package.json b/packages/auth-construct/package.json index 480a79b191..bc32373fde 100644 --- a/packages/auth-construct/package.json +++ b/packages/auth-construct/package.json @@ -17,7 +17,8 @@ "update:api": "api-extractor run --local" }, "dependencies": { - "@aws-amplify/backend-output-schemas": "^0.2.0-alpha.2" + "@aws-amplify/backend-output-schemas": "^0.2.0-alpha.2", + "@aws-amplify/backend-output-storage": "^0.1.0" }, "peerDependencies": { "@aws-amplify/plugin-types": "^0.1.1-alpha.4", diff --git a/packages/auth-construct/src/construct.test.ts b/packages/auth-construct/src/construct.test.ts index 51cc9dab97..059ced3032 100644 --- a/packages/auth-construct/src/construct.test.ts +++ b/packages/auth-construct/src/construct.test.ts @@ -474,6 +474,7 @@ describe('Auth construct', () => { loginWith: { email: true, }, + outputStorageStrategy: stubBackendOutputStorageStrategy, }); const expectedUserPoolId = ( @@ -487,8 +488,6 @@ describe('Auth construct', () => { ).userPoolClientId; const expectedRegion = Stack.of(authConstruct).region; - authConstruct.storeOutput(stubBackendOutputStorageStrategy); - const storeOutputArgs = storeOutputMock.mock.calls[0].arguments; assert.equal(storeOutputArgs.length, 2); @@ -505,6 +504,32 @@ describe('Auth construct', () => { }, ]); }); + + it('stores output when no storage strategy is injected', () => { + const app = new App(); + const stack = new Stack(app); + + new AmplifyAuth(stack, 'test', { + loginWith: { + email: true, + }, + }); + + const template = Template.fromStack(stack); + template.templateMatches({ + Metadata: { + [authOutputKey]: { + version: '1', + stackOutputs: [ + 'userPoolId', + 'webClientId', + 'identityPoolId', + 'authRegion', + ], + }, + }, + }); + }); }); describe('defaults', () => { diff --git a/packages/auth-construct/src/construct.ts b/packages/auth-construct/src/construct.ts index 1d7b892f06..7121193d7d 100644 --- a/packages/auth-construct/src/construct.ts +++ b/packages/auth-construct/src/construct.ts @@ -4,7 +4,6 @@ import { AmplifyFunction, AuthResources, BackendOutputStorageStrategy, - BackendOutputWriter, ResourceProvider, } from '@aws-amplify/plugin-types'; import { @@ -32,6 +31,7 @@ import { AuthStandardAttribute, } from './attributes.js'; import { IFunction } from 'aws-cdk-lib/aws-lambda'; +import { StackMetadataBackendOutputStorageStrategy } from '@aws-amplify/backend-output-storage'; type DefaultRoles = { auth: Role; unAuth: Role }; type IdentityProviderSetupResult = { @@ -55,7 +55,7 @@ const authProvidersList = { */ export class AmplifyAuth extends Construct - implements BackendOutputWriter, ResourceProvider + implements ResourceProvider { /** * The resources generated by the construct. @@ -123,6 +123,7 @@ export class AmplifyAuth identityPoolRoleAttachment, }, }; + this.storeOutput(props.outputStorageStrategy); } /** @@ -437,8 +438,10 @@ export class AmplifyAuth /** * Stores auth output using the provided strategy */ - storeOutput = ( - outputStorageStrategy: BackendOutputStorageStrategy + private storeOutput = ( + outputStorageStrategy: BackendOutputStorageStrategy = new StackMetadataBackendOutputStorageStrategy( + Stack.of(this) + ) ): void => { const output: AuthOutput['payload'] = { userPoolId: this.resources.userPool.userPoolId, diff --git a/packages/auth-construct/src/types.ts b/packages/auth-construct/src/types.ts index 173442dc3d..347b766458 100644 --- a/packages/auth-construct/src/types.ts +++ b/packages/auth-construct/src/types.ts @@ -1,6 +1,8 @@ import { aws_cognito as cognito } from 'aws-cdk-lib'; import { AuthUserAttribute } from './attributes.js'; import { triggerEvents } from './trigger_events.js'; +import { BackendOutputStorageStrategy } from '@aws-amplify/plugin-types'; +import { AuthOutput } from '@aws-amplify/backend-output-schemas/auth'; /** * Email login options. @@ -95,4 +97,6 @@ export type AuthProps = { * If only email or phone are enabled, they will be the default recovery methods. */ accountRecovery?: cognito.AccountRecovery; + + outputStorageStrategy?: BackendOutputStorageStrategy; }; diff --git a/packages/auth-construct/tsconfig.json b/packages/auth-construct/tsconfig.json index 8e6ba2e792..4b69ecc6df 100644 --- a/packages/auth-construct/tsconfig.json +++ b/packages/auth-construct/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "rootDir": "src", "outDir": "lib" }, "references": [ { "path": "../backend-output-schemas" }, + { "path": "../backend-output-storage" }, { "path": "../plugin-types" } ] } diff --git a/packages/backend-auth/API.md b/packages/backend-auth/API.md index e6eac54e73..c0e6354e04 100644 --- a/packages/backend-auth/API.md +++ b/packages/backend-auth/API.md @@ -22,7 +22,7 @@ export class AmplifyAuthFactory implements ConstructFactory & TriggerConfig; // @public export const Auth: typeof AmplifyAuthFactory; diff --git a/packages/backend-auth/src/factory.test.ts b/packages/backend-auth/src/factory.test.ts index dd3e20961f..1dcfe0bbde 100644 --- a/packages/backend-auth/src/factory.test.ts +++ b/packages/backend-auth/src/factory.test.ts @@ -3,7 +3,6 @@ import { AmplifyAuthFactory } from './factory.js'; import { NestedStackResolver, SingletonConstructContainer, - StackMetadataBackendOutputStorageStrategy, ToggleableImportPathVerifier, } from '@aws-amplify/backend/test-utils'; import { App, Stack, aws_lambda } from 'aws-cdk-lib'; @@ -19,6 +18,7 @@ import { ResourceProvider, } from '@aws-amplify/plugin-types'; import { triggerEvents } from '@aws-amplify/auth-construct-alpha'; +import { StackMetadataBackendOutputStorageStrategy } from '@aws-amplify/backend-output-storage'; describe('AmplifyAuthFactory', () => { let authFactory: AmplifyAuthFactory; diff --git a/packages/backend-auth/src/factory.ts b/packages/backend-auth/src/factory.ts index 18caa2dca7..a92e274476 100644 --- a/packages/backend-auth/src/factory.ts +++ b/packages/backend-auth/src/factory.ts @@ -19,7 +19,8 @@ export type TriggerConfig = { >; }; -export type AmplifyAuthFactoryProps = AuthProps & TriggerConfig; +export type AmplifyAuthFactoryProps = Omit & + TriggerConfig; /** * Singleton factory for AmplifyAuth that can be used in Amplify project files @@ -68,8 +69,11 @@ class AmplifyAuthGenerator implements ConstructContainerEntryGenerator { ) {} generateContainerEntry = (scope: Construct) => { - const authConstruct = new AmplifyAuth(scope, this.defaultName, this.props); - authConstruct.storeOutput(this.getInstanceProps.outputStorageStrategy); + const authProps: AuthProps = { + ...this.props, + outputStorageStrategy: this.getInstanceProps.outputStorageStrategy, + }; + const authConstruct = new AmplifyAuth(scope, this.defaultName, authProps); Object.entries(this.props.triggers || {}).forEach( ([triggerEvent, handlerFactory]) => { authConstruct.addTrigger( diff --git a/packages/backend-function/src/factory.test.ts b/packages/backend-function/src/factory.test.ts index 26338ab7b0..107c8b08ed 100644 --- a/packages/backend-function/src/factory.test.ts +++ b/packages/backend-function/src/factory.test.ts @@ -4,12 +4,12 @@ import { App, Stack } from 'aws-cdk-lib'; import { NestedStackResolver, SingletonConstructContainer, - StackMetadataBackendOutputStorageStrategy, } from '@aws-amplify/backend/test-utils'; import { ConstructFactoryGetInstanceProps } from '@aws-amplify/plugin-types'; import assert from 'node:assert'; import { fileURLToPath } from 'url'; import * as path from 'path'; +import { StackMetadataBackendOutputStorageStrategy } from '@aws-amplify/backend-output-storage'; describe('AmplifyFunctionFactory', () => { let getInstanceProps: ConstructFactoryGetInstanceProps; diff --git a/packages/backend-graphql/src/factory.test.ts b/packages/backend-graphql/src/factory.test.ts index b4835f7a81..264adf5998 100644 --- a/packages/backend-graphql/src/factory.test.ts +++ b/packages/backend-graphql/src/factory.test.ts @@ -5,7 +5,6 @@ import { App, Stack } from 'aws-cdk-lib'; import { NestedStackResolver, SingletonConstructContainer, - StackMetadataBackendOutputStorageStrategy, ToggleableImportPathVerifier, } from '@aws-amplify/backend/test-utils'; import { Template } from 'aws-cdk-lib/assertions'; @@ -25,6 +24,7 @@ import { UserPool, UserPoolClient, } from 'aws-cdk-lib/aws-cognito'; +import { StackMetadataBackendOutputStorageStrategy } from '@aws-amplify/backend-output-storage'; const testSchema = ` input AMPLIFY {globalAuthRule: AuthRule = { allow: public }} # FOR TESTING ONLY! diff --git a/packages/backend-graphql/src/factory.ts b/packages/backend-graphql/src/factory.ts index 629bca59ba..5f64a1f8b9 100644 --- a/packages/backend-graphql/src/factory.ts +++ b/packages/backend-graphql/src/factory.ts @@ -94,13 +94,11 @@ class DataGenerator implements ConstructContainerEntryGenerator { authorizationConfig: authConfig, outputStorageStrategy: this.outputStorageStrategy, }; - const graphqlConstruct = new AmplifyGraphqlApi( + return new AmplifyGraphqlApi( scope, this.defaultName, graphqlConstructProps ); - - return graphqlConstruct; }; } diff --git a/packages/backend-output-schemas/API.md b/packages/backend-output-schemas/API.md index ecd550c8d7..79c7a014e8 100644 --- a/packages/backend-output-schemas/API.md +++ b/packages/backend-output-schemas/API.md @@ -6,11 +6,8 @@ import { z } from 'zod'; -// @public (undocumented) -export const amplifyStackMetadataKey = "AWS::Amplify::Output"; - // @public -export const authOutputKey = "authOutput"; +export const authOutputKey = "AWS::Amplify::Auth"; // @public export type BackendOutputEntryStackMetadata = z.infer; @@ -43,17 +40,17 @@ export const backendOutputStackMetadataSchema: z.ZodRecord>; // @public -export const graphqlOutputKey = "graphqlOutput"; +export const graphqlOutputKey = "AWS::Amplify::GraphQL"; // @public -export const storageOutputKey = "storageOutput"; +export const storageOutputKey = "AWS::Amplify::Storage"; // @public export type UnifiedBackendOutput = z.infer; // @public export const unifiedBackendOutputSchema: z.ZodObject<{ - authOutput: z.ZodOptional; payload: z.ZodObject<{ userPoolId: z.ZodString; @@ -108,7 +105,7 @@ export const unifiedBackendOutputSchema: z.ZodObject<{ googleClientId?: string | undefined; }; }>]>>; - graphqlOutput: z.ZodOptional; payload: z.ZodObject<{ awsAppsyncRegion: z.ZodString; @@ -153,7 +150,7 @@ export const unifiedBackendOutputSchema: z.ZodObject<{ awsAppsyncApiKey?: string | undefined; }; }>]>>; - storageOutput: z.ZodOptional; payload: z.ZodObject<{ bucketName: z.ZodString; @@ -179,7 +176,7 @@ export const unifiedBackendOutputSchema: z.ZodObject<{ }; }>]>>; }, "strip", z.ZodTypeAny, { - authOutput?: { + "AWS::Amplify::Auth"?: { version: "1"; payload: { userPoolId: string; @@ -192,7 +189,7 @@ export const unifiedBackendOutputSchema: z.ZodObject<{ googleClientId?: string | undefined; }; } | undefined; - graphqlOutput?: { + "AWS::Amplify::GraphQL"?: { version: "1"; payload: { awsAppsyncRegion: string; @@ -203,7 +200,7 @@ export const unifiedBackendOutputSchema: z.ZodObject<{ awsAppsyncApiKey?: string | undefined; }; } | undefined; - storageOutput?: { + "AWS::Amplify::Storage"?: { version: "1"; payload: { bucketName: string; @@ -211,7 +208,7 @@ export const unifiedBackendOutputSchema: z.ZodObject<{ }; } | undefined; }, { - authOutput?: { + "AWS::Amplify::Auth"?: { version: "1"; payload: { userPoolId: string; @@ -224,7 +221,7 @@ export const unifiedBackendOutputSchema: z.ZodObject<{ googleClientId?: string | undefined; }; } | undefined; - graphqlOutput?: { + "AWS::Amplify::GraphQL"?: { version: "1"; payload: { awsAppsyncRegion: string; @@ -235,7 +232,7 @@ export const unifiedBackendOutputSchema: z.ZodObject<{ awsAppsyncApiKey?: string | undefined; }; } | undefined; - storageOutput?: { + "AWS::Amplify::Storage"?: { version: "1"; payload: { bucketName: string; diff --git a/packages/backend-output-schemas/src/index.ts b/packages/backend-output-schemas/src/index.ts index f41e85f898..9dfabee6f6 100644 --- a/packages/backend-output-schemas/src/index.ts +++ b/packages/backend-output-schemas/src/index.ts @@ -6,15 +6,15 @@ import { versionedStorageOutputSchema } from './storage/index.js'; /** * Expected key that auth output is stored under */ -export const authOutputKey = 'authOutput'; +export const authOutputKey = 'AWS::Amplify::Auth'; /** * Expected key that graphql output is stored under */ -export const graphqlOutputKey = 'graphqlOutput'; +export const graphqlOutputKey = 'AWS::Amplify::GraphQL'; /** * Expected key that storage output is stored under */ -export const storageOutputKey = 'storageOutput'; +export const storageOutputKey = 'AWS::Amplify::Storage'; /** * Defines the unified expected shape of Amplify backend output. * As new constructs are added that need to contribute backend output, entries should be added here so that client config generation is aware of these outputs diff --git a/packages/backend-output-schemas/src/platform/amplify_stack_metadata_key.ts b/packages/backend-output-schemas/src/platform/amplify_stack_metadata_key.ts deleted file mode 100644 index bc75a030dd..0000000000 --- a/packages/backend-output-schemas/src/platform/amplify_stack_metadata_key.ts +++ /dev/null @@ -1 +0,0 @@ -export const amplifyStackMetadataKey = 'AWS::Amplify::Output'; diff --git a/packages/backend-output-schemas/src/platform/index.ts b/packages/backend-output-schemas/src/platform/index.ts index 2449d23cae..05922786d6 100644 --- a/packages/backend-output-schemas/src/platform/index.ts +++ b/packages/backend-output-schemas/src/platform/index.ts @@ -1,2 +1 @@ -export * from './amplify_stack_metadata_key.js'; export * from './stack_metadata_schemas.js'; diff --git a/packages/backend-output-schemas/src/platform/stack_metadata_schemas.ts b/packages/backend-output-schemas/src/platform/stack_metadata_schemas.ts index ad93a0d774..69d9ad4e16 100644 --- a/packages/backend-output-schemas/src/platform/stack_metadata_schemas.ts +++ b/packages/backend-output-schemas/src/platform/stack_metadata_schemas.ts @@ -1,8 +1,10 @@ import { z } from 'zod'; /** - * The types here are meant to be used internally when reading / writing backend output to stack metadata - * They should not be exposed in public APIs + * The types here are meant to be used internally when reading / writing backend output to stack metadata. + * + * They represent broader metadata types than the category-specific metadata objects that allows the platform to interact with metadata in a category-agnostic way + * They should not be exposed in public APIs (although they currently are under the "platform" submodule export so they can be consumed by both the backend and client-config packages */ /** diff --git a/packages/backend-output-storage/.npmignore b/packages/backend-output-storage/.npmignore new file mode 100644 index 0000000000..dbde1fb5db --- /dev/null +++ b/packages/backend-output-storage/.npmignore @@ -0,0 +1,14 @@ +# Be very careful editing this file. It is crafted to work around [this issue](https://github.com/npm/npm/issues/4479) + +# First ignore everything +**/* + +# Then add back in transpiled js and ts declaration files +!lib/**/*.js +!lib/**/*.d.ts + +# Then ignore test js and ts declaration files +*.test.js +*.test.d.ts + +# This leaves us with including only js and ts declaration files of functional code diff --git a/packages/backend-output-storage/API.md b/packages/backend-output-storage/API.md new file mode 100644 index 0000000000..aa9e206a5c --- /dev/null +++ b/packages/backend-output-storage/API.md @@ -0,0 +1,20 @@ +## API Report File for "@aws-amplify/backend-output-storage" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { BackendOutputEntry } from '@aws-amplify/plugin-types'; +import { BackendOutputStorageStrategy } from '@aws-amplify/plugin-types'; +import { Stack } from 'aws-cdk-lib'; + +// @public +export class StackMetadataBackendOutputStorageStrategy implements BackendOutputStorageStrategy { + constructor(stack: Stack); + addBackendOutputEntry: (keyName: string, backendOutputEntry: BackendOutputEntry) => void; + flush: () => void; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/packages/backend-output-storage/api-extractor.json b/packages/backend-output-storage/api-extractor.json new file mode 100644 index 0000000000..0f56de03f6 --- /dev/null +++ b/packages/backend-output-storage/api-extractor.json @@ -0,0 +1,3 @@ +{ + "extends": "../../api-extractor.base.json" +} diff --git a/packages/backend-output-storage/package.json b/packages/backend-output-storage/package.json new file mode 100644 index 0000000000..3759246b6e --- /dev/null +++ b/packages/backend-output-storage/package.json @@ -0,0 +1,22 @@ +{ + "name": "@aws-amplify/backend-output-storage", + "version": "0.1.0", + "type": "module", + "publishConfig": { + "access": "public" + }, + "exports": { + ".": { + "types": "./lib/index.d.ts", + "import": "./lib/index.js", + "require": "./lib/index.js" + } + }, + "types": "lib/index.d.ts", + "scripts": { + "update:api": "api-extractor run --local" + }, + "peerDependencies": { + "aws-cdk-lib": "^2.80.0" + } +} diff --git a/packages/backend-output-storage/src/index.ts b/packages/backend-output-storage/src/index.ts new file mode 100644 index 0000000000..05fc9a88da --- /dev/null +++ b/packages/backend-output-storage/src/index.ts @@ -0,0 +1 @@ +export * from './stack_metadata_output_storage_strategy.js'; diff --git a/packages/backend/src/engine/stack_metadata_output_storage_strategy.test.ts b/packages/backend-output-storage/src/stack_metadata_output_storage_strategy.test.ts similarity index 79% rename from packages/backend/src/engine/stack_metadata_output_storage_strategy.test.ts rename to packages/backend-output-storage/src/stack_metadata_output_storage_strategy.test.ts index 2cecf43ead..501595f13d 100644 --- a/packages/backend/src/engine/stack_metadata_output_storage_strategy.test.ts +++ b/packages/backend-output-storage/src/stack_metadata_output_storage_strategy.test.ts @@ -2,10 +2,7 @@ import { describe, it } from 'node:test'; import { StackMetadataBackendOutputStorageStrategy } from './stack_metadata_output_storage_strategy.js'; import { App, Stack } from 'aws-cdk-lib'; import { Template } from 'aws-cdk-lib/assertions'; -import { - amplifyStackMetadataKey, - backendOutputStackMetadataSchema, -} from '@aws-amplify/backend-output-schemas/platform'; +import { backendOutputStackMetadataSchema } from '@aws-amplify/backend-output-schemas/platform'; describe('StackMetadataBackendOutputStorageStrategy', () => { describe('storeOutput', () => { @@ -27,11 +24,9 @@ describe('StackMetadataBackendOutputStorageStrategy', () => { template.hasOutput('something', { Value: 'special' }); template.templateMatches({ Metadata: { - [amplifyStackMetadataKey]: { - TestStorageOutput: { - version: '1', - stackOutputs: ['something'], - }, + TestStorageOutput: { + version: '1', + stackOutputs: ['something'], }, }, }); @@ -53,9 +48,7 @@ describe('StackMetadataBackendOutputStorageStrategy', () => { const template = Template.fromStack(stack); // successfully parsing the metadata means it validated against the schema - backendOutputStackMetadataSchema.parse( - template.toJSON().Metadata[amplifyStackMetadataKey] - ); + backendOutputStackMetadataSchema.parse(template.toJSON().Metadata); }); }); }); diff --git a/packages/backend/src/engine/stack_metadata_output_storage_strategy.ts b/packages/backend-output-storage/src/stack_metadata_output_storage_strategy.ts similarity index 65% rename from packages/backend/src/engine/stack_metadata_output_storage_strategy.ts rename to packages/backend-output-storage/src/stack_metadata_output_storage_strategy.ts index fa87b230f0..be6fb8ec17 100644 --- a/packages/backend/src/engine/stack_metadata_output_storage_strategy.ts +++ b/packages/backend-output-storage/src/stack_metadata_output_storage_strategy.ts @@ -3,10 +3,7 @@ import { BackendOutputStorageStrategy, } from '@aws-amplify/plugin-types'; import { CfnOutput, Stack } from 'aws-cdk-lib'; -import { - BackendOutputStackMetadata, - amplifyStackMetadataKey, -} from '@aws-amplify/backend-output-schemas/platform'; +import { graphqlOutputKey } from '@aws-amplify/backend-output-schemas'; /** * Implementation of BackendOutputStorageStrategy that stores config data in stack metadata and outputs @@ -14,7 +11,6 @@ import { export class StackMetadataBackendOutputStorageStrategy implements BackendOutputStorageStrategy { - private readonly metadata: BackendOutputStackMetadata = {}; /** * Initialize the instance with a stack. * @@ -36,16 +32,23 @@ export class StackMetadataBackendOutputStorageStrategy new CfnOutput(this.stack, key, { value }); }); - this.metadata[keyName] = { + // TODO https://github.com/aws-amplify/samsara-cli/issues/252 + // temporary hack to work around the fact that the gql construct has hard-coded a duplicate of this key in their codebase + // once this hard-coding is removed and they are depending on the shared packages, this can be removed + const mappedKeyName = + keyName === 'graphqlOutput' ? graphqlOutputKey : keyName; + + this.stack.addMetadata(mappedKeyName, { version: backendOutputEntry.version, stackOutputs: Object.keys(backendOutputEntry.payload), - }; + }); }; /** * Persists the metadata object to the stack metadata */ flush = (): void => { - this.stack.addMetadata(amplifyStackMetadataKey, this.metadata); + // TODO https://github.com/aws-amplify/samsara-cli/issues/252 + // NOOP until the duplicate BackendOutputStorageStrategy type in the gql construct can be removed }; } diff --git a/packages/backend-output-storage/tsconfig.json b/packages/backend-output-storage/tsconfig.json new file mode 100644 index 0000000000..2aab102e9b --- /dev/null +++ b/packages/backend-output-storage/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { "rootDir": "src", "outDir": "lib" }, + "references": [] +} diff --git a/packages/backend-output-storage/typedoc.json b/packages/backend-output-storage/typedoc.json new file mode 100644 index 0000000000..35fed2c958 --- /dev/null +++ b/packages/backend-output-storage/typedoc.json @@ -0,0 +1,3 @@ +{ + "entryPoints": ["src/index.ts"] +} diff --git a/packages/backend-storage/API.md b/packages/backend-storage/API.md index fc9d07c63e..4c012b34f9 100644 --- a/packages/backend-storage/API.md +++ b/packages/backend-storage/API.md @@ -11,10 +11,13 @@ import { ConstructFactoryGetInstanceProps } from '@aws-amplify/plugin-types'; // @public export class AmplifyStorageFactory implements ConstructFactory { - constructor(props: AmplifyStorageProps); + constructor(props: AmplifyStorageFactoryProps); getInstance: ({ constructContainer, outputStorageStrategy, importPathVerifier, }: ConstructFactoryGetInstanceProps) => AmplifyStorage; } +// @public (undocumented) +export type AmplifyStorageFactoryProps = Omit; + // @public export const Storage: typeof AmplifyStorageFactory; diff --git a/packages/backend-storage/package.json b/packages/backend-storage/package.json index 5a45923177..e0710ac6c5 100644 --- a/packages/backend-storage/package.json +++ b/packages/backend-storage/package.json @@ -17,7 +17,8 @@ "update:api": "api-extractor run --local" }, "dependencies": { - "@aws-amplify/storage-construct-alpha": "^0.1.1-alpha.2" + "@aws-amplify/storage-construct-alpha": "^0.1.1-alpha.2", + "@aws-amplify/backend-output-storage": "^0.1.0" }, "devDependencies": { "@aws-amplify/backend": "^0.1.1-alpha.2" diff --git a/packages/backend-storage/src/factory.test.ts b/packages/backend-storage/src/factory.test.ts index b75646adf0..4331d901cf 100644 --- a/packages/backend-storage/src/factory.test.ts +++ b/packages/backend-storage/src/factory.test.ts @@ -5,7 +5,6 @@ import { Template } from 'aws-cdk-lib/assertions'; import { NestedStackResolver, SingletonConstructContainer, - StackMetadataBackendOutputStorageStrategy, ToggleableImportPathVerifier, } from '@aws-amplify/backend/test-utils'; import assert from 'node:assert'; @@ -16,6 +15,7 @@ import { ConstructFactoryGetInstanceProps, ImportPathVerifier, } from '@aws-amplify/plugin-types'; +import { StackMetadataBackendOutputStorageStrategy } from '@aws-amplify/backend-output-storage'; describe('AmplifyStorageFactory', () => { let storageFactory: AmplifyStorageFactory; diff --git a/packages/backend-storage/src/factory.ts b/packages/backend-storage/src/factory.ts index c88cd51ddc..4cbd369b81 100644 --- a/packages/backend-storage/src/factory.ts +++ b/packages/backend-storage/src/factory.ts @@ -11,6 +11,11 @@ import { AmplifyStorageProps, } from '@aws-amplify/storage-construct-alpha'; +export type AmplifyStorageFactoryProps = Omit< + AmplifyStorageProps, + 'outputStorageStrategy' +>; + /** * Singleton factory for a Storage bucket that can be used in `storage.ts` files */ @@ -21,7 +26,7 @@ export class AmplifyStorageFactory implements ConstructFactory { /** * Set the properties that will be used to initialize the bucket */ - constructor(private readonly props: AmplifyStorageProps) { + constructor(private readonly props: AmplifyStorageFactoryProps) { this.importStack = new Error().stack; } @@ -58,13 +63,10 @@ class AmplifyStorageGenerator implements ConstructContainerEntryGenerator { ) {} generateContainerEntry = (scope: Construct) => { - const storageConstruct = new AmplifyStorage( - scope, - this.defaultName, - this.props - ); - storageConstruct.storeOutput(this.outputStorageStrategy); - return storageConstruct; + return new AmplifyStorage(scope, this.defaultName, { + ...this.props, + outputStorageStrategy: this.outputStorageStrategy, + }); }; } diff --git a/packages/backend-storage/tsconfig.json b/packages/backend-storage/tsconfig.json index 234d222763..d0af4cb39c 100644 --- a/packages/backend-storage/tsconfig.json +++ b/packages/backend-storage/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "rootDir": "src", "outDir": "lib" }, "references": [ { "path": "../storage-construct" }, + { "path": "../backend-output-storage" }, { "path": "../backend" }, { "path": "../plugin-types" } ] diff --git a/packages/backend/package.json b/packages/backend/package.json index b13f006032..1e38222604 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -23,6 +23,7 @@ }, "dependencies": { "@aws-amplify/backend-output-schemas": "^0.2.0-alpha.2", + "@aws-amplify/backend-output-storage": "^0.1.0", "@aws-amplify/backend-secret": "^0.1.0" }, "peerDependencies": { diff --git a/packages/backend/src/backend.test.ts b/packages/backend/src/backend.test.ts index 02315438b9..e3ee374028 100644 --- a/packages/backend/src/backend.test.ts +++ b/packages/backend/src/backend.test.ts @@ -79,11 +79,9 @@ describe('Backend', () => { rootStackTemplate.hasOutput('bucketName', {}); rootStackTemplate.templateMatches({ Metadata: { - 'AWS::Amplify::Output': { - TestStorageOutput: { - version: '1', - stackOutputs: ['bucketName'], - }, + TestStorageOutput: { + version: '1', + stackOutputs: ['bucketName'], }, }, }); diff --git a/packages/backend/src/backend.ts b/packages/backend/src/backend.ts index fc067beb04..81c02f61bb 100644 --- a/packages/backend/src/backend.ts +++ b/packages/backend/src/backend.ts @@ -7,7 +7,7 @@ import { } from './engine/nested_stack_resolver.js'; import { SingletonConstructContainer } from './engine/singleton_construct_container.js'; import { ToggleableImportPathVerifier } from './engine/toggleable_import_path_verifier.js'; -import { StackMetadataBackendOutputStorageStrategy } from './engine/stack_metadata_output_storage_strategy.js'; +import { StackMetadataBackendOutputStorageStrategy } from '@aws-amplify/backend-output-storage'; import { createDefaultStack } from './default_stack_factory.js'; /** diff --git a/packages/backend/src/test-utils/index.ts b/packages/backend/src/test-utils/index.ts index 255afa9e6f..b9c3710fa5 100644 --- a/packages/backend/src/test-utils/index.ts +++ b/packages/backend/src/test-utils/index.ts @@ -1,5 +1,4 @@ export * from '../engine/amplify_stack.js'; export * from '../engine/nested_stack_resolver.js'; export * from '../engine/singleton_construct_container.js'; -export * from '../engine/stack_metadata_output_storage_strategy.js'; export * from '../engine/toggleable_import_path_verifier.js'; diff --git a/packages/backend/tsconfig.json b/packages/backend/tsconfig.json index 59b24d580a..a276683c17 100644 --- a/packages/backend/tsconfig.json +++ b/packages/backend/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "rootDir": "src", "outDir": "lib" }, "references": [ { "path": "../backend-output-schemas" }, + { "path": "../backend-output-storage" }, { "path": "../backend-secret" }, { "path": "../plugin-types" } ] diff --git a/packages/client-config/src/client-config-contributor/auth_client_config_contributor.test.ts b/packages/client-config/src/client-config-contributor/auth_client_config_contributor.test.ts index a914f39c29..645dfc4b05 100644 --- a/packages/client-config/src/client-config-contributor/auth_client_config_contributor.test.ts +++ b/packages/client-config/src/client-config-contributor/auth_client_config_contributor.test.ts @@ -1,13 +1,17 @@ import { describe, it } from 'node:test'; import assert from 'node:assert'; import { AuthClientConfigContributor } from './auth_client_config_contributor.js'; +import { + authOutputKey, + graphqlOutputKey, +} from '@aws-amplify/backend-output-schemas'; describe('AuthClientConfigContributor', () => { it('returns an empty object if output has no auth output', () => { const contributor = new AuthClientConfigContributor(); assert.deepStrictEqual( contributor.contribute({ - graphqlOutput: { + [graphqlOutputKey]: { version: '1', payload: { awsAppsyncApiEndpoint: 'testApiEndpoint', @@ -27,7 +31,7 @@ describe('AuthClientConfigContributor', () => { const contributor = new AuthClientConfigContributor(); assert.deepStrictEqual( contributor.contribute({ - authOutput: { + [authOutputKey]: { version: '1', payload: { identityPoolId: 'testIdentityPoolId', diff --git a/packages/client-config/src/client-config-contributor/auth_client_config_contributor.ts b/packages/client-config/src/client-config-contributor/auth_client_config_contributor.ts index 490e9d9a67..fce44fc969 100644 --- a/packages/client-config/src/client-config-contributor/auth_client_config_contributor.ts +++ b/packages/client-config/src/client-config-contributor/auth_client_config_contributor.ts @@ -1,5 +1,8 @@ import { ClientConfigContributor } from './client_config_contributor.js'; -import { UnifiedBackendOutput } from '@aws-amplify/backend-output-schemas'; +import { + UnifiedBackendOutput, + authOutputKey, +} from '@aws-amplify/backend-output-schemas'; import { AuthClientConfig } from '../client-config-types/auth_client_config.js'; /** @@ -10,7 +13,7 @@ export class AuthClientConfigContributor implements ClientConfigContributor { * Given some BackendOutput, contribute the Auth portion of the ClientConfig */ contribute = ({ - authOutput, + [authOutputKey]: authOutput, }: UnifiedBackendOutput): AuthClientConfig | Record => { if (authOutput === undefined) { return {}; diff --git a/packages/client-config/src/client-config-contributor/graphql_client_config_contributor.test.ts b/packages/client-config/src/client-config-contributor/graphql_client_config_contributor.test.ts index 369a952bce..771e8ea0a0 100644 --- a/packages/client-config/src/client-config-contributor/graphql_client_config_contributor.test.ts +++ b/packages/client-config/src/client-config-contributor/graphql_client_config_contributor.test.ts @@ -1,13 +1,17 @@ import { describe, it } from 'node:test'; import assert from 'node:assert'; import { GraphqlClientConfigContributor } from './graphql_client_config_contributor.js'; +import { + authOutputKey, + graphqlOutputKey, +} from '@aws-amplify/backend-output-schemas'; describe('GraphqlClientConfigContributor', () => { it('returns an empty object if output has no graphql output', () => { const contributor = new GraphqlClientConfigContributor(); assert.deepStrictEqual( contributor.contribute({ - authOutput: { + [authOutputKey]: { version: '1', payload: { identityPoolId: 'testIdentityPoolId', @@ -25,7 +29,7 @@ describe('GraphqlClientConfigContributor', () => { const contributor = new GraphqlClientConfigContributor(); assert.deepStrictEqual( contributor.contribute({ - graphqlOutput: { + [graphqlOutputKey]: { version: '1', payload: { awsAppsyncApiEndpoint: 'testApiEndpoint', diff --git a/packages/client-config/src/client-config-contributor/graphql_client_config_contributor.ts b/packages/client-config/src/client-config-contributor/graphql_client_config_contributor.ts index af64a678dc..1212be8b7b 100644 --- a/packages/client-config/src/client-config-contributor/graphql_client_config_contributor.ts +++ b/packages/client-config/src/client-config-contributor/graphql_client_config_contributor.ts @@ -1,5 +1,8 @@ import { ClientConfigContributor } from './client_config_contributor.js'; -import { UnifiedBackendOutput } from '@aws-amplify/backend-output-schemas'; +import { + UnifiedBackendOutput, + graphqlOutputKey, +} from '@aws-amplify/backend-output-schemas'; import { GraphqlClientConfig } from '../client-config-types/graphql_client_config.js'; /** @@ -10,7 +13,7 @@ export class GraphqlClientConfigContributor implements ClientConfigContributor { * Given some BackendOutput, contribute the Graphql API portion of the client config */ contribute = ({ - graphqlOutput, + [graphqlOutputKey]: graphqlOutput, }: UnifiedBackendOutput): GraphqlClientConfig | Record => { if (graphqlOutput === undefined) { return {}; diff --git a/packages/client-config/src/client-config-contributor/storage_client_config_contributor.test.ts b/packages/client-config/src/client-config-contributor/storage_client_config_contributor.test.ts index 4161eca080..9275ee9945 100644 --- a/packages/client-config/src/client-config-contributor/storage_client_config_contributor.test.ts +++ b/packages/client-config/src/client-config-contributor/storage_client_config_contributor.test.ts @@ -1,13 +1,17 @@ import { describe, it } from 'node:test'; import assert from 'node:assert'; import { StorageClientConfigContributor } from './storage_client_config_contributor.js'; +import { + graphqlOutputKey, + storageOutputKey, +} from '@aws-amplify/backend-output-schemas'; describe('StorageClientConfigContributor', () => { it('returns an empty object if output has no storage output', () => { const contributor = new StorageClientConfigContributor(); assert.deepStrictEqual( contributor.contribute({ - graphqlOutput: { + [graphqlOutputKey]: { version: '1', payload: { awsAppsyncApiEndpoint: 'stuff', @@ -26,7 +30,7 @@ describe('StorageClientConfigContributor', () => { const contributor = new StorageClientConfigContributor(); assert.deepStrictEqual( contributor.contribute({ - storageOutput: { + [storageOutputKey]: { version: '1', payload: { bucketName: 'testBucketName', diff --git a/packages/client-config/src/client-config-contributor/storage_client_config_contributor.ts b/packages/client-config/src/client-config-contributor/storage_client_config_contributor.ts index 62f6b88cb6..f3312dcc77 100644 --- a/packages/client-config/src/client-config-contributor/storage_client_config_contributor.ts +++ b/packages/client-config/src/client-config-contributor/storage_client_config_contributor.ts @@ -1,5 +1,8 @@ import { ClientConfigContributor } from './client_config_contributor.js'; -import { UnifiedBackendOutput } from '@aws-amplify/backend-output-schemas'; +import { + UnifiedBackendOutput, + storageOutputKey, +} from '@aws-amplify/backend-output-schemas'; import { StorageClientConfig } from '../client-config-types/storage_client_config.js'; /** @@ -10,7 +13,7 @@ export class StorageClientConfigContributor implements ClientConfigContributor { * Given some BackendOutput, contribute the Storage portion of the ClientConfig */ contribute = ({ - storageOutput, + [storageOutputKey]: storageOutput, }: UnifiedBackendOutput): StorageClientConfig | Record => { if (storageOutput === undefined) { return {}; diff --git a/packages/client-config/src/stack_metadata_output_retrieval_strategy.test.ts b/packages/client-config/src/stack_metadata_output_retrieval_strategy.test.ts index 431120f64f..4f267baaed 100644 --- a/packages/client-config/src/stack_metadata_output_retrieval_strategy.test.ts +++ b/packages/client-config/src/stack_metadata_output_retrieval_strategy.test.ts @@ -6,9 +6,12 @@ import { } from '@aws-sdk/client-cloudformation'; import { StackMetadataBackendOutputRetrievalStrategy } from './stack_metadata_output_retrieval_strategy.js'; import assert from 'node:assert'; -import { amplifyStackMetadataKey } from '@aws-amplify/backend-output-schemas/platform'; import { ZodError } from 'zod'; import { MainStackNameResolver } from '@aws-amplify/plugin-types'; +import { + authOutputKey, + graphqlOutputKey, +} from '@aws-amplify/backend-output-schemas'; describe('StackMetadataBackendOutputRetrievalStrategy', () => { describe('fetchBackendOutput', () => { @@ -44,11 +47,9 @@ describe('StackMetadataBackendOutputRetrievalStrategy', () => { if (command instanceof GetTemplateSummaryCommand) { return { Metadata: JSON.stringify({ - [amplifyStackMetadataKey]: { - TestOutput: { - version: '1', - stackOutputs: ['testName1', 'testName2'], - }, + [authOutputKey]: { + version: '1', + stackOutputs: ['testName1', 'testName2'], }, }), }; @@ -85,11 +86,9 @@ describe('StackMetadataBackendOutputRetrievalStrategy', () => { if (command instanceof GetTemplateSummaryCommand) { return { Metadata: JSON.stringify({ - [amplifyStackMetadataKey]: { - TestOutput: { - version: '1', // should be number - stackOutputs: [{ wrong: 'type' }, 'otherThing'], - }, + [authOutputKey]: { + version: '1', // should be number + stackOutputs: [{ wrong: 'type' }, 'otherThing'], }, }), }; @@ -119,11 +118,9 @@ describe('StackMetadataBackendOutputRetrievalStrategy', () => { if (command instanceof GetTemplateSummaryCommand) { return { Metadata: JSON.stringify({ - [amplifyStackMetadataKey]: { - TestOutput: { - version: '1', - stackOutputs: ['testName1', 'testName2'], - }, + [authOutputKey]: { + version: '1', + stackOutputs: ['testName1', 'testName2'], }, }), }; @@ -165,15 +162,13 @@ describe('StackMetadataBackendOutputRetrievalStrategy', () => { if (command instanceof GetTemplateSummaryCommand) { return { Metadata: JSON.stringify({ - [amplifyStackMetadataKey]: { - TestOutput: { - version: '1', - stackOutputs: ['testName1', 'testName2'], - }, - OtherOutput: { - version: '2', - stackOutputs: ['thing1', 'thing2'], - }, + [authOutputKey]: { + version: '1', + stackOutputs: ['testName1', 'testName2'], + }, + [graphqlOutputKey]: { + version: '2', + stackOutputs: ['thing1', 'thing2'], }, }), }; @@ -218,14 +213,14 @@ describe('StackMetadataBackendOutputRetrievalStrategy', () => { const output = await retrievalStrategy.fetchBackendOutput(); assert.deepStrictEqual(output, { - TestOutput: { + [authOutputKey]: { version: '1', payload: { testName1: 'testValue1', testName2: 'testValue2', }, }, - OtherOutput: { + [graphqlOutputKey]: { version: '2', payload: { thing1: 'The cat', diff --git a/packages/client-config/src/stack_metadata_output_retrieval_strategy.ts b/packages/client-config/src/stack_metadata_output_retrieval_strategy.ts index f588f4b35c..7dbaa477ac 100644 --- a/packages/client-config/src/stack_metadata_output_retrieval_strategy.ts +++ b/packages/client-config/src/stack_metadata_output_retrieval_strategy.ts @@ -8,10 +8,7 @@ import { BackendOutputRetrievalStrategy, MainStackNameResolver, } from '@aws-amplify/plugin-types'; -import { - amplifyStackMetadataKey, - backendOutputStackMetadataSchema, -} from '@aws-amplify/backend-output-schemas/platform'; +import { backendOutputStackMetadataSchema } from '@aws-amplify/backend-output-schemas/platform'; /** * Gets Amplify backend outputs from stack metadata and outputs @@ -46,12 +43,9 @@ export class StackMetadataBackendOutputRetrievalStrategy const metadataObject = JSON.parse(templateSummary.Metadata); - const unvalidatedBackendOutput = metadataObject[amplifyStackMetadataKey]; - // parse and validate the metadata object - const backendOutputMetadata = backendOutputStackMetadataSchema.parse( - unvalidatedBackendOutput - ); + const backendOutputMetadata = + backendOutputStackMetadataSchema.parse(metadataObject); // DescribeStacks includes the template output const stackDescription = await this.cfnClient.send( diff --git a/packages/client-config/src/unified_client_config_generator.test.ts b/packages/client-config/src/unified_client_config_generator.test.ts index d951bc671f..d1e45838a6 100644 --- a/packages/client-config/src/unified_client_config_generator.test.ts +++ b/packages/client-config/src/unified_client_config_generator.test.ts @@ -4,14 +4,18 @@ import { UnifiedClientConfigGenerator } from './unified_client_config_generator. import assert from 'node:assert'; import { AuthClientConfigContributor } from './client-config-contributor/auth_client_config_contributor.js'; import { GraphqlClientConfigContributor } from './client-config-contributor/graphql_client_config_contributor.js'; -import { UnifiedBackendOutput } from '@aws-amplify/backend-output-schemas'; +import { + UnifiedBackendOutput, + authOutputKey, + graphqlOutputKey, +} from '@aws-amplify/backend-output-schemas'; import { ClientConfig } from './client-config-types/client_config.js'; describe('UnifiedClientConfigGenerator', () => { describe('generateClientConfig', () => { it('transforms backend output into client config', async () => { const stubOutput: UnifiedBackendOutput = { - authOutput: { + [authOutputKey]: { version: '1', payload: { identityPoolId: 'testIdentityPoolId', @@ -20,7 +24,7 @@ describe('UnifiedClientConfigGenerator', () => { authRegion: 'testRegion', }, }, - graphqlOutput: { + [graphqlOutputKey]: { version: '1', payload: { awsAppsyncApiEndpoint: 'testApiEndpoint', diff --git a/packages/create-amplify/templates/basic-auth-data/expected-cdk-out/amplify-testAppId-testBranchName.assets.json b/packages/create-amplify/templates/basic-auth-data/expected-cdk-out/amplify-testAppId-testBranchName.assets.json index 07e15e709e..e17da48b07 100644 --- a/packages/create-amplify/templates/basic-auth-data/expected-cdk-out/amplify-testAppId-testBranchName.assets.json +++ b/packages/create-amplify/templates/basic-auth-data/expected-cdk-out/amplify-testAppId-testBranchName.assets.json @@ -352,7 +352,7 @@ } } }, - "93b4d3c4f5aad9d55fcad7aaa2be3bdbe17249f0e45678f6f66c510834ddd8ed": { + "dffc8a213c76b1f33d2cacb9fe316a495d76ba1860f8011909231a11587ff8c9": { "source": { "path": "amplify-testAppId-testBranchName.template.json", "packaging": "file" @@ -360,7 +360,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "93b4d3c4f5aad9d55fcad7aaa2be3bdbe17249f0e45678f6f66c510834ddd8ed.json", + "objectKey": "dffc8a213c76b1f33d2cacb9fe316a495d76ba1860f8011909231a11587ff8c9.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/create-amplify/templates/basic-auth-data/expected-cdk-out/amplify-testAppId-testBranchName.template.json b/packages/create-amplify/templates/basic-auth-data/expected-cdk-out/amplify-testAppId-testBranchName.template.json index 3c6692290d..1e06935694 100644 --- a/packages/create-amplify/templates/basic-auth-data/expected-cdk-out/amplify-testAppId-testBranchName.template.json +++ b/packages/create-amplify/templates/basic-auth-data/expected-cdk-out/amplify-testAppId-testBranchName.template.json @@ -1,25 +1,23 @@ { "Metadata": { - "AWS::Amplify::Output": { - "authOutput": { - "version": "1", - "stackOutputs": [ - "userPoolId", - "webClientId", - "identityPoolId", - "authRegion" - ] - }, - "graphqlOutput": { - "version": "1", - "stackOutputs": [ - "awsAppsyncApiId", - "awsAppsyncApiEndpoint", - "awsAppsyncAuthenticationType", - "awsAppsyncRegion", - "amplifyApiModelSchemaS3Uri" - ] - } + "AWS::Amplify::Auth": { + "version": "1", + "stackOutputs": [ + "userPoolId", + "webClientId", + "identityPoolId", + "authRegion" + ] + }, + "AWS::Amplify::GraphQL": { + "version": "1", + "stackOutputs": [ + "awsAppsyncApiId", + "awsAppsyncApiEndpoint", + "awsAppsyncAuthenticationType", + "awsAppsyncRegion", + "amplifyApiModelSchemaS3Uri" + ] } }, "Resources": { diff --git a/packages/integration-tests/test-projects/data-storage-auth-with-triggers/expected-cdk-out/amplify-testAppId-testBranchName.assets.json b/packages/integration-tests/test-projects/data-storage-auth-with-triggers/expected-cdk-out/amplify-testAppId-testBranchName.assets.json index 787b52042e..5ee6d54422 100644 --- a/packages/integration-tests/test-projects/data-storage-auth-with-triggers/expected-cdk-out/amplify-testAppId-testBranchName.assets.json +++ b/packages/integration-tests/test-projects/data-storage-auth-with-triggers/expected-cdk-out/amplify-testAppId-testBranchName.assets.json @@ -313,7 +313,7 @@ } } }, - "c68d4e15ab0316467c23706d0f08ec8f4e6cb455fcfb76176c69a0d3b9e3fc57": { + "526d0a14bf9079dd2bb2e37686a1e8ad131b37383f9f9bc07ac602953adf4f4a": { "source": { "path": "amplify-testAppId-testBranchName.template.json", "packaging": "file" @@ -321,7 +321,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "c68d4e15ab0316467c23706d0f08ec8f4e6cb455fcfb76176c69a0d3b9e3fc57.json", + "objectKey": "526d0a14bf9079dd2bb2e37686a1e8ad131b37383f9f9bc07ac602953adf4f4a.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/integration-tests/test-projects/data-storage-auth-with-triggers/expected-cdk-out/amplify-testAppId-testBranchName.template.json b/packages/integration-tests/test-projects/data-storage-auth-with-triggers/expected-cdk-out/amplify-testAppId-testBranchName.template.json index 3af1d8f0e1..98322c939f 100644 --- a/packages/integration-tests/test-projects/data-storage-auth-with-triggers/expected-cdk-out/amplify-testAppId-testBranchName.template.json +++ b/packages/integration-tests/test-projects/data-storage-auth-with-triggers/expected-cdk-out/amplify-testAppId-testBranchName.template.json @@ -1,32 +1,30 @@ { "Metadata": { - "AWS::Amplify::Output": { - "authOutput": { - "version": "1", - "stackOutputs": [ - "userPoolId", - "webClientId", - "identityPoolId", - "authRegion" - ] - }, - "storageOutput": { - "version": "1", - "stackOutputs": [ - "storageRegion", - "bucketName" - ] - }, - "graphqlOutput": { - "version": "1", - "stackOutputs": [ - "awsAppsyncApiId", - "awsAppsyncApiEndpoint", - "awsAppsyncAuthenticationType", - "awsAppsyncRegion", - "amplifyApiModelSchemaS3Uri" - ] - } + "AWS::Amplify::Auth": { + "version": "1", + "stackOutputs": [ + "userPoolId", + "webClientId", + "identityPoolId", + "authRegion" + ] + }, + "AWS::Amplify::Storage": { + "version": "1", + "stackOutputs": [ + "storageRegion", + "bucketName" + ] + }, + "AWS::Amplify::GraphQL": { + "version": "1", + "stackOutputs": [ + "awsAppsyncApiId", + "awsAppsyncApiEndpoint", + "awsAppsyncAuthenticationType", + "awsAppsyncRegion", + "amplifyApiModelSchemaS3Uri" + ] } }, "Resources": { diff --git a/packages/storage-construct/API.md b/packages/storage-construct/API.md index 246a1f61b2..f643866a0a 100644 --- a/packages/storage-construct/API.md +++ b/packages/storage-construct/API.md @@ -5,19 +5,18 @@ ```ts import { BackendOutputStorageStrategy } from '@aws-amplify/plugin-types'; -import { BackendOutputWriter } from '@aws-amplify/plugin-types'; import { Construct } from 'constructs'; import { StorageOutput } from '@aws-amplify/backend-output-schemas/storage'; // @public -export class AmplifyStorage extends Construct implements BackendOutputWriter { +export class AmplifyStorage extends Construct { constructor(scope: Construct, id: string, props: AmplifyStorageProps); - storeOutput: (outputStorageStrategy: BackendOutputStorageStrategy) => void; } // @public (undocumented) export type AmplifyStorageProps = { versioned?: boolean; + outputStorageStrategy?: BackendOutputStorageStrategy; }; // (No @packageDocumentation comment for this package) diff --git a/packages/storage-construct/package.json b/packages/storage-construct/package.json index 12a17cd193..a5ac47f481 100644 --- a/packages/storage-construct/package.json +++ b/packages/storage-construct/package.json @@ -17,7 +17,8 @@ "update:api": "api-extractor run --local" }, "dependencies": { - "@aws-amplify/backend-output-schemas": "^0.2.0-alpha.2" + "@aws-amplify/backend-output-schemas": "^0.2.0-alpha.2", + "@aws-amplify/backend-output-storage": "^0.1.0" }, "devDependencies": { "@aws-amplify/plugin-types": "^0.1.1-alpha.3" diff --git a/packages/storage-construct/src/construct.test.ts b/packages/storage-construct/src/construct.test.ts index 0604e3a0cd..4343c608fd 100644 --- a/packages/storage-construct/src/construct.test.ts +++ b/packages/storage-construct/src/construct.test.ts @@ -33,7 +33,6 @@ describe('AmplifyStorage', () => { it('stores output using the provided strategy', () => { const app = new App(); const stack = new Stack(app); - const storageConstruct = new AmplifyStorage(stack, 'test', {}); const storeOutputMock = mock.fn(); const storageStrategy: BackendOutputStorageStrategy = @@ -41,7 +40,10 @@ describe('AmplifyStorage', () => { addBackendOutputEntry: storeOutputMock, flush: mock.fn(), }; - storageConstruct.storeOutput(storageStrategy); + + const storageConstruct = new AmplifyStorage(stack, 'test', { + outputStorageStrategy: storageStrategy, + }); const expectedBucketName = ( storageConstruct.node.findChild('testBucket') as Bucket @@ -62,5 +64,20 @@ describe('AmplifyStorage', () => { }, ]); }); + it('stores output when no storage strategy is injected', () => { + const app = new App(); + const stack = new Stack(app); + + new AmplifyStorage(stack, 'test', {}); + const template = Template.fromStack(stack); + template.templateMatches({ + Metadata: { + [storageOutputKey]: { + version: '1', + stackOutputs: ['storageRegion', 'bucketName'], + }, + }, + }); + }); }); }); diff --git a/packages/storage-construct/src/construct.ts b/packages/storage-construct/src/construct.ts index 85ee174bd3..01fe9f4efb 100644 --- a/packages/storage-construct/src/construct.ts +++ b/packages/storage-construct/src/construct.ts @@ -1,15 +1,14 @@ import { Construct } from 'constructs'; import { Bucket, BucketProps } from 'aws-cdk-lib/aws-s3'; -import { - BackendOutputStorageStrategy, - BackendOutputWriter, -} from '@aws-amplify/plugin-types'; +import { BackendOutputStorageStrategy } from '@aws-amplify/plugin-types'; import { storageOutputKey } from '@aws-amplify/backend-output-schemas'; import { StorageOutput } from '@aws-amplify/backend-output-schemas/storage'; import { Stack } from 'aws-cdk-lib'; +import { StackMetadataBackendOutputStorageStrategy } from '@aws-amplify/backend-output-storage'; export type AmplifyStorageProps = { versioned?: boolean; + outputStorageStrategy?: BackendOutputStorageStrategy; }; /** @@ -17,7 +16,7 @@ export type AmplifyStorageProps = { * * Currently just a thin wrapper around an S3 bucket */ -export class AmplifyStorage extends Construct implements BackendOutputWriter { +export class AmplifyStorage extends Construct { private readonly bucket: Bucket; /** * Create a new AmplifyStorage instance @@ -30,13 +29,17 @@ export class AmplifyStorage extends Construct implements BackendOutputWriter { }; this.bucket = new Bucket(this, `${id}Bucket`, bucketProps); + + this.storeOutput(props.outputStorageStrategy); } /** * Store storage outputs using provided strategy */ - storeOutput = ( - outputStorageStrategy: BackendOutputStorageStrategy + private storeOutput = ( + outputStorageStrategy: BackendOutputStorageStrategy = new StackMetadataBackendOutputStorageStrategy( + Stack.of(this) + ) ): void => { outputStorageStrategy.addBackendOutputEntry(storageOutputKey, { version: '1', diff --git a/packages/storage-construct/tsconfig.json b/packages/storage-construct/tsconfig.json index 8e6ba2e792..4b69ecc6df 100644 --- a/packages/storage-construct/tsconfig.json +++ b/packages/storage-construct/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "rootDir": "src", "outDir": "lib" }, "references": [ { "path": "../backend-output-schemas" }, + { "path": "../backend-output-storage" }, { "path": "../plugin-types" } ] }