UNPKG

@aws-amplify/core

Version:

Core category of aws-amplify

194 lines (173 loc) • 5.3 kB
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { LegacyConfig, ResourcesConfig } from '../singleton/types'; import { AmplifyOutputsUnknown } from '../singleton/AmplifyOutputs/types'; import { parseAmplifyConfig } from '../utils/parseAmplifyConfig'; import { deepMerge } from '../utils/deepMerge'; /** * Supported category names for `.add()`. */ type CategoryName = keyof ResourcesConfig; /** * Maps a category name to its config type. */ type CategoryConfig<K extends CategoryName> = NonNullable<ResourcesConfig[K]>; /** * Allowed seed formats for `createConfiguration({ from })`. */ type ConfigurationSeed = | ResourcesConfig | LegacyConfig | AmplifyOutputsUnknown | ConfigurationBuilder; /** * Recursively makes all properties optional. */ type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T; export interface ConfigurationBuilder { /** * Merge an existing config into this builder. Accepts any format that * `Amplify.configure()` accepts, or another `ConfigurationBuilder`. * * @example * ```ts * const config = createConfiguration() * .from(amplifyOutputs) * .add('Storage', { S3: { bucket: 'my-bucket', region: 'us-east-1' } }) * .build(); * ``` */ from(existing: ConfigurationSeed): ConfigurationBuilder; /** * Add or replace a category configuration. * * @example * ```ts * config.add('Auth', { Cognito: { userPoolId: '...', userPoolClientId: '...' } }); * config.add('Storage', { S3: { bucket: '...', region: '...' } }); * ``` */ add<K extends CategoryName>( category: K, value: CategoryConfig<K>, ): ConfigurationBuilder; /** * Deep-merge a partial config into an existing category. Use this to * override specific nested values without replacing the entire category. * * @example * ```ts * // Base config from outputs, override just the user pool for dev * const dev = createConfiguration({ from: outputs }) * .patch('Auth', { Cognito: { userPoolId: 'us-east-1_DEV' } }) * .build(); * ``` */ patch<K extends CategoryName>( category: K, value: DeepPartial<CategoryConfig<K>>, ): ConfigurationBuilder; /** Shorthand for `.add('Auth', config)` */ auth(config: CategoryConfig<'Auth'>): ConfigurationBuilder; /** Shorthand for `.add('Storage', config)` */ storage(config: CategoryConfig<'Storage'>): ConfigurationBuilder; /** Shorthand for `.add('API', config)` */ api(config: CategoryConfig<'API'>): ConfigurationBuilder; /** Shorthand for `.add('Analytics', config)` */ analytics(config: CategoryConfig<'Analytics'>): ConfigurationBuilder; /** Shorthand for `.add('Geo', config)` */ geo(config: CategoryConfig<'Geo'>): ConfigurationBuilder; /** Shorthand for `.add('Notifications', config)` */ notifications(config: CategoryConfig<'Notifications'>): ConfigurationBuilder; /** Shorthand for `.add('Interactions', config)` */ interactions(config: CategoryConfig<'Interactions'>): ConfigurationBuilder; /** Shorthand for `.add('Predictions', config)` */ predictions(config: CategoryConfig<'Predictions'>): ConfigurationBuilder; /** * Produces a frozen `ResourcesConfig` ready for `Amplify.configure()`. */ build(): ResourcesConfig; } export interface CreateConfigurationBuilderOptions { from?: ConfigurationSeed; } /** * Creates a configuration builder for constructing `ResourcesConfig` objects * programmatically. * * @example * ```ts * import outputs from './amplify_outputs.json'; * * const config = createConfiguration({ from: outputs }) * .add('Storage', { S3: { bucket: 'my-bucket', region: 'us-east-1' } }) * .build(); * * Amplify.configure(config); * ``` */ export function createConfigurationBuilder( options?: CreateConfigurationBuilderOptions, ): ConfigurationBuilder { const config: ResourcesConfig = {}; function mergeFrom(seed: ConfigurationSeed): void { const resolved: ResourcesConfig = 'build' in seed && typeof seed.build === 'function' ? seed.build() : parseAmplifyConfig( seed as ResourcesConfig | LegacyConfig | AmplifyOutputsUnknown, ); Object.assign(config, resolved); } if (options?.from) { mergeFrom(options.from); } const builder: ConfigurationBuilder = { from(existing) { mergeFrom(existing); return builder; }, add(category, value) { (config as Record<string, unknown>)[category] = value; return builder; }, patch(category, value) { const existing = (config as Record<string, unknown>)[category]; (config as Record<string, unknown>)[category] = deepMerge( existing ?? {}, value, ); return builder; }, auth(value) { return builder.add('Auth', value); }, storage(value) { return builder.add('Storage', value); }, api(value) { return builder.add('API', value); }, analytics(value) { return builder.add('Analytics', value); }, geo(value) { return builder.add('Geo', value); }, notifications(value) { return builder.add('Notifications', value); }, interactions(value) { return builder.add('Interactions', value); }, predictions(value) { return builder.add('Predictions', value); }, build(): ResourcesConfig { return Object.freeze({ ...config }); }, }; return builder; }