@@ -12,7 +12,7 @@ import {
1212 TokenIdentity ,
1313 TokenIdentityProvider ,
1414} from '@smithy/types'
15- import { getUserAgent } from './telemetry/util'
15+ import { getUserAgentPairs } from './telemetry/util'
1616import { DevSettings } from './settings'
1717import {
1818 BuildHandler ,
@@ -37,7 +37,6 @@ import { HttpResponse, HttpRequest } from '@aws-sdk/protocol-http'
3737import { ConfiguredRetryStrategy } from '@smithy/util-retry'
3838import { telemetry } from './telemetry/telemetry'
3939import { getRequestId , getTelemetryReason , getTelemetryReasonDesc , getTelemetryResult } from './errors'
40- import { extensionVersion } from './vscode/env'
4140import { getLogger } from './logger/logger'
4241import { partialClone } from './utilities/collectionUtils'
4342import { selectFrom } from './utilities/tsUtils'
@@ -72,7 +71,7 @@ export interface AwsCommand<InputType extends object, OutputType extends object>
7271export interface AwsClientOptions {
7372 credentials : AwsCredentialIdentityProvider
7473 region : string | Provider < string >
75- userAgent : UserAgent
74+ customUserAgent : UserAgent
7675 requestHandler : {
7776 metadata ?: RequestHandlerMetadata
7877 handle : ( req : any , options ?: any ) => Promise < RequestHandlerOutput < any > >
@@ -155,8 +154,8 @@ export class AWSClientBuilderV3 {
155154 opt . region = serviceOptions . region
156155 }
157156
158- if ( ! opt . userAgent && userAgent ) {
159- opt . userAgent = [ [ getUserAgent ( { includePlatform : true , includeClientId : true } ) , extensionVersion ] ]
157+ if ( ! opt . customUserAgent && userAgent ) {
158+ opt . customUserAgent = getUserAgentPairs ( { includePlatform : true , includeClientId : true } )
160159 }
161160
162161 if ( ! opt . retryStrategy ) {
@@ -196,6 +195,7 @@ export class AWSClientBuilderV3 {
196195 }
197196 const service = new serviceOptions . serviceClient ( opt )
198197 service . middlewareStack . add ( telemetryMiddleware , { step : 'deserialize' } )
198+ service . middlewareStack . add ( captureHeadersMiddleware , { step : 'deserialize' } )
199199 service . middlewareStack . add ( loggingMiddleware , { step : 'finalizeRequest' } )
200200 service . middlewareStack . add ( getEndpointMiddleware ( serviceOptions . settings ) , { step : 'build' } )
201201
@@ -254,6 +254,26 @@ function getEndpointMiddleware(settings: DevSettings = DevSettings.instance): Bu
254254const keepAliveMiddleware : BuildMiddleware < any , any > = ( next : BuildHandler < any , any > ) => async ( args : any ) =>
255255 addKeepAliveHeader ( next , args )
256256
257+ /**
258+ * Middleware that captures HTTP response headers and attaches them to the output object.
259+ * This makes headers accessible via `response.$httpHeaders` for all AWS SDK v3 operations.
260+ * Useful for detecting custom headers from services like LocalStack.
261+ */
262+ const captureHeadersMiddleware : DeserializeMiddleware < any , any > =
263+ ( next : DeserializeHandler < any , any > ) => async ( args : any ) => {
264+ const result = await next ( args )
265+
266+ // Extract headers from HTTP response and attach to output for easy access
267+ if ( HttpResponse . isInstance ( result . response ) ) {
268+ const headers = result . response . headers
269+ if ( headers && result . output ) {
270+ result . output . $httpHeaders = headers
271+ }
272+ }
273+
274+ return result
275+ }
276+
257277export async function emitOnRequest ( next : DeserializeHandler < any , any > , context : HandlerExecutionContext , args : any ) {
258278 if ( ! HttpResponse . isInstance ( args . request ) ) {
259279 return next ( args )
0 commit comments