1+ import type { MiddlewareArgsLike , SdkClient } from './types/awsSdk' ;
2+ import { MAOTS_VERSION } from './version' ;
3+
4+ const EXEC_ENV = process . env . AWS_EXECUTION_ENV || 'NA' ;
5+ const middlewareOptions = {
6+ relation : 'after' ,
7+ toMiddleware : 'getUserAgentMiddleware' ,
8+ name : 'addMaoToUserAgent' ,
9+ tags : [ 'MAOTS' , 'USER_AGENT' ] ,
10+ } ;
11+
12+ /**
13+ * Type guard to check if the client provided is a valid AWS SDK v3 client.
14+ *
15+ * @internal
16+ */
17+ const isSdkClient = ( client : unknown ) : client is SdkClient =>
18+ typeof client === 'object' &&
19+ client !== null &&
20+ 'send' in client &&
21+ typeof client . send === 'function' &&
22+ 'config' in client &&
23+ client . config !== undefined &&
24+ typeof client . config === 'object' &&
25+ client . config !== null &&
26+ 'middlewareStack' in client &&
27+ client . middlewareStack !== undefined &&
28+ typeof client . middlewareStack === 'object' &&
29+ client . middlewareStack !== null &&
30+ 'identify' in client . middlewareStack &&
31+ typeof client . middlewareStack . identify === 'function' &&
32+ 'addRelativeTo' in client . middlewareStack &&
33+ typeof client . middlewareStack . addRelativeTo === 'function' ;
34+
35+ /**
36+ * Helper function to create a custom user agent middleware for the AWS SDK v3 clients.
37+ *
38+ * The middleware will append the provided feature name and the current version of
39+ * the Mao for AWS Lambda library to the user agent string.
40+ *
41+ * @example "MAOTS/Bedrock-classifier/2.1.0 PTEnv/nodejs20x"
42+ *
43+ * @param feature The feature name to be added to the user agent
44+ *
45+ * @internal
46+ */
47+ const customUserAgentMiddleware = ( feature : string ) => {
48+ return < T extends MiddlewareArgsLike > ( next : ( arg0 : T ) => Promise < T > ) =>
49+ async ( args : T ) => {
50+ const existingUserAgent = args . request . headers [ 'user-agent' ] || '' ;
51+ if ( existingUserAgent . includes ( 'MAOTS/NO-OP' ) ) {
52+ const featureSpecificUserAgent = existingUserAgent . replace (
53+ 'MAOTS/NO-OP' ,
54+ `MAOTS/${ feature } /${ MAOTS_VERSION } MAOTSEnv/${ EXEC_ENV } `
55+ ) ;
56+
57+ args . request . headers [ 'user-agent' ] = featureSpecificUserAgent ;
58+ return await next ( args ) ;
59+ }
60+ if ( existingUserAgent . includes ( 'MAOTS/' ) ) {
61+ return await next ( args ) ;
62+ }
63+ args . request . headers [ 'user-agent' ] =
64+ existingUserAgent === ''
65+ ? `MAOTS/${ feature } /${ MAOTS_VERSION } MAOTSEnv/${ EXEC_ENV } `
66+ : `${ existingUserAgent } MAOTS/${ feature } /${ MAOTS_VERSION } MAOTSEnv/${ EXEC_ENV } ` ;
67+
68+ return await next ( args ) ;
69+ } ;
70+ } ;
71+
72+ /**
73+ * Check if the provided middleware stack already has the Mao for AWS Lambda
74+ * user agent middleware.
75+ *
76+ * @param middlewareStack The middleware stack to check
77+ *
78+ * @internal
79+ */
80+ const hasMao = ( middlewareStack : string [ ] ) : boolean => {
81+ let found = false ;
82+ for ( const middleware of middlewareStack ) {
83+ if ( middleware . includes ( 'addMaoToUserAgent' ) ) {
84+ found = true ;
85+ }
86+ }
87+
88+ return found ;
89+ } ;
90+
91+ /**
92+ * Add the MAo for AWS Lambda user agent middleware to the
93+ * AWS SDK v3 client provided.
94+ *
95+ * We use this middleware to unbotrusively track the usage of the library
96+ * and secure continued investment in the project.
97+ *
98+ * @param client The AWS SDK v3 client to add the middleware to
99+ * @param feature The feature name to be added to the user agent
100+ */
101+ const addUserAgentMiddleware = ( client : unknown , feature : string ) : void => {
102+ try {
103+ if ( isSdkClient ( client ) ) {
104+ if ( hasMao ( client . middlewareStack . identify ( ) ) ) {
105+ return ;
106+ }
107+ client . middlewareStack . addRelativeTo (
108+ customUserAgentMiddleware ( feature ) ,
109+ middlewareOptions
110+ ) ;
111+ } else {
112+ throw new Error (
113+ 'The client provided does not match the expected interface'
114+ ) ;
115+ }
116+ } catch ( error ) {
117+ console . warn ( 'Failed to add user agent middleware' , error ) ;
118+ }
119+ } ;
120+
121+ export { customUserAgentMiddleware , addUserAgentMiddleware , isSdkClient } ;
0 commit comments