diff --git a/packages/commons/src/awsSdkUtils.ts b/packages/commons/src/awsSdkUtils.ts index df922f9e27..5eabe7f396 100644 --- a/packages/commons/src/awsSdkUtils.ts +++ b/packages/commons/src/awsSdkUtils.ts @@ -47,9 +47,23 @@ const isSdkClient = (client: unknown): client is SdkClient => const customUserAgentMiddleware = (feature: string) => { return (next: (arg0: T) => Promise) => async (args: T) => { - const powertoolsUserAgent = `PT/${feature}/${PT_VERSION} PTEnv/${EXEC_ENV}`; + const existingUserAgent = args.request.headers['user-agent'] || ''; + if (existingUserAgent.includes('PT/NO-OP')) { + const featureSpecificUserAgent = existingUserAgent.replace( + 'PT/NO-OP', + `PT/${feature}/${PT_VERSION} PTEnv/${EXEC_ENV}` + ); + + args.request.headers['user-agent'] = featureSpecificUserAgent; + return await next(args); + } + if (existingUserAgent.includes('PT/')) { + return await next(args); + } args.request.headers['user-agent'] = - `${args.request.headers['user-agent']} ${powertoolsUserAgent}`; + existingUserAgent === '' + ? `PT/${feature}/${PT_VERSION} PTEnv/${EXEC_ENV}` + : `${existingUserAgent} PT/${feature}/${PT_VERSION} PTEnv/${EXEC_ENV}`; return await next(args); }; diff --git a/packages/commons/src/index.ts b/packages/commons/src/index.ts index 591ad8ccff..03b21e2ef7 100644 --- a/packages/commons/src/index.ts +++ b/packages/commons/src/index.ts @@ -1,3 +1,8 @@ +import { PT_VERSION } from './version.js'; +if (!process.env.AWS_SDK_UA_APP_ID) { + process.env.AWS_SDK_UA_APP_ID = `PT/NO-OP/${PT_VERSION}`; +} +export { PT_VERSION } from './version.js'; export { isRecord, isString, @@ -19,4 +24,3 @@ export { METRICS_KEY, IDEMPOTENCY_KEY, } from './middleware/constants.js'; -export { PT_VERSION } from './version.js'; diff --git a/packages/commons/tests/unit/awsSdkUtils.test.ts b/packages/commons/tests/unit/awsSdkUtils.test.ts index 907409b25d..c8f233e355 100644 --- a/packages/commons/tests/unit/awsSdkUtils.test.ts +++ b/packages/commons/tests/unit/awsSdkUtils.test.ts @@ -96,26 +96,49 @@ describe('Helpers: awsSdk', () => { expect(middleware).toBeInstanceOf(Function); }); - it('adds the Powertools UA to the request headers', async () => { + const feature = 'my-feature'; + const middleware = customUserAgentMiddleware(feature); + + it.each([ + { + case: 'adds the feature-specific UA when none is present', + headers: {}, + expected: `PT/my-feature/${version} PTEnv/NA`, + }, + { + case: 'concatenates the ua to existing ones', + headers: { + 'user-agent': 'foo', + }, + expected: `foo PT/my-feature/${version} PTEnv/NA`, + }, + { + case: 'replaces no-op UA with the feature-specific one', + headers: { + 'user-agent': 'PT/NO-OP', + }, + expected: `PT/my-feature/${version} PTEnv/NA`, + }, + { + case: 'leaves a feature-specific UA intact', + headers: { + 'user-agent': 'PT/other-feature/1.0 PTEnv/NA', + }, + expected: 'PT/other-feature/1.0 PTEnv/NA', + }, + ])('it $case', async ({ headers, expected }) => { // Prepare - const feature = 'my-feature'; - const middleware = customUserAgentMiddleware(feature); - const next = vi.fn(); const args = { request: { - headers: { - 'user-agent': 'foo', - }, + headers, }, }; // Act - await middleware(next)(args); + await middleware(vi.fn())(args); // Assess - expect(args.request.headers['user-agent']).toEqual( - `foo PT/my-feature/${version} PTEnv/NA` - ); + expect(args.request.headers['user-agent']).toEqual(expected); }); });