diff --git a/packages/parameters/jest.config.js b/packages/parameters/jest.config.js index 6c267d005e..d7114e8417 100644 --- a/packages/parameters/jest.config.js +++ b/packages/parameters/jest.config.js @@ -25,6 +25,7 @@ module.exports = { 'coveragePathIgnorePatterns': [ '/node_modules/', '/types/', + '/src/docs.ts', // this file is only used for documentation ], 'coverageThreshold': { 'global': { diff --git a/packages/parameters/package.json b/packages/parameters/package.json index 469e72f70b..754508eca9 100644 --- a/packages/parameters/package.json +++ b/packages/parameters/package.json @@ -30,7 +30,7 @@ "license": "MIT-0", "main": "./lib/index.js", "types": "./lib/index.d.ts", - "typedocMain": "src/file_that_does_not_exist_so_its_ignored_from_api_docs.ts", + "typedocMain": "src/docs.ts", "files": [ "lib" ], diff --git a/packages/parameters/src/BaseProvider.ts b/packages/parameters/src/BaseProvider.ts index b2fc4efc1c..e9456d8e00 100644 --- a/packages/parameters/src/BaseProvider.ts +++ b/packages/parameters/src/BaseProvider.ts @@ -9,6 +9,25 @@ import type { BaseProviderInterface, GetMultipleOptionsInterface, GetOptionsInte // These providers are dinamycally intialized on first use of the helper functions const DEFAULT_PROVIDERS: Record = {}; +/** + * Base class for all providers. + * + * As an abstract class, it should not be used directly, but rather extended by other providers. + * + * It implements the common logic for all providers, such as caching, transformation, etc. + * Each provider that extends this class must implement the `_get` and `_getMultiple` abstract methods. + * + * These methods are responsible for retrieving the values from the underlying parameter store. They are + * called by the `get` and `getMultiple` methods, which are responsible for caching and transformation. + * + * If there are multiple calls to the same parameter but in a different transform, they will be stored multiple times. + * This allows us to optimize by transforming the data only once per retrieval, thus there is no need to transform cached values multiple times. + * + * However, this means that we need to make multiple calls to the underlying parameter store if we need to return it in different transforms. + * + * Since the number of supported transform is small and the probability that a given parameter will always be used in a specific transform, + * this should be an acceptable tradeoff. + */ abstract class BaseProvider implements BaseProviderInterface { protected store: Map; @@ -16,26 +35,28 @@ abstract class BaseProvider implements BaseProviderInterface { this.store = new Map(); } + /** + * Add a value to the cache. + * + * @param {string} key - Key of the cached value + * @param {string | Uint8Array | Record} value - Value to be cached + * @param {number} maxAge - Maximum age in seconds for the value to be cached + */ public addToCache(key: string, value: string | Uint8Array | Record, maxAge: number): void { if (maxAge <= 0) return; this.store.set(key, new ExpirableValue(value, maxAge)); } + /** + * Clear the cache. + */ public clearCache(): void { this.store.clear(); } /** - * Retrieve a parameter value or return the cached value - * - * If there are multiple calls to the same parameter but in a different transform, they will be stored multiple times. - * This allows us to optimize by transforming the data only once per retrieval, thus there is no need to transform cached values multiple times. - * - * However, this means that we need to make multiple calls to the underlying parameter store if we need to return it in different transforms. - * - * Since the number of supported transform is small and the probability that a given parameter will always be used in a specific transform, - * this should be an acceptable tradeoff. + * Retrieve a parameter value or return the cached value. * * @param {string} name - Parameter name * @param {GetOptionsInterface} options - Options to configure maximum age, trasformation, AWS SDK options, or force fetch @@ -68,6 +89,13 @@ abstract class BaseProvider implements BaseProviderInterface { return value; } + /** + * Retrieve multiple parameter values or return the cached values. + * + * @param {string} path - Parameters path + * @param {GetMultipleOptionsInterface} options - Options to configure maximum age, trasformation, AWS SDK options, or force fetch + * @returns + */ public async getMultiple(path: string, options?: GetMultipleOptionsInterface): Promise> { const configs = new GetMultipleOptions(options || {}); const key = [ path, configs.transform ].toString(); @@ -97,7 +125,7 @@ abstract class BaseProvider implements BaseProviderInterface { } /** - * Check whether a key has expired in the cache or not + * Check whether a key has expired in the cache or not. * * It returns true if the key is expired or not present in the cache. * @@ -111,7 +139,7 @@ abstract class BaseProvider implements BaseProviderInterface { } /** - * Retrieve parameter value from the underlying parameter store + * Retrieve parameter value from the underlying parameter store. * * @param {string} name - Parameter name * @param {unknown} options - Options to pass to the underlying implemented method @@ -119,7 +147,7 @@ abstract class BaseProvider implements BaseProviderInterface { protected abstract _get(name: string, options?: unknown): Promise; /** - * Retrieve multiple parameter values from the underlying parameter store + * Retrieve multiple parameter values from the underlying parameter store. * * @param {string} path - Parameter name * @param {unknown} options - Options to pass to the underlying implementated method @@ -128,6 +156,16 @@ abstract class BaseProvider implements BaseProviderInterface { } +/** + * Utility function to transform a value. + * + * It supports JSON and binary transformations, as well as an 'auto' mode that will try to transform the value based on the key. + * + * @param {string | Uint8Array | undefined} value - Value to be transformed + * @param {TransformOptions} transform - Transform to be applied, can be 'json', 'binary', or 'auto' + * @param {boolean} throwOnTransformError - Whether to throw an error if the transformation fails, when transforming multiple values this can be set to false + * @param {string} key - Key of the value to be transformed, used to determine the transformation method when using 'auto' + */ const transformValue = (value: string | Uint8Array | undefined, transform: TransformOptions, throwOnTransformError: boolean, key: string): string | Record | undefined => { try { const normalizedTransform = transform.toLowerCase(); @@ -159,6 +197,15 @@ const transformValue = (value: string | Uint8Array | undefined, transform: Trans } }; +/** + * Utility function to transform multiple values. + * + * It iterates over the values and applies the transformation to each one by calling the `transformValue` function. + * + * @param {Record} value - Values to be transformed + * @param {TransformOptions} transform - Transform to be applied, can be 'json', 'binary', or 'auto' + * @param {boolean} throwOnTransformError - Whether to throw an error if the transformation fails, when transforming multiple values this can be set to false + */ const transformValues = (value: Record, transform: TransformOptions, throwOnTransformError: boolean): Record | undefined> => { const transformedValues: Record | undefined> = {}; for (const [ entryKey, entryValue ] of Object.entries(value)) { diff --git a/packages/parameters/src/Exceptions.ts b/packages/parameters/src/Exceptions.ts index 845577e453..09712bb60c 100644 --- a/packages/parameters/src/Exceptions.ts +++ b/packages/parameters/src/Exceptions.ts @@ -1,5 +1,8 @@ class GetParameterError extends Error {} +/** + * Error thrown when a transform fails. + */ class TransformParameterError extends Error { public constructor(transform: string, message: string) { super(message); diff --git a/packages/parameters/src/ExpirableValue.ts b/packages/parameters/src/ExpirableValue.ts index 7dcc3a2473..35f6c13be8 100644 --- a/packages/parameters/src/ExpirableValue.ts +++ b/packages/parameters/src/ExpirableValue.ts @@ -1,15 +1,31 @@ import type { ExpirableValueInterface } from './types'; +/** + * Class to represent a value that can expire. + * + * Upon creation, the value is assigned a TTL (time to live) that is calculated + * by adding the current time with the maximum age. + */ class ExpirableValue implements ExpirableValueInterface { public ttl: number; public value: string | Uint8Array | Record; + /** + * + * @param value - Value to be cached + * @param maxAge - Maximum age in seconds for the value to be cached + */ public constructor(value: string | Uint8Array | Record, maxAge: number) { this.value = value; const timeNow = new Date(); this.ttl = timeNow.setSeconds(timeNow.getSeconds() + maxAge); } + /** + * Check if the value has expired. + * + * @returns {boolean} - True if the value has expired, false otherwise + */ public isExpired(): boolean { return this.ttl < Date.now(); } diff --git a/packages/parameters/src/GetMultipleOptions.ts b/packages/parameters/src/GetMultipleOptions.ts index 5f03a0ee3e..1b1b0180c6 100644 --- a/packages/parameters/src/GetMultipleOptions.ts +++ b/packages/parameters/src/GetMultipleOptions.ts @@ -1,6 +1,11 @@ import { DEFAULT_MAX_AGE_SECS } from './constants'; import type { GetMultipleOptionsInterface, TransformOptions } from './types'; +/** + * Options for the `getMultiple` method. + * + * It merges the default options with the provided options. + */ class GetMultipleOptions implements GetMultipleOptionsInterface { public forceFetch: boolean = false; public maxAge: number = DEFAULT_MAX_AGE_SECS; diff --git a/packages/parameters/src/GetOptions.ts b/packages/parameters/src/GetOptions.ts index 807962a5aa..254412f127 100644 --- a/packages/parameters/src/GetOptions.ts +++ b/packages/parameters/src/GetOptions.ts @@ -1,6 +1,11 @@ import { DEFAULT_MAX_AGE_SECS } from './constants'; import type { GetOptionsInterface, TransformOptions } from './types'; +/** + * Options for the `get` method. + * + * It merges the default options with the provided options. + */ class GetOptions implements GetOptionsInterface { public forceFetch: boolean = false; public maxAge: number = DEFAULT_MAX_AGE_SECS; diff --git a/packages/parameters/src/appconfig/AppConfigProvider.ts b/packages/parameters/src/appconfig/AppConfigProvider.ts index 9e9e2b0152..84a83cc68d 100644 --- a/packages/parameters/src/appconfig/AppConfigProvider.ts +++ b/packages/parameters/src/appconfig/AppConfigProvider.ts @@ -10,6 +10,159 @@ import type { AppConfigGetOptionsInterface, } from '../types/AppConfigProvider'; +/** + * ## Intro + * The Parameters utility provides an AppConfigProvider that allows to retrieve configuration profiles from AWS AppConfig. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-appconfigdata + * ``` + * + * ## Basic usage + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a configuration profile + * const encodedConfig = await configProvider.get('my-config'); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * If you want to retrieve configs without customizing the provider, you can use the {@link getAppConfig} function instead. + * + * ## Advanced usage + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a configuration profile and cache it for 10 seconds + * const encodedConfig = await configProvider.get('my-config', { maxAge: 10 }); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a config and always fetch the latest value + * const config = await configProvider.get('my-config', { forceFetch: true }); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * ### Transformations + * + * For configurations stored as freeform JSON, Freature Flag, you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a JSON config or Feature Flag and parse it as JSON + * const config = await configProvider.get('my-config', { transform: 'json' }); + * }; + * ``` + * + * For configurations that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return a decoded string. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a base64-encoded string and decode it + * const config = await configProvider.get('my-config', { transform: 'binary' }); + * }; + * ``` + * + * ### Extra SDK options + * + * When retrieving a configuration profile, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a config and pass extra options to the AWS SDK v3 for JavaScript client + * const config = await configProvider.get('my-config', { + * sdkOptions: { + * RequiredMinimumPollIntervalInSeconds: 60, + * }, + * }); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript AppConfigData client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-appconfigdata/interfaces/startconfigurationsessioncommandinput.html). + * + * ### Customize AWS SDK v3 for JavaScript client + * + * By default, the provider will create a new AppConfigData client using the default configuration. + * + * You can customize the client by passing a custom configuration object to the provider. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider({ + * clientConfig: { region: 'eu-west-1' }, + * }); + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript AppConfig Data client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-appconfigdata/interfaces/appconfigdataclientconfig.html). + * + * Otherwise, if you want to use a custom client altogether, you can pass it to the provider. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * import { AppConfigDataClient } from '@aws-sdk/client-appconfigdata'; + * + * const client = new AppConfigDataClient({ region: 'eu-west-1' }); + * const configProvider = new AppConfigProvider({ + * awsSdkV3Client: client, + * }); + * ``` + * + * This object must be an instance of the [AWS SDK v3 for JavaScript AppConfig Data client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-appconfigdata/classes/appconfigdataclient.html). + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + */ class AppConfigProvider extends BaseProvider { public client: AppConfigDataClient; protected configurationTokenStore: Map = new Map(); @@ -17,9 +170,9 @@ class AppConfigProvider extends BaseProvider { private environment: string; /** - * It initializes the AppConfigProvider class'. + * It initializes the AppConfigProvider class. * * - * @param {AppConfigProviderOptions} options + * @param {AppConfigProviderOptions} options - The configuration object. */ public constructor(options: AppConfigProviderOptions) { super(); @@ -44,7 +197,32 @@ class AppConfigProvider extends BaseProvider { } /** - * Retrieve a configuration from AWS App config. + * Retrieve a configuration profile from AWS AppConfig. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a configuration profile + * const encodedConfig = await configProvider.get('my-config'); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * You can customize the retrieval of the configuration profile by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * + * For usage examples check {@link AppConfigProvider}. + * + * @param {string} name - The name of the configuration profile or its ID + * @param {GetAppConfigCombinedInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ */ public async get( name: string, @@ -54,7 +232,7 @@ class AppConfigProvider extends BaseProvider { } /** - * Retrieving multiple configurations is not supported by AWS App Config Provider. + * Retrieving multiple configurations is not supported by AWS AppConfig. */ public async getMultiple( path: string, @@ -64,11 +242,10 @@ class AppConfigProvider extends BaseProvider { } /** - * Retrieve a configuration from AWS App config. + * Retrieve a configuration from AWS AppConfig. * - * @param {string} name - Name of the configuration + * @param {string} name - Name of the configuration or its ID * @param {AppConfigGetOptionsInterface} options - SDK options to propagate to `StartConfigurationSession` API call - * @returns {Promise} */ protected async _get( name: string, @@ -80,7 +257,6 @@ class AppConfigProvider extends BaseProvider { * First we start the session and after that we retrieve the configuration * We need to store { name: token } pairs to use in the next execution **/ - if (!this.configurationTokenStore.has(name)) { const sessionOptions: StartConfigurationSessionCommandInput = { @@ -117,7 +293,7 @@ class AppConfigProvider extends BaseProvider { } /** - * Retrieving multiple configurations is not supported by AWS App Config Provider API. + * Retrieving multiple configurations is not supported by AWS AppConfig. * * @throws Not Implemented Error. */ @@ -125,11 +301,7 @@ class AppConfigProvider extends BaseProvider { _path: string, _sdkOptions?: unknown ): Promise> { - return this._notImplementedError(); - } - - private _notImplementedError(): never { - throw new Error('Not Implemented'); + throw new Error('Method not implemented.'); } } diff --git a/packages/parameters/src/appconfig/getAppConfig.ts b/packages/parameters/src/appconfig/getAppConfig.ts index ca336ea777..7613e0d942 100644 --- a/packages/parameters/src/appconfig/getAppConfig.ts +++ b/packages/parameters/src/appconfig/getAppConfig.ts @@ -2,11 +2,120 @@ import { AppConfigProvider, DEFAULT_PROVIDERS } from './AppConfigProvider'; import type { GetAppConfigCombinedInterface } from '../types/AppConfigProvider'; /** - * Gets the AppConfig data for the specified name. + * ## Intro + * The Parameters utility provides an AppConfigProvider that allows to retrieve configuration profiles from AWS AppConfig. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-appconfigdata + * ``` * - * @param {string} name - The configuration profile ID or the configuration profile name. - * @param {GetAppConfigCombinedInterface} options - Options for the AppConfigProvider and the get method. - * @returns {Promise>} A promise that resolves to the AppConfig data or undefined if not found. + * ## Basic usage + * + * @example + * ```typescript + * import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig'; + * + * export const handler = async (): Promise => { + * // Retrieve a configuration profile + * const encodedConfig = await getAppConfig('my-config'); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * ## Advanced usage + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig'; + * + * export const handler = async (): Promise => { + * // Retrieve a configuration profile and cache it for 10 seconds + * const encodedConfig = await getAppConfig('my-config'); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig'; + * + * export const handler = async (): Promise => { + * // Retrieve a config and always fetch the latest value + * const config = await getAppConfig('my-config', { forceFetch: true }); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * ### Transformations + * + * For configurations stored as freeform JSON, Freature Flag, you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. + * + * @example + * ```typescript + * import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig'; + * + * export const handler = async (): Promise => { + * // Retrieve a JSON config or Feature Flag and parse it as JSON + * const config = await getAppConfig('my-config', { transform: 'json' }); + * }; + * ``` + * + * For configurations that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return a decoded string. + * + * @example + * ```typescript + * import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig'; + * + * export const handler = async (): Promise => { + * // Retrieve a base64-encoded string and decode it + * const config = await getAppConfig('my-config', { transform: 'binary' }); + * }; + * ``` + * + * ### Extra SDK options + * + * When retrieving a configuration profile, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig'; + * + * export const handler = async (): Promise => { + * // Retrieve a config and pass extra options to the AWS SDK v3 for JavaScript client + * const config = await getAppConfig('my-config', { + * sdkOptions: { + * RequiredMinimumPollIntervalInSeconds: 60, + * }, + * }); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript AppConfigData client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-appconfigdata/interfaces/startconfigurationsessioncommandinput.html). + * + * ### Built-in provider class + * + * For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link AppConfigProvider} class. + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + * + * @param {string} name - The name of the configuration profile or its ID + * @param {GetAppConfigCombinedInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ */ const getAppConfig = ( name: string, diff --git a/packages/parameters/src/docs.ts b/packages/parameters/src/docs.ts new file mode 100644 index 0000000000..028b2bbc6b --- /dev/null +++ b/packages/parameters/src/docs.ts @@ -0,0 +1,4 @@ +export * from './appconfig'; +export * from './ssm'; +export * from './secrets'; +export * from './dynamodb'; \ No newline at end of file diff --git a/packages/parameters/src/dynamodb/DynamoDBProvider.ts b/packages/parameters/src/dynamodb/DynamoDBProvider.ts index 58f0f2456b..d178542894 100644 --- a/packages/parameters/src/dynamodb/DynamoDBProvider.ts +++ b/packages/parameters/src/dynamodb/DynamoDBProvider.ts @@ -9,6 +9,226 @@ import type { GetItemCommandInput, QueryCommandInput } from '@aws-sdk/client-dyn import { marshall, unmarshall } from '@aws-sdk/util-dynamodb'; import type { PaginationConfiguration } from '@aws-sdk/types'; +/** + * ## Intro + * The Parameters utility provides a DynamoDBProvider that allows to retrieve values from Amazon DynamoDB. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-dynamodb @aws-sdk/util-dynamodb + * ``` + * + * ## Basic usage + * + * Retrieve a value from DynamoDB: + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a value from DynamoDB + * const value = await tableProvider.get('my-value-key'); + * }; + * ``` + * + * You can also retrieve multiple values at once: + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve multiple values from DynamoDB + * const values = await tableProvider.getMultiple('my-values-path'); + * }; + * + * ## Advanced usage + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a value and cache it for 10 seconds + * const value = await tableProvider.get('my-value-key', { maxAge: 10 }); + * // Retrieve multiple values and cache them for 20 seconds + * const values = await tableProvider.getMultiple('my-values-path', { maxAge: 20 }); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a value and skip cache + * const value = await tableProvider.get('my-value-key', { forceFetch: true }); + * // Retrieve multiple values and skip cache + * const values = await tableProvider.getMultiple('my-values-path', { forceFetch: true }); + * }; + * ``` + * + * ### Transformations + * + * For values stored as JSON you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a value and parse it as JSON + * const value = await tableProvider.get('my-value-key', { transform: 'json' }); + * // Retrieve multiple values and parse them as JSON + * const values = await tableProvider.getMultiple('my-values-path', { transform: 'json' }); + * }; + * ``` + * + * For values that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return a decoded string. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a base64-encoded string and decode it + * const value = await tableProvider.get('my-value-key', { transform: 'binary' }); + * // Retrieve multiple base64-encoded strings and decode them + * const values = await tableProvider.getMultiple('my-values-path', { transform: 'binary' }); + * }; + * ``` + * + * When retrieving multiple values, you can also use the `transform` argument set to `auto` to let the provider automatically detect the type of transformation to apply. + * The provider will use the suffix of the sort key (`sk`) to determine the transformation to apply. For example, if the sort key is `my-value-key.json`, the provider will + * automatically parse the value as JSON. Likewise, if the sort key is `my-value-key.binary`, the provider will automatically decode the value as base64-encoded binary data. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve multiple values and automatically detect the transformation to apply + * const values = await tableProvider.getMultiple('my-values-path', { transform: 'auto' }); + * }; + * ``` + * + * ### Custom key names + * + * By default, the provider will use the following key names: `id` for the partition key, `sk` for the sort key, and `value` for the value. + * You can adjust the key names by using the `keyAttr`, `sortAttr`, and `valueAttr` parameters. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * keyAttr: 'key', + * sortAttr: 'sort', + * valueAttr: 'val', + * }); + * ``` + * + * ### Extra SDK options + * + * When retrieving values, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a value and pass extra options to the AWS SDK v3 for JavaScript client + * const value = await tableProvider.get('my-value-key', { + * sdkOptions: { + * ConsistentRead: true, + * }, + * }); + * }; + * ``` + * + * The objects accept the same options as respectively the [AWS SDK v3 for JavaScript PutItem command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-dynamodb/classes/putitemcommand.html) and the [AWS SDK v3 for JavaScript DynamoDB client Query command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-dynamodb/classes/querycommand.html). + * + * ### Customize AWS SDK v3 for JavaScript client + * + * By default, the provider will create a new DynamoDB client using the default configuration. + * + * You can customize the client by passing a custom configuration object to the provider. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * clientConfig: { region: 'eu-west-1' }, + * }); + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript DynamoDB client constructor](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-dynamodb/classes/dynamodbclient.html). + * + * Otherwise, if you want to use a custom client altogether, you can pass it to the provider. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; + * + * const client = new DynamoDBClient({ region: 'eu-west-1' }); + * const tableProvider = new DynamoDBProvider({ + * awsSdkV3Client: client, + * }); + * ``` + * + * This object must be an instance of the [AWS SDK v3 for JavaScript DynamoDB client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-dynamodb/classes/dynamodbclient.html). + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + */ class DynamoDBProvider extends BaseProvider { public client: DynamoDBClient; protected keyAttr: string = 'id'; @@ -16,6 +236,11 @@ class DynamoDBProvider extends BaseProvider { protected tableName: string; protected valueAttr: string = 'value'; + /** + * It initializes the DynamoDBProvider class. + * + * @param {DynamoDBProviderOptions} config - The configuration object. + */ public constructor(config: DynamoDBProviderOptions) { super(); @@ -36,6 +261,35 @@ class DynamoDBProvider extends BaseProvider { if (config.valueAttr) this.valueAttr = config.valueAttr; } + /** + * Retrieve a value from Amazon DynamoDB. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a single value + * const value = await tableProvider.get('my-value-key'); + * }; + * ``` + * + * You can customize the retrieval of the value by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * + * For usage examples check {@link DynamoDBProvider}. + * + * @param {string} name - The name of the value to retrieve (i.e. the partition key) + * @param {DynamoDBGetOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ public async get( name: string, options?: DynamoDBGetOptionsInterface @@ -43,6 +297,36 @@ class DynamoDBProvider extends BaseProvider { return super.get(name, options) as Promise>; } + /** + * Retrieve multiple values from Amazon DynamoDB. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve multiple values + * const values = await tableProvider.getMultiple('my-values-path'); + * }; + * ``` + * + * You can customize the retrieval of the values by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `throwOnTransformError` - Whether to throw an error if the transform fails (default: `true`) + * + * For usage examples check {@link DynamoDBProvider}. + * + * @param {string} path - The path of the values to retrieve (i.e. the partition key) + * @param {DynamoDBGetMultipleOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ public async getMultiple( path: string, options?: DynamoDBGetMultipleOptionsInterface @@ -50,6 +334,12 @@ class DynamoDBProvider extends BaseProvider { return super.getMultiple(path, options); } + /** + * Retrieve an item from Amazon DynamoDB. + * + * @param {string} name - Key of the item to retrieve (i.e. the partition key) + * @param {DynamoDBGetOptionsInterface} options - Options to customize the retrieval + */ protected async _get( name: string, options?: DynamoDBGetOptionsInterface @@ -68,6 +358,12 @@ class DynamoDBProvider extends BaseProvider { return result.Item ? unmarshall(result.Item)[this.valueAttr] : undefined; } + /** + * Retrieve multiple items from Amazon DynamoDB. + * + * @param {string} path - The path of the values to retrieve (i.e. the partition key) + * @param {DynamoDBGetMultipleOptionsInterface} options - Options to customize the retrieval + */ protected async _getMultiple( path: string, options?: DynamoDBGetMultipleOptionsInterface diff --git a/packages/parameters/src/secrets/SecretsProvider.ts b/packages/parameters/src/secrets/SecretsProvider.ts index 12a6703783..c8d1e56b77 100644 --- a/packages/parameters/src/secrets/SecretsProvider.ts +++ b/packages/parameters/src/secrets/SecretsProvider.ts @@ -9,9 +9,154 @@ import type { SecretsGetOptionsInterface } from '../types/SecretsProvider'; +/** + * ## Intro + * The Parameters utility provides a SecretsProvider that allows to retrieve secrets from AWS Secrets Manager. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for Secrets Manager: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-secrets-manager + * ``` + * + * ## Basic usage + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a secret + * const secret = await secretsProvider.get('my-secret'); + * }; + * ``` + * + * If you want to retrieve secrets without customizing the provider, you can use the {@link getSecret} function instead. + * + * ## Advanced usage + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a secret and cache it for 10 seconds + * const secret = await secretsProvider.get('my-secret', { maxAge: 10 }); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a secret and always fetch the latest value + * const secret = await secretsProvider.get('my-secret', { forceFetch: true }); + * }; + * ``` + * + * ### Transformations + * + * For parameters stored in JSON or Base64 format, you can use the transform argument for deserialization. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a secret and parse it as JSON + * const secret = await secretsProvider.get('my-secret', { transform: 'json' }); + * }; + * ``` + * + * ### Extra SDK options + * + * When retrieving a secret, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a secret and pass extra options to the AWS SDK v3 for JavaScript client + * const secret = await secretsProvider.get('my-secret', { + * sdkOptions: { + * VersionId: 1, + * }, + * }); + * }; + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript Secrets Manager client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-secrets-manager/interfaces/getsecretvaluecommandinput.html). + * + * ### Customize AWS SDK v3 for JavaScript client + * + * By default, the provider will create a new Secrets Manager client using the default configuration. + * + * You can customize the client by passing a custom configuration object to the provider. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider({ + * clientConfig: { region: 'eu-west-1' }, + * }); + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript Secrets Manager client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-secrets-manager/interfaces/secretsmanagerclientconfig.html). + * + * Otherwise, if you want to use a custom client altogether, you can pass it to the provider. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * import { SecretsManagerClient } from '@aws-sdk/client-secrets-manager'; + * + * const client = new SecretsManagerClient({ region: 'eu-west-1' }); + * const secretsProvider = new SecretsProvider({ + * awsSdkV3Client: client, + * }); + * ``` + * + * This object must be an instance of the [AWS SDK v3 for JavaScript Secrets Manager client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-secrets-manager/classes/secretsmanagerclient.html). + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + * + * @class + * @implements {BaseProvider} + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ class SecretsProvider extends BaseProvider { public client: SecretsManagerClient; + /** + * It initializes the SecretsProvider class. + * + * @param {SecretsProviderOptions} config - The configuration object. + */ public constructor (config?: SecretsProviderOptions) { super(); @@ -28,6 +173,33 @@ class SecretsProvider extends BaseProvider { } + /** + * Retrieve a secret from AWS Secrets Manager. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a secret + * const secret = await secretsProvider.get('my-secret'); + * }; + * ``` + * + * You can customize the retrieval of the secret by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * + * For usage examples check {@link SecretsProvider}. + * + * @param {string} name - The name of the secret + * @param {SecretsGetOptionsInterface} options - Options to customize the retrieval of the secret + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ public async get( name: string, options?: SecretsGetOptionsInterface @@ -45,6 +217,12 @@ class SecretsProvider extends BaseProvider { return super.getMultiple(path); } + /** + * Retrieve a configuration from AWS AppConfig. + * + * @param {string} name - Name of the configuration or its ID + * @param {SecretsGetOptionsInterface} options - SDK options to propagate to the AWS SDK v3 for JavaScript client + */ protected async _get( name: string, options?: SecretsGetOptionsInterface @@ -63,6 +241,8 @@ class SecretsProvider extends BaseProvider { /** * Retrieving multiple parameter values is not supported with AWS Secrets Manager. + * + * @throws Not Implemented Error. */ protected async _getMultiple( _path: string, diff --git a/packages/parameters/src/secrets/getSecret.ts b/packages/parameters/src/secrets/getSecret.ts index 92f123e6e5..a6b39b3229 100644 --- a/packages/parameters/src/secrets/getSecret.ts +++ b/packages/parameters/src/secrets/getSecret.ts @@ -2,6 +2,107 @@ import { DEFAULT_PROVIDERS } from '../BaseProvider'; import { SecretsProvider } from './SecretsProvider'; import type { SecretsGetOptionsInterface } from '../types/SecretsProvider'; +/** + * ## Intro + * The Parameters utility provides a SecretsProvider that allows to retrieve secrets from AWS Secrets Manager. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for Secrets Manager: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-secrets-manager + * ``` + * + * ## Basic usage + * + * @example + * ```typescript + * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; + * + * export const handler = async (): Promise => { + * // Retrieve a secret + * const secret = await getSecret('my-secret'); + * }; + * ``` + * + * ## Advanced usage + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; + * + * export const handler = async (): Promise => { + * // Retrieve a secret and cache it for 10 seconds + * const secret = await getSecret('my-secret', { maxAge: 10 }); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; + * + * export const handler = async (): Promise => { + * // Retrieve a secret and always fetch the latest value + * const secret = await getSecret('my-secret', { forceFetch: true }); + * }; + * ``` + * + * ### Transformations + * + * For parameters stored as JSON or base64-encoded strings, you can use the transform argument set to `json` or `binary` for deserialization. + * + * @example + * ```typescript + * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; + * + * export const handler = async (): Promise => { + * // Retrieve a secret and parse it as JSON + * const secret = await getSecret('my-secret', { transform: 'json' }); + * }; + * ``` + * + * ### Extra SDK options + * + * When retrieving a secret, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; + * + * export const handler = async (): Promise => { + * // Retrieve a secret and pass extra options to the AWS SDK v3 for JavaScript client + * const secret = await getSecret('my-secret', { + * sdkOptions: { + * VersionId: 1, + * }, + * }); + * }; + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript Secrets Manager client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-secrets-manager/interfaces/getsecretvaluecommandinput.html). + * + * ### Built-in provider class + * + * For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link SecretsProvider} class. + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + * + * + * @param {string} name - The name of the secret to retrieve + * @param {SecretsGetOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ const getSecret = async (name: string, options?: SecretsGetOptionsInterface): Promise> => { if (!DEFAULT_PROVIDERS.hasOwnProperty('secrets')) { DEFAULT_PROVIDERS.secrets = new SecretsProvider(); diff --git a/packages/parameters/src/ssm/SSMProvider.ts b/packages/parameters/src/ssm/SSMProvider.ts index dd45070162..28818a8aaa 100644 --- a/packages/parameters/src/ssm/SSMProvider.ts +++ b/packages/parameters/src/ssm/SSMProvider.ts @@ -24,11 +24,254 @@ import type { } from '../types/SSMProvider'; import type { PaginationConfiguration } from '@aws-sdk/types'; +/** + * ## Intro + * The Parameters utility provides a SSMProvider that allows to retrieve parameters from AWS Systems Manager. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm + * ``` + * + * ## Basic usage + * + * Retrieve a parameter from SSM: + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter from SSM + * const parameter = await parametersProvider.get('/my-parameter'); + * }; + * ``` + * + * If you want to retrieve a parameter without customizing the provider, you can use the {@link getParameter} function instead. + * + * You can also retrieve parameters at once. If you want to get multiple parameters under the same path, you can use the `getMultiple` method. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve multiple parameters by path from SSM + * const parameters = await parametersProvider.getMultiple('/my-parameters-path'); + * }; + * + * If you don't need to customize the provider, you can also use the {@link getParameters} function instead. + * + * If instead you want to retrieve multiple parameters by name, you can use the `getParametersByName` method. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve multiple parameters by name from SSM + * const parameters = await parametersProvider.getParametersByName({ + * '/my-parameter-1': {}, // Use default options + * '/my-parameter-2': { transform: 'json' }, // Parse the value as JSON + * }); + * }; + * ``` + * + * If you don't need to customize the provider, you can also use the {@link getParametersByName} function instead. + * + * ## Advanced usage + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and cache it for 10 seconds + * const parameter = await parametersProvider.get('/my-parameter', { maxAge: 10 }); + * // Retrieve multiple parameters by path and cache them for 20 seconds + * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { maxAge: 20 }); + * }; + * ``` + * + * When using the `getParametersByName` method, you can set a different `maxAge` for each parameter or set a default `maxAge` for all parameters. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve multiple parameters by name and cache them individually + * const parameters = await parametersProvider.getParametersByName({ + * '/my-parameter-1': { maxAge: 10 }, // Cache for 10 seconds + * '/my-parameter-2': { maxAge: 20 }, // Cache for 20 seconds + * }); + * // Retrieve multiple parameters by name and cache them all for 20 seconds + * const parameters = await parametersProvider.getParametersByName({ + * '/my-parameter-1': {}, + * '/my-parameter-2': {}, + * }, { maxAge: 20 }); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and skip cache + * const parameter = await parametersProvider.get('/my-parameter', { forceFetch: true }); + * // Retrieve multiple parameters and skip cache + * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { forceFetch: true }); + * }; + * ``` + * + * Likewise, you can use the `forceFetch` parameter with the `getParametersByName` method both for individual parameters and for all parameters. + * + * ### Decryption + * + * If you want to retrieve a parameter that is encrypted, you can use the `decrypt` parameter. This parameter is compatible with `get`, `getMultiple` and `getParametersByName`. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and decrypt it + * const parameter = await parametersProvider.get('/my-parameter', { decrypt: true }); + * // Retrieve multiple parameters and decrypt them + * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { decrypt: true }); + * }; + * ``` + * + * ### Transformations + * + * For parameters stored as JSON you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and parse it as JSON + * const parameter = await parametersProvider.get('/my-parameter', { transform: 'json' }); + * // Retrieve multiple parameters and parse them as JSON + * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { transform: 'json' }); + * }; + * ``` + * + * For parameters that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return a decoded string. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a base64-encoded string and decode it + * const parameter = await parametersProvider.get('/my-parameter', { transform: 'binary' }); + * // Retrieve multiple base64-encoded strings and decode them + * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { transform: 'binary' }); + * }; + * ``` + * + * Both type of transformations are compatible also with the `getParametersByName` method. + * + * ### Extra SDK options + * + * When retrieving parameters, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and pass extra options to the AWS SDK v3 for JavaScript client + * const parameter = await parametersProvider.get('/my-parameter', { + * sdkOptions: { + * WithDecryption: true, + * }, + * }); + * }; + * ``` + * + * The objects accept the same options as respectively the [AWS SDK v3 for JavaScript GetParameter command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/classes/getparametercommand.html) and the [AWS SDK v3 for JavaScript GetParametersByPath command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/classes/getparametersbypathcommand.html). + * + * ### Customize AWS SDK v3 for JavaScript client + * + * By default, the provider will create a new SSM client using the default configuration. + * + * You can customize the client by passing a custom configuration object to the provider. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider({ + * clientConfig: { region: 'eu-west-1' }, + * }); + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript SSM client constructor](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/classes/ssmclient.html#constructor). + * + * Otherwise, if you want to use a custom client altogether, you can pass it to the provider. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * import { SSMClient } from '@aws-sdk/client-ssm'; + * + * const client = new SSMClient({ region: 'eu-west-1' }); + * const parametersProvider = new SSMProvider({ + * awsSdkV3Client: client, + * }); + * ``` + * + * This object must be an instance of the [AWS SDK v3 for JavaScript SSM client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/classes/ssmclient.html). + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + */ class SSMProvider extends BaseProvider { public client: SSMClient; protected errorsKey = '_errors'; protected maxGetParametersItems = 10; + /** + * It initializes the SSMProvider class. + * + * @param {SSMProviderOptions} config - The configuration object. + */ public constructor(config?: SSMProviderOptions) { super(); @@ -44,6 +287,34 @@ class SSMProvider extends BaseProvider { } } + /** + * Retrieve a value from AWS Systems Manager. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter from SSM + * const parameter = await parametersProvider.get('/my-parameter'); + * }; + * ``` + * + * You can customize the retrieval of the value by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `decrypt` - Whether to decrypt the value before returning it. + * + * For usage examples check {@link SSMProvider}. + * + * @param {string} name - The name of the value to retrieve (i.e. the partition key) + * @param {SSMGetOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ public async get( name: string, options?: SSMGetOptionsInterface | undefined @@ -51,6 +322,36 @@ class SSMProvider extends BaseProvider { return super.get(name, options) as Promise | undefined>; } + /** + * Retrieve multiple values from AWS Systems Manager. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve multiple parameters from SSM + * const parameters = await parametersProvider.getMultiple('/my-parameters-path'); + * }; + * ``` + * + * You can customize the retrieval of the values by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `throwOnTransformError` - Whether to throw an error if the transform fails (default: `true`) + * * `decrypt` - Whether to decrypt the value before returning it. + * * `recursive` - Whether to recursively retrieve all parameters under the given path (default: `false`) + * + * For usage examples check {@link SSMProvider}. + * + * @param {string} path - The path of the parameters to retrieve + * @param {SSMGetMultipleOptionsInterface} options - Options to configure the retrieval + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ public async getMultiple( path: string, options?: SSMGetMultipleOptionsInterface | undefined @@ -59,14 +360,36 @@ class SSMProvider extends BaseProvider { } /** - * Retrieve multiple parameter values by name from SSM or cache. - * - * `ThrowOnError` decides whether to throw an error if a parameter is not found: + * Retrieve multiple parameters by name from AWS Systems Manager. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve multiple parameters by name from SSM + * const parameters = await parametersProvider.getParametersByName({ + * '/my-parameter-1': {}, // Use default options + * '/my-parameter-2': { transform: 'json' }, // Parse the value as JSON + * }); + * }; + * ``` + * You can customize the retrieval of the values by passing options to **both the function and the parameter**: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `throwOnTransformError` - Whether to throw an error if the transform fails (default: `true`) + * * `decrypt` - Whether to decrypt the value before returning it + * + * `throwOnError` decides whether to throw an error if a parameter is not found: * - A) Default fail-fast behavior: Throws a `GetParameterError` error upon any failure. * - B) Gracefully aggregate all parameters that failed under "_errors" key. - * + * * It transparently uses GetParameter and/or GetParameters depending on decryption requirements. - * + * * ```sh * ┌────────────────────────┐ * ┌───▶ Decrypt entire batch │─────┐ @@ -81,9 +404,10 @@ class SSMProvider extends BaseProvider { * └────────────────────────┘ │ GetParameters API │ * └────────────────────┘ * ``` - * - * @param {Record[]} parameters - List of parameter names, and any optional overrides - * + * + * @param {Record} parameters - Object containing parameter names and any optional overrides + * @param {SSMGetParametersByNameOptionsInterface} options - Options to configure the retrieval + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ */ public async getParametersByName( parameters: Record, @@ -117,7 +441,7 @@ class SSMProvider extends BaseProvider { response: batchResponse, errors: batchErrors } = await this.getParametersBatchByName(parametersToFetchInBatch, configs.throwOnError, false); - + response = { ...decryptResponse, ...batchResponse }; // Fail-fast disabled, let's aggregate errors under "_errors" key so they can handle gracefully if (!configs.throwOnError) { @@ -128,7 +452,7 @@ class SSMProvider extends BaseProvider { response: batchResponse, errors: batchErrors } = await this.getParametersBatchByName(parametersToDecrypt, configs.throwOnError, true); - + response = batchResponse; // Fail-fast disabled, let's aggregate errors under "_errors" key so they can handle gracefully if (!configs.throwOnError) { @@ -139,6 +463,12 @@ class SSMProvider extends BaseProvider { return response; } + /** + * Retrieve a parameter from AWS Systems Manager. + * + * @param {string} name - Name of the parameter to retrieve + * @param {SSMGetOptionsInterface} options - Options to customize the retrieval + */ protected async _get( name: string, options?: SSMGetOptionsInterface @@ -154,6 +484,12 @@ class SSMProvider extends BaseProvider { return result.Parameter?.Value; } + /** + * Retrieve multiple items from AWS Systems Manager. + * + * @param {string} path - The path of the parameters to retrieve + * @param {SSMGetMultipleOptionsInterface} options - Options to configure the provider + */ protected async _getMultiple( path: string, options?: SSMGetMultipleOptionsInterface @@ -171,7 +507,7 @@ class SSMProvider extends BaseProvider { options.recursive : sdkOptions.Recursive; paginationOptions.pageSize = sdkOptions.MaxResults !== undefined ? sdkOptions.MaxResults : undefined; - + const parameters: Record = {}; for await (const page of paginateGetParametersByPath(paginationOptions, sdkOptions)) { for (const parameter of page.Parameters || []) { @@ -179,9 +515,9 @@ class SSMProvider extends BaseProvider { * Standardize the parameter name * * The parameter name returned by SSM will contain the full path. - * However, for readability, we should return only the part after the path. - **/ - + * However, for readability, we should return only the part after the path. + **/ + // If the parameter is present in the response, then it has a Name // eslint-disable-next-line @typescript-eslint/no-non-null-assertion let name = parameter.Name!; @@ -196,6 +532,13 @@ class SSMProvider extends BaseProvider { return parameters; } + /** + * Retrieve multiple items by name from AWS Systems Manager. + * + * @param {Record} parameters - An object of parameter names and their options + * @param {throwOnError} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully + * @param {boolean} decrypt - Whether to decrypt the parameters or not + */ protected async _getParametersByName( parameters: Record, throwOnError: boolean, @@ -207,7 +550,7 @@ class SSMProvider extends BaseProvider { if (decrypt) { sdkOptions.WithDecryption = true; } - + const result = await this.client.send(new GetParametersCommand(sdkOptions)); const errors = SSMProvider.handleAnyInvalidGetParameterErrors(result, throwOnError); const response = this.transformAndCacheGetParametersResponse( @@ -224,6 +567,10 @@ class SSMProvider extends BaseProvider { /** * Slice batch and fetch parameters using GetPrameters API by max permissible batch size + * + * @param {Record} parameters - An object of parameter names and their options + * @param {throwOnError} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully + * @param {boolean} decrypt - Whether to decrypt the parameters or not */ protected async getParametersBatchByName( parameters: Record, @@ -260,6 +607,8 @@ class SSMProvider extends BaseProvider { /** * Fetch each parameter from batch that hasn't expired from cache + * + * @param {Record} parameters - An object of parameter names and their options */ protected async getParametersByNameFromCache( parameters: Record @@ -284,6 +633,13 @@ class SSMProvider extends BaseProvider { }; } + /** + * Slice object into chunks of max permissible batch size and fetch parameters + * + * @param {Record} parameters - An object of parameter names and their options + * @param {boolean} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully + * @param {boolean} decrypt - Whether to decrypt the parameters or not + */ protected async getParametersByNameInChunks( parameters: Record, throwOnError: boolean, @@ -291,7 +647,7 @@ class SSMProvider extends BaseProvider { ): Promise { let response: Record = {}; let errors: string[] = []; - + // Slice object into chunks of max permissible batch size const chunks = Object.entries(parameters).reduce(( acc, @@ -313,7 +669,7 @@ class SSMProvider extends BaseProvider { response: chunkResponse, errors: chunkErrors } = await this._getParametersByName(chunk, throwOnError, decrypt); - + response = { ...response, ...chunkResponse }; errors = [ ...errors, ...chunkErrors ]; } @@ -324,6 +680,12 @@ class SSMProvider extends BaseProvider { }; } + /** + * Fetch parameters by name while also decrypting them + * + * @param {Record} parameters - An object of parameter names and their options + * @param {boolean} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully + */ protected async getParametersByNameWithDecryptOption( parameters: Record, throwOnError: boolean @@ -351,6 +713,9 @@ class SSMProvider extends BaseProvider { /** * Handle any invalid parameters returned by GetParameters API * GetParameters is non-atomic. Failures don't always reflect in exceptions so we need to collect. + * + * @param {GetParametersCommandOutput} result - The result of the GetParameters API call + * @param {boolean} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully */ protected static handleAnyInvalidGetParameterErrors( result: GetParametersCommandOutput, @@ -371,6 +736,9 @@ class SSMProvider extends BaseProvider { /** * Split parameters that can be fetched by GetParameters vs GetParameter. + * + * @param {Record} parameters - An object of parameter names and their options + * @param {SSMGetParametersByNameOptionsInterface} configs - The configs passed down */ protected static splitBatchAndDecryptParameters( parameters: Record, @@ -387,7 +755,7 @@ class SSMProvider extends BaseProvider { overrides.decrypt : configs.decrypt; overrides.maxAge = overrides.maxAge !== undefined ? overrides.maxAge : configs.maxAge; - + if (overrides.decrypt) { parametersToDecrypt[parameterName] = overrides; } else { @@ -403,10 +771,10 @@ class SSMProvider extends BaseProvider { /** * Throw a GetParameterError if fail-fast is disabled and `_errors` key is in parameters list. - * - * @param {Record} parameters - * @param {string} reservedParameter - * @param {boolean} throwOnError + * + * @param {Record} parameters + * @param {string} reservedParameter + * @param {boolean} throwOnError */ protected static throwIfErrorsKeyIsPresent( parameters: Record, @@ -420,6 +788,13 @@ class SSMProvider extends BaseProvider { } } + /** + * Transform and cache the response from GetParameters API call + * + * @param {GetParametersCommandOutput} response - The response from the GetParameters API call + * @param {Record} parameters - An object of parameter names and their options + * @param {boolean} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully + */ protected transformAndCacheGetParametersResponse( response: GetParametersCommandOutput, parameters: Record, diff --git a/packages/parameters/src/ssm/getParameter.ts b/packages/parameters/src/ssm/getParameter.ts index fd4d8e8e0e..12b09e0c08 100644 --- a/packages/parameters/src/ssm/getParameter.ts +++ b/packages/parameters/src/ssm/getParameter.ts @@ -1,6 +1,141 @@ import { SSMProvider, DEFAULT_PROVIDERS } from './SSMProvider'; import type { SSMGetOptionsInterface } from '../types/SSMProvider'; +/** + * ## Intro + * The Parameters utility provides an SSMProvider that allows to retrieve parameters from AWS Systems Manager. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm + * ``` + * + * ## Basic usage + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a parameter + * const parameter = await getParameter('/my-parameter'); + * }; + * ``` + * + * ## Advanced usage + * + * ### Decryption + * + * If you have encrypted parameters, you can use the `decrypt` option to automatically decrypt them. + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and decrypt it + * const parameter = await getParameter('/my-parameter', { decrypt: true }); + * }; + * ``` + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and cache it for 10 seconds + * const parameter = await getParameter('/my-parameter', { maxAge: 10 }); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and always fetch the latest value + * const parameter = await getParameter('/my-parameter', { forceFetch: true }); + * }; + * ``` + * + * ### Transformations + * + * For parameters stored as JSON you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and parse it as JSON + * const parameter = await getParameter('/my-parameter', { transform: 'json' }); + * }; + * ``` + * + * For parameters that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return a decoded string. + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a base64-encoded string and decode it + * const parameter = await getParameter('/my-parameter', { transform: 'binary' }); + * }; + * ``` + * + * ### Extra SDK options + * + * When retrieving a parameter, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and pass extra options to the AWS SDK v3 for JavaScript client + * const parameter = await getParameter('/my-parameter', { + * sdkOptions: { + * WithDecryption: true, + * }, + * }); + * }; + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript SSM GetParameter command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/interfaces/getparametercommandinput.html). + * + * ### Built-in provider class + * + * For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link SSMProvider} class. + * + * ### Options + * + * * You can customize the retrieval of the value by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `decrypt` - Whether to decrypt the value before returning it. + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + * + * @param {string} name - The name of the parameter to retrieve + * @param {SSMGetOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ const getParameter = ( name: string, options?: SSMGetOptionsInterface diff --git a/packages/parameters/src/ssm/getParameters.ts b/packages/parameters/src/ssm/getParameters.ts index 0283bc0b5e..e93daf1ea8 100644 --- a/packages/parameters/src/ssm/getParameters.ts +++ b/packages/parameters/src/ssm/getParameters.ts @@ -1,6 +1,142 @@ import { SSMProvider, DEFAULT_PROVIDERS } from './SSMProvider'; import type { SSMGetMultipleOptionsInterface } from '../types/SSMProvider'; +/** + * ## Intro + * The Parameters utility provides an SSMProvider that allows to retrieve parameters from AWS Systems Manager. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm + * ``` + * + * ## Basic usage + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters by path + * const parameters = await getParameters('/my-parameters-path'); + * }; + * ``` + * + * ## Advanced usage + * + * ### Decryption + * + * If you have encrypted parameters, you can use the `decrypt` option to automatically decrypt them. + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and decrypt them + * const parameters = await getParameters('/my-parameters-path', { decrypt: true }); + * }; + * ``` + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and cache them for 10 seconds + * const parameters = await getParameters('/my-parameters-path', { maxAge: 10 }); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest values from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and always fetch the latest values + * const parameters = await getParameters('/my-parameters-path', { forceFetch: true }); + * }; + * ``` + * + * ### Transformations + * + * For parameters stored as JSON you can use the transform argument for deserialization. This will return a JavaScript objects instead of a strings. + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and parse them as JSON + * const parameters = await getParameters('/my-parameters-path', { transform: 'json' }); + * }; + * ``` + * + * For parameters that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return decoded strings for each parameter. + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve base64-encoded strings and decode them + * const parameters = await getParameters('/my-parameters-path', { transform: 'binary' }); + * }; + * ``` + * + * ### Extra SDK options + * + * When retrieving a parameter, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and pass extra options to the AWS SDK v3 for JavaScript client + * const parameters = await getParameters('/my-parameters-path', { + * sdkOptions: { + * WithDecryption: true, + * }, + * }); + * }; + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript SSM getParametersByPath command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/interfaces/getParameterssbypathcommandinput.html). + * + * ### Built-in provider class + * + * For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link SSMProvider} class. + * + * ### Options + * + * * You can customize the retrieval of the value by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `decrypt` - Whether to decrypt the value before returning it. + * * `recursive` - Whether to recursively retrieve all parameters within the path. + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + * + * @param {string} path - The path of the parameters to retrieve + * @param {SSMGetMultipleOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ const getParameters = ( path: string, options?: SSMGetMultipleOptionsInterface diff --git a/packages/parameters/src/ssm/getParametersByName.ts b/packages/parameters/src/ssm/getParametersByName.ts index 18d50073b8..5efd333f5f 100644 --- a/packages/parameters/src/ssm/getParametersByName.ts +++ b/packages/parameters/src/ssm/getParametersByName.ts @@ -3,6 +3,163 @@ import type { SSMGetParametersByNameOptionsInterface } from '../types/SSMProvider'; +/** + * ## Intro + * The Parameters utility provides an SSMProvider that allows to retrieve parameters from AWS Systems Manager. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm + * ``` + * + * ## Basic usage + * + * @example + * ```typescript + * import { getParametersByName } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and cache them for 10 seconds + * const parameters = await getParametersByName({ + * '/my-parameter-1': {}, // Use default options + * '/my-parameter-2': { maxAge: 10 }, // Cache for 10 seconds + * }); + * }; + * ``` + * + * ## Advanced usage + * + * ### Decryption + * + * If you have encrypted parameters, you can use the `decrypt` option to automatically decrypt them. + * + * @example + * ```typescript + * import { getParametersByName } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and decrypt them + * const parameters = await getParametersByName({ + * '/my-parameter-1': {}, // Use default options + * '/my-parameter-2': {}, // Use default options + * }, { decrypt: true }); + * }; + * ``` + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { getParametersByName } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and cache them for 10 seconds + * const parameters = await getParametersByName({ + * '/my-parameter-1': {}, // Use default options + * '/my-parameter-2': {}, // Use default options + * }, { maxAge: 10 }); + * }; + * ``` + * + * Alternatively, if you need more granular control over caching each parameter, you can pass it in the options object. + * + * @example + * ```typescript + * import { getParametersByName } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and cache them individually + * const parameters = await getParametersByName({ + * '/my-parameter-1': { maxAge: 10 }, // Cache for 10 seconds + * '/my-parameter-2': { maxAge: 20 }, // Cache for 20 seconds + * }); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest values from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { getParametersByName } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and pass extra options to skip cache + * const parameters = await getParametersByName({ + * '/my-parameter-1': {}, // Use default options + * '/my-parameter-2': {}, // Use default options + * }, { forceFetch: true }); + * }; + * ``` + * + * ### Transformations + * + * For parameters stored as JSON you can use the transform argument for deserialization. This will return a JavaScript objects instead of a strings. + * For parameters that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return decoded strings for each parameter. + * + * @example + * ```typescript + * import { getParametersByName } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and pass extra options to transform them + * const parameters = await getParametersByName({ + * '/my-parameter-1': {}, // Use default options (no transformation) + * '/my-parameter-2': { transform: 'json' }, // Parse the value as JSON + * '/my-parameter-3': { transform: 'binary' }, // Parse the value as base64-encoded binary data + * }); + * }; + * ``` + * + * + * ### Built-in provider class + * + * For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link SSMProvider} class. + * + * ### Options + * + * * You can customize the retrieval of the value by passing options to **both the function and the parameter**: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `decrypt` - Whether to decrypt the value before returning it + * + * `throwOnError` decides whether to throw an error if a parameter is not found: + * - A) Default fail-fast behavior: Throws a `GetParameterError` error upon any failure. + * - B) Gracefully aggregate all parameters that failed under "_errors" key. + * + * It transparently uses GetParameter and/or getParametersByName depending on decryption requirements. + * + * ```sh + * ┌────────────────────────┐ + * ┌───▶ Decrypt entire batch │─────┐ + * │ └────────────────────────┘ │ ┌────────────────────┐ + * │ ├─────▶ getParametersByName API │ + * ┌──────────────────┐ │ ┌────────────────────────┐ │ └────────────────────┘ + * │ Split batch │─── ┼──▶│ No decryption required │─────┘ + * └──────────────────┘ │ └────────────────────────┘ + * │ ┌────────────────────┐ + * │ ┌────────────────────────┐ │ GetParameter API │ + * └──▶│Decrypt some but not all│───────────▶────────────────────┤ + * └────────────────────────┘ │ getParametersByName API │ + * └────────────────────┘ + * ``` + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + * + * @param {Record} parameters - The path of the parameters to retrieve + * @param {SSMGetParametersByNameOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ const getParametersByName = ( parameters: Record, options?: SSMGetParametersByNameOptionsInterface diff --git a/packages/parameters/src/types/AppConfigProvider.ts b/packages/parameters/src/types/AppConfigProvider.ts index 007bca8a50..e69fc256c0 100644 --- a/packages/parameters/src/types/AppConfigProvider.ts +++ b/packages/parameters/src/types/AppConfigProvider.ts @@ -8,9 +8,9 @@ import type { GetOptionsInterface } from 'types/BaseProvider'; /** * Base interface for AppConfigProviderOptions. * - * @interface - * @property {string} environment - The environment ID or the environment name. - * @property {string} [application] - The application ID or the application name. + * @interface + * @property {string} environment - The environment ID or the environment name. + * @property {string} [application] - The application ID or the application name. */ interface AppConfigProviderOptionsBaseInterface { environment: string @@ -20,10 +20,10 @@ interface AppConfigProviderOptionsBaseInterface { /** * Interface for AppConfigProviderOptions with clientConfig property. * - * @interface - * @extends AppConfigProviderOptionsBaseInterface - * @property {AppConfigDataClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. - * @property {never} [awsSdkV3Client] - This property should never be passed. + * @interface + * @extends AppConfigProviderOptionsBaseInterface + * @property {AppConfigDataClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. + * @property {never} [awsSdkV3Client] - This property should never be passed. */ interface AppConfigProviderOptionsWithClientConfig extends AppConfigProviderOptionsBaseInterface { clientConfig?: AppConfigDataClientConfig @@ -59,7 +59,10 @@ type AppConfigProviderOptions = AppConfigProviderOptionsWithClientConfig | AppCo * * @interface AppConfigGetOptionsInterface * @extends {GetOptionsInterface} - * @property {StartConfigurationSessionCommandInput} [sdkOptions] - Required options to start configuration session. + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {StartConfigurationSessionCommandInput} [sdkOptions] - Additional options to pass to the AWS SDK v3 client. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. */ interface AppConfigGetOptionsInterface extends Omit { sdkOptions?: Omit< diff --git a/packages/parameters/src/types/BaseProvider.ts b/packages/parameters/src/types/BaseProvider.ts index 1a0ae3fa9a..c0e5a08c3d 100644 --- a/packages/parameters/src/types/BaseProvider.ts +++ b/packages/parameters/src/types/BaseProvider.ts @@ -1,21 +1,68 @@ +/** + * Type for the transform option. + */ type TransformOptions = 'auto' | 'binary' | 'json'; +/** + * Options for the `get` method. + * + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. Will be applied after the first API call. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {unknown} sdkOptions - Options to pass to the underlying SDK. + * @property {TransformOptions} transform - Transform to be applied, can be 'json', 'binary', or 'auto'. + */ interface GetOptionsInterface { + /** + * Maximum age of the value in the cache, in seconds. + */ maxAge?: number + /** + * Force fetch the value from the parameter store, ignoring the cache. + */ forceFetch?: boolean + /** + * Options to pass to the underlying SDK. + */ sdkOptions?: unknown + /** + * Transform to be applied, can be 'json', 'binary', or 'auto'. + */ transform?: TransformOptions } +/** + * Options for the `getMultiple` method. + * + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. Will be applied after the first API call. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {unknown} sdkOptions - Options to pass to the underlying SDK. + * @property {TransformOptions} transform - Transform to be applied, can be 'json', 'binary', or 'auto'. + * @property {boolean} throwOnTransformError - Whether to throw an error if a value cannot be transformed. + */ interface GetMultipleOptionsInterface extends GetOptionsInterface { + /** + * Whether to throw an error if a value cannot be transformed. + */ throwOnTransformError?: boolean } +/** + * Interface for a value that can expire. + */ interface ExpirableValueInterface { + /** + * Value of the parameter. + */ value: string | Uint8Array | Record + /** + * Expiration timestamp of the value. + */ ttl: number } +/** + * Interface for a parameter store provider. + */ interface BaseProviderInterface { get(name: string, options?: GetOptionsInterface): Promise> getMultiple(path: string, options?: GetMultipleOptionsInterface): Promise> diff --git a/packages/parameters/src/types/DynamoDBProvider.ts b/packages/parameters/src/types/DynamoDBProvider.ts index 140bf50fd2..075f123838 100644 --- a/packages/parameters/src/types/DynamoDBProvider.ts +++ b/packages/parameters/src/types/DynamoDBProvider.ts @@ -1,6 +1,15 @@ import type { GetOptionsInterface, GetMultipleOptionsInterface } from './BaseProvider'; import type { DynamoDBClient, GetItemCommandInput, QueryCommandInput, DynamoDBClientConfig } from '@aws-sdk/client-dynamodb'; +/** + * Base interface for DynamoDBProviderOptions. + * + * @interface + * @property {string} tableName - The DynamoDB table name. + * @property {string} [keyAttr] - The DynamoDB table key attribute name. Defaults to 'id'. + * @property {string} [sortAttr] - The DynamoDB table sort attribute name. Defaults to 'sk'. + * @property {string} [valueAttr] - The DynamoDB table value attribute name. Defaults to 'value'. + */ interface DynamoDBProviderOptionsBaseInterface { tableName: string keyAttr?: string @@ -8,30 +17,70 @@ interface DynamoDBProviderOptionsBaseInterface { valueAttr?: string } +/** + * Interface for DynamoDBProviderOptions with clientConfig property. + * + * @interface + * @extends DynamoDBProviderOptionsBaseInterface + * @property {AppConfigDataClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. + * @property {never} [awsSdkV3Client] - This property should never be passed. + */ interface DynamoDBProviderOptionsWithClientConfig extends DynamoDBProviderOptionsBaseInterface { clientConfig?: DynamoDBClientConfig awsSdkV3Client?: never } +/** + * Interface for DynamoDBProviderOptions with awsSdkV3Client property. + * + * @interface + * @extends DynamoDBProviderOptionsBaseInterface + * @property {AppConfigDataClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during AppConfigProvider class instantiation + * @property {never} [clientConfig] - This property should never be passed. + */ interface DynamoDBProviderOptionsWithClientInstance extends DynamoDBProviderOptionsBaseInterface { awsSdkV3Client?: DynamoDBClient clientConfig?: never } +/** + * Options for the AppConfigProvider class constructor. + * + * @type AppConfigProviderOptions + * @property {string} tableName - The DynamoDB table name. + * @property {string} [keyAttr] - The DynamoDB table key attribute name. Defaults to 'id'. + * @property {string} [sortAttr] - The DynamoDB table sort attribute name. Defaults to 'sk'. + * @property {string} [valueAttr] - The DynamoDB table value attribute name. Defaults to 'value'. + * @property {AppConfigDataClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. Mutually exclusive with awsSdkV3Client. + * @property {AppConfigDataClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during DynamoDBProvider class instantiation. Mutually exclusive with clientConfig. + */ type DynamoDBProviderOptions = DynamoDBProviderOptionsWithClientConfig | DynamoDBProviderOptionsWithClientInstance; /** * Options for the DynamoDBProvider get method. - * + * * @interface DynamoDBGetOptionsInterface * @extends {GetOptionsInterface} - * @property {boolean} decrypt - If true, the parameter will be decrypted. - * @property {Partial} sdkOptions - Options for the AWS SDK. + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {GetItemCommandInput} [sdkOptions] - Additional options to pass to the AWS SDK v3 client. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. */ interface DynamoDBGetOptionsInterface extends GetOptionsInterface { sdkOptions?: Omit, 'Key' | 'TableName' | 'ProjectionExpression'> } +/** + * Options for the DynamoDBProvider getMultiple method. + * + * @interface DynamoDBGetMultipleOptionsInterface + * @extends {GetMultipleOptionsInterface} + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {QueryCommandInput} [sdkOptions] - Additional options to pass to the AWS SDK v3 client. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. + * @property {boolean} throwOnTransformError - Whether to throw an error if the transform fails (default: `true`) + */ interface DynamoDBGetMultipleOptionsInterface extends GetMultipleOptionsInterface { sdkOptions?: Partial } diff --git a/packages/parameters/src/types/SSMProvider.ts b/packages/parameters/src/types/SSMProvider.ts index 9ce1f66e97..36d5f85cb3 100644 --- a/packages/parameters/src/types/SSMProvider.ts +++ b/packages/parameters/src/types/SSMProvider.ts @@ -10,31 +10,68 @@ import type { TransformOptions } from './BaseProvider'; +/** + * Interface for SSMProvider with clientConfig property. + * + * @interface + * @property {SSMClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. + * @property {never} [awsSdkV3Client] - This property should never be passed. + */ interface SSMProviderOptionsWithClientConfig { clientConfig?: SSMClientConfig awsSdkV3Client?: never } +/** + * Interface for SSMProvider with awsSdkV3Client property. + * + * @interface + * @property {SSMClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during SSMProvider class instantiation + * @property {never} [clientConfig] - This property should never be passed. + */ interface SSMProviderOptionsWithClientInstance { awsSdkV3Client?: SSMClient clientConfig?: never } +/** + * Options for the SSMProvider class constructor. + * + * @type SSMProviderOptions + * @property {SSMClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. Mutually exclusive with awsSdkV3Client. + * @property {SSMClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during DynamoDBProvider class instantiation. Mutually exclusive with clientConfig. + */ type SSMProviderOptions = SSMProviderOptionsWithClientConfig | SSMProviderOptionsWithClientInstance; /** - * Options for the SSMProvider get method. - * + * Options for the SSMProvider getMultiple method. + * * @interface SSMGetOptionsInterface * @extends {GetOptionsInterface} + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {GetItemCommandInput} [sdkOptions] - Additional options to pass to the AWS SDK v3 client. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. * @property {boolean} decrypt - If true, the parameter will be decrypted. - * @property {Partial} sdkOptions - Options for the AWS SDK. */ interface SSMGetOptionsInterface extends GetOptionsInterface { decrypt?: boolean sdkOptions?: Partial } +/** + * Options for the SSMProvider getMultiple method. + * + * @interface SSMGetMultipleOptionsInterface + * @extends {GetMultipleOptionsInterface} + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {GetItemCommandInput} [sdkOptions] - Additional options to pass to the AWS SDK v3 client. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. + * @property {boolean} decrypt - If true, the parameter will be decrypted. + * @property {boolean} recursive - If true, the parameter will be fetched recursively. + * @property {boolean} throwOnTransformError - If true, the method will throw an error if the transform fails. + */ interface SSMGetMultipleOptionsInterface extends GetMultipleOptionsInterface { sdkOptions?: Partial decrypt?: boolean @@ -42,6 +79,15 @@ interface SSMGetMultipleOptionsInterface extends GetMultipleOptionsInterface { throwOnTransformError?: boolean } +/** + * Options for the SSMProvider getParametersByName method. + * + * @interface SSMGetParametersByNameOptionsInterface + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. + * @property {boolean} decrypt - If true, the parameter will be decrypted. + * @property {boolean} throwOnError - If true, the method will throw an error if one of the parameters cannot be fetched. Otherwise it will aggregate the errors under an _errors key in the response. + */ interface SSMGetParametersByNameOptionsInterface { maxAge?: number throwOnError?: boolean @@ -49,16 +95,25 @@ interface SSMGetParametersByNameOptionsInterface { transform?: TransformOptions } +/** + * Output type for the SSMProvider splitBatchAndDecryptParameters method. + */ type SSMSplitBatchAndDecryptParametersOutputType = { parametersToFetchInBatch: Record parametersToDecrypt: Record }; +/** + * Output type for the SSMProvider getParametersByName method. + */ interface SSMGetParametersByNameOutputInterface { response: Record errors: string[] } +/** + * Output type for the SSMProvider getParametersByNameFromCache method. + */ type SSMGetParametersByNameFromCacheOutputType = { cached: Record> toFetch: Record diff --git a/packages/parameters/src/types/SecretsProvider.ts b/packages/parameters/src/types/SecretsProvider.ts index 757f38b18b..152dff709b 100644 --- a/packages/parameters/src/types/SecretsProvider.ts +++ b/packages/parameters/src/types/SecretsProvider.ts @@ -1,18 +1,50 @@ import type { GetOptionsInterface } from './BaseProvider'; import type { SecretsManagerClient, SecretsManagerClientConfig, GetSecretValueCommandInput } from '@aws-sdk/client-secrets-manager'; +/** + * Base interface for SecretsProviderOptions. + * + * @interface + * @property {SecretsManagerClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. + * @property {never} [awsSdkV3Client] - This property should never be passed. + */ interface SecretsProviderOptionsWithClientConfig { clientConfig?: SecretsManagerClientConfig awsSdkV3Client?: never } +/** + * Interface for SecretsProviderOptions with awsSdkV3Client property. + * + * @interface + * @extends SecretsProviderOptionsWithClientConfig + * @property {SecretsManagerClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during SecretsProvider class instantiation + * @property {never} [clientConfig] - This property should never be passed. + */ interface SecretsProviderOptionsWithClientInstance { awsSdkV3Client?: SecretsManagerClient clientConfig?: never } +/** + * Options for the SecretsProvider class constructor. + * + * @type SecretsProviderOptions + * @property {AppConfigDataClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. Mutually exclusive with awsSdkV3Client. + * @property {AppConfigDataClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during SecretsProvider class instantiation. Mutually exclusive with clientConfig. + */ type SecretsProviderOptions = SecretsProviderOptionsWithClientConfig | SecretsProviderOptionsWithClientInstance; +/** + * Options to configure the retrieval of a secret. + * + * @interface SecretsGetOptionsInterface + * @extends {GetOptionsInterface} + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {GetSecretValueCommandInput} sdkOptions - Options to pass to the underlying SDK. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. + */ interface SecretsGetOptionsInterface extends GetOptionsInterface { sdkOptions?: Omit, 'SecretId'> } diff --git a/packages/parameters/tests/e2e/appConfigProvider.class.test.functionCode.ts b/packages/parameters/tests/e2e/appConfigProvider.class.test.functionCode.ts index 11d8feb01f..8d3df5445b 100644 --- a/packages/parameters/tests/e2e/appConfigProvider.class.test.functionCode.ts +++ b/packages/parameters/tests/e2e/appConfigProvider.class.test.functionCode.ts @@ -73,10 +73,10 @@ export const handler = async (_event: unknown, _context: Context): Promise // Test 3 - get a free-form base64-encoded plain text and apply binary transformation (should return a decoded string) await _call_get(freeFormBase64encodedPlainText, 'get-freeform-base64-plaintext-binary', { transform: 'binary' }); - // Test 5 - get a feature flag and apply json transformation (should return an object) + // Test 4 - get a feature flag and apply json transformation (should return an object) await _call_get(featureFlagName, 'get-feature-flag-binary', { transform: 'json' }); - // Test 6 + // Test 5 // get parameter twice with middleware, which counts the number of requests, we check later if we only called AppConfig API once try { providerWithMiddleware.clearCache(); @@ -94,7 +94,7 @@ export const handler = async (_event: unknown, _context: Context): Promise }); } - // Test 7 + // Test 6 // get parameter twice, but force fetch 2nd time, we count number of SDK requests and check that we made two API calls try { providerWithMiddleware.clearCache(); diff --git a/packages/parameters/tests/unit/AppConfigProvider.test.ts b/packages/parameters/tests/unit/AppConfigProvider.test.ts index 56365d882c..bf10013df0 100644 --- a/packages/parameters/tests/unit/AppConfigProvider.test.ts +++ b/packages/parameters/tests/unit/AppConfigProvider.test.ts @@ -236,7 +236,7 @@ describe('Class: AppConfigProvider', () => { }; const path = '/my/path'; const provider = new AppConfigProvider(config); - const errorMessage = 'Not Implemented'; + const errorMessage = 'Method not implemented.'; // Act & Assess await expect(provider.getMultiple(path)).rejects.toThrow(errorMessage); diff --git a/typedoc.js b/typedoc.js index de645c6431..d3e9d58c9d 100644 --- a/typedoc.js +++ b/typedoc.js @@ -3,6 +3,7 @@ module.exports = { exclude: [ '**/node_modules/**', '**/*.test.ts', '**/*.json' ], name: 'aws-lambda-powertools-typescript', excludePrivate: true, + excludeInternal: true, entryPointStrategy: 'packages', readme: './README.md', }; \ No newline at end of file