diff --git a/packages/core/src/submodules/account-id-endpoint/AccountIdEndpointModeConfigResolver.spec.ts b/packages/core/src/submodules/account-id-endpoint/AccountIdEndpointModeConfigResolver.spec.ts new file mode 100644 index 000000000000..d518134cee93 --- /dev/null +++ b/packages/core/src/submodules/account-id-endpoint/AccountIdEndpointModeConfigResolver.spec.ts @@ -0,0 +1,10 @@ +import { describe, expect, test as it } from "vitest"; + +import { resolveAccountIdEndpointModeConfig } from "./AccountIdEndpointModeConfigResolver"; + +describe(resolveAccountIdEndpointModeConfig.name, () => { + it("maintains object custody", () => { + const input = {}; + expect(resolveAccountIdEndpointModeConfig(input)).toBe(input); + }); +}); diff --git a/packages/core/src/submodules/account-id-endpoint/AccountIdEndpointModeConfigResolver.ts b/packages/core/src/submodules/account-id-endpoint/AccountIdEndpointModeConfigResolver.ts index 36ae35492651..b9166c184c39 100644 --- a/packages/core/src/submodules/account-id-endpoint/AccountIdEndpointModeConfigResolver.ts +++ b/packages/core/src/submodules/account-id-endpoint/AccountIdEndpointModeConfigResolver.ts @@ -35,11 +35,9 @@ export interface AccountIdEndpointModeResolvedConfig { export const resolveAccountIdEndpointModeConfig = ( input: T & AccountIdEndpointModeInputConfig & PreviouslyResolved ): T & AccountIdEndpointModeResolvedConfig => { - const accountIdEndpointModeProvider = normalizeProvider( - input.accountIdEndpointMode ?? DEFAULT_ACCOUNT_ID_ENDPOINT_MODE - ); - return { - ...input, + const { accountIdEndpointMode } = input; + const accountIdEndpointModeProvider = normalizeProvider(accountIdEndpointMode ?? DEFAULT_ACCOUNT_ID_ENDPOINT_MODE); + return Object.assign(input, { accountIdEndpointMode: async () => { const accIdMode = await accountIdEndpointModeProvider(); if (!validateAccountIdEndpointMode(accIdMode)) { @@ -49,5 +47,5 @@ export const resolveAccountIdEndpointModeConfig = ( } return accIdMode; }, - }; + }); }; diff --git a/packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4AConfig.spec.ts b/packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4AConfig.spec.ts index 7a258e16bb68..c51290d15856 100644 --- a/packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4AConfig.spec.ts +++ b/packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4AConfig.spec.ts @@ -9,4 +9,9 @@ describe(resolveAwsSdkSigV4AConfig.name, () => { expect(typeof config.sigv4aSigningRegionSet).toEqual("function"); expect(await config.sigv4aSigningRegionSet()).toEqual(undefined); }); + + it("maintains object custody", () => { + const input = {}; + expect(resolveAwsSdkSigV4AConfig(input)).toBe(input); + }); }); diff --git a/packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4Config.spec.ts b/packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4Config.spec.ts index 3f3b1a5fabb8..eb3c2455bf4b 100644 --- a/packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4Config.spec.ts +++ b/packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4Config.spec.ts @@ -4,6 +4,17 @@ import { describe, expect, test as it, vi } from "vitest"; import { resolveAwsSdkSigV4Config } from "./resolveAwsSdkSigV4Config"; describe(resolveAwsSdkSigV4Config.name, () => { + it("maintains object custody", () => { + const input = { + region: "", + sha256: vi.fn(), + serviceId: "", + useFipsEndpoint: async () => false, + useDualstackEndpoint: async () => false, + }; + expect(resolveAwsSdkSigV4Config(input)).toBe(input); + }); + it("should allow one argument to be passed to the resolved credentials function", async () => { const fn = vi.fn(); diff --git a/packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4Config.ts b/packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4Config.ts index 9079d9def144..b71b04c607f7 100644 --- a/packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4Config.ts +++ b/packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4Config.ts @@ -221,8 +221,7 @@ export const resolveAwsSdkSigV4Config = ( }; } - return { - ...config, + return Object.assign(config, { systemClockOffset, signingEscapePath, credentials: isUserSupplied @@ -232,7 +231,7 @@ export const resolveAwsSdkSigV4Config = ( ) : boundCredentialsProvider!, signer, - }; + }); }; /** diff --git a/packages/middleware-api-key/src/apiKeyConfiguration.spec.ts b/packages/middleware-api-key/src/apiKeyConfiguration.spec.ts index d67bae14a948..25a508d41493 100644 --- a/packages/middleware-api-key/src/apiKeyConfiguration.spec.ts +++ b/packages/middleware-api-key/src/apiKeyConfiguration.spec.ts @@ -3,6 +3,12 @@ import { describe, expect, test as it } from "vitest"; import { resolveApiKeyConfig } from "./index"; describe("ApiKeyConfig", () => { + it("maintains object custody", () => { + const config = { + apiKey: () => Promise.resolve("example-api-key"), + }; + expect(resolveApiKeyConfig(config)).toBe(config); + }); it("should return the input unchanged", () => { const config = { apiKey: () => Promise.resolve("example-api-key"), diff --git a/packages/middleware-api-key/src/apiKeyConfiguration.ts b/packages/middleware-api-key/src/apiKeyConfiguration.ts index a3050a27fee5..dc4360cfd4c3 100644 --- a/packages/middleware-api-key/src/apiKeyConfiguration.ts +++ b/packages/middleware-api-key/src/apiKeyConfiguration.ts @@ -31,8 +31,8 @@ export interface ApiKeyResolvedConfig { export const resolveApiKeyConfig = ( input: T & ApiKeyPreviouslyResolved & ApiKeyInputConfig ): T & ApiKeyResolvedConfig => { - return { - ...input, - apiKey: input.apiKey ? normalizeProvider(input.apiKey) : undefined, - }; + const { apiKey } = input; + return Object.assign(input, { + apiKey: apiKey ? normalizeProvider(apiKey) : undefined, + }); }; diff --git a/packages/middleware-bucket-endpoint/src/configurations.spec.ts b/packages/middleware-bucket-endpoint/src/configurations.spec.ts new file mode 100644 index 000000000000..b413f7514af7 --- /dev/null +++ b/packages/middleware-bucket-endpoint/src/configurations.spec.ts @@ -0,0 +1,15 @@ +import { describe, expect, test as it, vi } from "vitest"; + +import { resolveBucketEndpointConfig } from "./configurations"; + +describe(resolveBucketEndpointConfig.name, () => { + it("maintains object custody", () => { + const input = { + region: async () => "", + regionInfoProvider: vi.fn(), + useFipsEndpoint: async () => false, + useDualstackEndpoint: async () => false, + }; + expect(resolveBucketEndpointConfig(input)).toBe(input); + }); +}); diff --git a/packages/middleware-bucket-endpoint/src/configurations.ts b/packages/middleware-bucket-endpoint/src/configurations.ts index f555ad0484f8..831466103fa0 100644 --- a/packages/middleware-bucket-endpoint/src/configurations.ts +++ b/packages/middleware-bucket-endpoint/src/configurations.ts @@ -93,8 +93,7 @@ export function resolveBucketEndpointConfig( useArnRegion = false, disableMultiregionAccessPoints = false, } = input; - return { - ...input, + return Object.assign(input, { bucketEndpoint, forcePathStyle, useAccelerateEndpoint, @@ -103,5 +102,5 @@ export function resolveBucketEndpointConfig( typeof disableMultiregionAccessPoints === "function" ? disableMultiregionAccessPoints : () => Promise.resolve(disableMultiregionAccessPoints), - }; + }); } diff --git a/packages/middleware-endpoint-discovery/src/resolveEndpointDiscoveryConfig.spec.ts b/packages/middleware-endpoint-discovery/src/resolveEndpointDiscoveryConfig.spec.ts index f435d191eef3..5462144461e4 100644 --- a/packages/middleware-endpoint-discovery/src/resolveEndpointDiscoveryConfig.spec.ts +++ b/packages/middleware-endpoint-discovery/src/resolveEndpointDiscoveryConfig.spec.ts @@ -7,18 +7,26 @@ vi.mock("@aws-sdk/endpoint-cache"); describe(resolveEndpointDiscoveryConfig.name, () => { const endpointDiscoveryCommandCtor = vi.fn(); - const mockInput = { + const mockInput = () => ({ isCustomEndpoint: false, credentials: vi.fn(), endpointDiscoveryEnabledProvider: vi.fn(), - }; + }); afterEach(() => { vi.clearAllMocks(); }); + it("maintains object custody", () => { + const input = { + credentials: vi.fn(), + endpointDiscoveryEnabledProvider: async () => false, + }; + expect(resolveEndpointDiscoveryConfig(input, { endpointDiscoveryCommandCtor })).toBe(input); + }); + it("assigns endpointDiscoveryCommandCtor in resolvedConfig", () => { - const resolvedConfig = resolveEndpointDiscoveryConfig(mockInput, { endpointDiscoveryCommandCtor }); + const resolvedConfig = resolveEndpointDiscoveryConfig(mockInput(), { endpointDiscoveryCommandCtor }); expect(resolvedConfig.endpointDiscoveryCommandCtor).toStrictEqual(endpointDiscoveryCommandCtor); }); @@ -27,7 +35,7 @@ describe(resolveEndpointDiscoveryConfig.name, () => { const endpointCacheSize = 100; resolveEndpointDiscoveryConfig( { - ...mockInput, + ...mockInput(), endpointCacheSize, }, { endpointDiscoveryCommandCtor } @@ -36,28 +44,30 @@ describe(resolveEndpointDiscoveryConfig.name, () => { }); it("creates cache of size 1000 if endpointCacheSize not passed", () => { - resolveEndpointDiscoveryConfig(mockInput, { endpointDiscoveryCommandCtor }); + resolveEndpointDiscoveryConfig(mockInput(), { endpointDiscoveryCommandCtor }); expect(EndpointCache).toBeCalledWith(1000); }); }); describe("endpointDiscoveryEnabled", () => { it.each([false, true])(`sets to value passed in the config: %s`, async (endpointDiscoveryEnabled) => { + const input = mockInput(); const resolvedConfig = resolveEndpointDiscoveryConfig( { - ...mockInput, + ...input, endpointDiscoveryEnabled, }, { endpointDiscoveryCommandCtor } ); await expect(resolvedConfig.endpointDiscoveryEnabled()).resolves.toBe(endpointDiscoveryEnabled); - expect(mockInput.endpointDiscoveryEnabledProvider).not.toHaveBeenCalled(); + expect(input.endpointDiscoveryEnabledProvider).not.toHaveBeenCalled(); expect(resolvedConfig.isClientEndpointDiscoveryEnabled).toStrictEqual(true); }); it(`sets to endpointDiscoveryEnabledProvider if value is not passed`, () => { - const resolvedConfig = resolveEndpointDiscoveryConfig(mockInput, { endpointDiscoveryCommandCtor }); - expect(resolvedConfig.endpointDiscoveryEnabled).toBe(mockInput.endpointDiscoveryEnabledProvider); + const input = mockInput(); + const resolvedConfig = resolveEndpointDiscoveryConfig(input, { endpointDiscoveryCommandCtor }); + expect(resolvedConfig.endpointDiscoveryEnabled).toBe(input.endpointDiscoveryEnabledProvider); expect(resolvedConfig.isClientEndpointDiscoveryEnabled).toStrictEqual(false); }); }); diff --git a/packages/middleware-endpoint-discovery/src/resolveEndpointDiscoveryConfig.ts b/packages/middleware-endpoint-discovery/src/resolveEndpointDiscoveryConfig.ts index 732b373ad7b8..2dfc63d1f757 100644 --- a/packages/middleware-endpoint-discovery/src/resolveEndpointDiscoveryConfig.ts +++ b/packages/middleware-endpoint-discovery/src/resolveEndpointDiscoveryConfig.ts @@ -68,13 +68,16 @@ export interface EndpointDiscoveryConfigOptions { export const resolveEndpointDiscoveryConfig = ( input: T & PreviouslyResolved & EndpointDiscoveryInputConfig, { endpointDiscoveryCommandCtor }: EndpointDiscoveryConfigOptions -): T & EndpointDiscoveryResolvedConfig => ({ - ...input, - endpointDiscoveryCommandCtor, - endpointCache: new EndpointCache(input.endpointCacheSize ?? 1000), - endpointDiscoveryEnabled: - input.endpointDiscoveryEnabled !== undefined - ? () => Promise.resolve(input.endpointDiscoveryEnabled) - : input.endpointDiscoveryEnabledProvider, - isClientEndpointDiscoveryEnabled: input.endpointDiscoveryEnabled !== undefined, -}); +): T & EndpointDiscoveryResolvedConfig => { + const { endpointCacheSize, endpointDiscoveryEnabled, endpointDiscoveryEnabledProvider } = input; + + return Object.assign(input, { + endpointDiscoveryCommandCtor, + endpointCache: new EndpointCache(endpointCacheSize ?? 1000), + endpointDiscoveryEnabled: + endpointDiscoveryEnabled !== undefined + ? () => Promise.resolve(endpointDiscoveryEnabled) + : endpointDiscoveryEnabledProvider, + isClientEndpointDiscoveryEnabled: endpointDiscoveryEnabled !== undefined, + }); +}; diff --git a/packages/middleware-eventstream/src/eventStreamConfiguration.ts b/packages/middleware-eventstream/src/eventStreamConfiguration.ts index b82fa0ffa2f7..47796b798329 100644 --- a/packages/middleware-eventstream/src/eventStreamConfiguration.ts +++ b/packages/middleware-eventstream/src/eventStreamConfiguration.ts @@ -36,13 +36,12 @@ export function resolveEventStreamConfig( ): T & EventStreamResolvedConfig { const eventSigner = input.signer; const messageSigner = input.signer; - const eventStreamPayloadHandler = input.eventStreamPayloadHandlerProvider({ - ...input, + const newInput = Object.assign(input, { + eventSigner, messageSigner, }); - return { - ...input, - eventSigner, + const eventStreamPayloadHandler = newInput.eventStreamPayloadHandlerProvider(newInput); + return Object.assign(newInput, { eventStreamPayloadHandler, - }; + }); } diff --git a/packages/middleware-eventstream/src/middleware-eventstream.integ.spec.ts b/packages/middleware-eventstream/src/middleware-eventstream.integ.spec.ts index b8cf25b96cbc..4f5aedd1267b 100644 --- a/packages/middleware-eventstream/src/middleware-eventstream.integ.spec.ts +++ b/packages/middleware-eventstream/src/middleware-eventstream.integ.spec.ts @@ -1,9 +1,11 @@ import { LexRuntimeV2 } from "@aws-sdk/client-lex-runtime-v2"; import { RekognitionStreaming } from "@aws-sdk/client-rekognitionstreaming"; import { TranscribeStreaming } from "@aws-sdk/client-transcribe-streaming"; -import { describe, expect, test as it } from "vitest"; +import { Decoder, Encoder, EventStreamPayloadHandlerProvider } from "@smithy/types"; +import { describe, expect, test as it, vi } from "vitest"; import { requireRequestsFrom } from "../../../private/aws-util-test/src"; +import { resolveEventStreamConfig } from "./eventStreamConfiguration"; describe("middleware-eventstream", () => { const logger = { @@ -14,6 +16,18 @@ describe("middleware-eventstream", () => { error() {}, }; + describe("config resolver", () => { + it("maintains object custody", () => { + const input = { + utf8Encoder: vi.fn(), + utf8Decoder: vi.fn(), + signer: vi.fn(), + eventStreamPayloadHandlerProvider: vi.fn(), + }; + expect(resolveEventStreamConfig(input)).toBe(input); + }); + }); + // TODO: http2 in CI describe.skip(LexRuntimeV2.name, () => { it("should set streaming headers", async () => { diff --git a/packages/middleware-flexible-checksums/src/resolveFlexibleChecksumsConfig.spec.ts b/packages/middleware-flexible-checksums/src/resolveFlexibleChecksumsConfig.spec.ts index 9f340834a480..7d8de834ee0b 100644 --- a/packages/middleware-flexible-checksums/src/resolveFlexibleChecksumsConfig.spec.ts +++ b/packages/middleware-flexible-checksums/src/resolveFlexibleChecksumsConfig.spec.ts @@ -20,6 +20,11 @@ describe(resolveFlexibleChecksumsConfig.name, () => { vi.clearAllMocks(); }); + it("maintains object custody", () => { + const input = {}; + expect(resolveFlexibleChecksumsConfig(input)).toBe(input); + }); + it("returns default client checksums configuration, if not provided", () => { const resolvedConfig = resolveFlexibleChecksumsConfig({}); expect(resolvedConfig).toEqual({ diff --git a/packages/middleware-flexible-checksums/src/resolveFlexibleChecksumsConfig.ts b/packages/middleware-flexible-checksums/src/resolveFlexibleChecksumsConfig.ts index 235b7625f01e..df38da5429ca 100644 --- a/packages/middleware-flexible-checksums/src/resolveFlexibleChecksumsConfig.ts +++ b/packages/middleware-flexible-checksums/src/resolveFlexibleChecksumsConfig.ts @@ -54,13 +54,11 @@ export interface FlexibleChecksumsResolvedConfig { */ export const resolveFlexibleChecksumsConfig = ( input: T & FlexibleChecksumsInputConfig -): T & FlexibleChecksumsResolvedConfig => ({ - ...input, - requestChecksumCalculation: normalizeProvider( - input.requestChecksumCalculation ?? DEFAULT_REQUEST_CHECKSUM_CALCULATION - ), - responseChecksumValidation: normalizeProvider( - input.responseChecksumValidation ?? DEFAULT_RESPONSE_CHECKSUM_VALIDATION - ), - requestStreamBufferSize: Number(input.requestStreamBufferSize ?? 0), -}); +): T & FlexibleChecksumsResolvedConfig => { + const { requestChecksumCalculation, responseChecksumValidation, requestStreamBufferSize } = input; + return Object.assign(input, { + requestChecksumCalculation: normalizeProvider(requestChecksumCalculation ?? DEFAULT_REQUEST_CHECKSUM_CALCULATION), + responseChecksumValidation: normalizeProvider(responseChecksumValidation ?? DEFAULT_RESPONSE_CHECKSUM_VALIDATION), + requestStreamBufferSize: Number(requestStreamBufferSize ?? 0), + }); +}; diff --git a/packages/middleware-host-header/src/index.spec.ts b/packages/middleware-host-header/src/index.spec.ts index 52e945c28429..81f13865a4ea 100644 --- a/packages/middleware-host-header/src/index.spec.ts +++ b/packages/middleware-host-header/src/index.spec.ts @@ -1,7 +1,7 @@ import { HttpRequest } from "@smithy/protocol-http"; import { beforeEach, describe, expect, test as it, vi } from "vitest"; -import { hostHeaderMiddleware } from "./index"; +import { hostHeaderMiddleware, resolveHostHeaderConfig } from "./index"; describe("hostHeaderMiddleware", () => { const mockNextHandler = vi.fn(); @@ -9,6 +9,13 @@ describe("hostHeaderMiddleware", () => { vi.clearAllMocks(); }); + it("maintains object custody", () => { + const input = { + requestHandler: vi.fn() as any, + }; + expect(resolveHostHeaderConfig(input)).toBe(input); + }); + it("should set host header if not already set", async () => { expect.assertions(2); const middleware = hostHeaderMiddleware({ requestHandler: {} as any }); diff --git a/packages/middleware-location-constraint/src/configuration.ts b/packages/middleware-location-constraint/src/configuration.ts index 88fe114eb04e..bd1b496593c9 100644 --- a/packages/middleware-location-constraint/src/configuration.ts +++ b/packages/middleware-location-constraint/src/configuration.ts @@ -18,5 +18,5 @@ export interface LocationConstraintResolvedConfig { export function resolveLocationConstraintConfig( input: T & LocationConstraintInputConfig & PreviouslyResolved ): T & LocationConstraintResolvedConfig { - return { ...input }; + return input; } diff --git a/packages/middleware-location-constraint/src/index.spec.ts b/packages/middleware-location-constraint/src/index.spec.ts index 320c4be1cd18..ac02e39e3929 100644 --- a/packages/middleware-location-constraint/src/index.spec.ts +++ b/packages/middleware-location-constraint/src/index.spec.ts @@ -1,6 +1,7 @@ import { beforeEach, describe, expect, test as it, vi } from "vitest"; import { locationConstraintMiddleware } from "./"; +import { resolveLocationConstraintConfig } from "./configuration"; describe("locationConstrainMiddleware", () => { const next = vi.fn(); @@ -12,6 +13,13 @@ describe("locationConstrainMiddleware", () => { vi.clearAllMocks(); }); + describe("config resolver", () => { + it("maintains object custody", () => { + const input = {} as any; + expect(resolveLocationConstraintConfig(input)).toBe(input); + }); + }); + describe("for region us-east-1", () => { const handler = locationConstraintMiddleware({ region: () => Promise.resolve("us-east-1"), diff --git a/packages/middleware-sdk-s3-control/src/configurations.spec.ts b/packages/middleware-sdk-s3-control/src/configurations.spec.ts new file mode 100644 index 000000000000..411383e6bbf7 --- /dev/null +++ b/packages/middleware-sdk-s3-control/src/configurations.spec.ts @@ -0,0 +1,10 @@ +import { describe, expect, test as it } from "vitest"; + +import { resolveS3ControlConfig } from "./configurations"; + +describe(resolveS3ControlConfig.name, () => { + it("maintains object custody", () => { + const input = {} as any; + expect(resolveS3ControlConfig(input)).toBe(input); + }); +}); diff --git a/packages/middleware-sdk-s3-control/src/configurations.ts b/packages/middleware-sdk-s3-control/src/configurations.ts index a7d34107d222..55ff29a12117 100644 --- a/packages/middleware-sdk-s3-control/src/configurations.ts +++ b/packages/middleware-sdk-s3-control/src/configurations.ts @@ -52,8 +52,7 @@ export function resolveS3ControlConfig( input: T & PreviouslyResolved & S3ControlInputConfig ): T & S3ControlResolvedConfig { const { useArnRegion = false } = input; - return { - ...input, + return Object.assign(input, { useArnRegion: typeof useArnRegion === "function" ? useArnRegion : () => Promise.resolve(useArnRegion), - }; + }); } diff --git a/packages/middleware-sdk-s3/src/s3Configuration.spec.ts b/packages/middleware-sdk-s3/src/s3Configuration.spec.ts new file mode 100644 index 000000000000..4465a63fd962 --- /dev/null +++ b/packages/middleware-sdk-s3/src/s3Configuration.spec.ts @@ -0,0 +1,14 @@ +import { describe, expect, test as it, vi } from "vitest"; + +import { resolveS3Config } from "./s3Configuration"; + +describe(resolveS3Config.name, () => { + it("maintains object custody", () => { + const input = {}; + expect( + resolveS3Config(input, { + session: [() => null, vi.fn()], + }) + ).toBe(input); + }); +}); diff --git a/packages/middleware-sdk-s3/src/s3Configuration.ts b/packages/middleware-sdk-s3/src/s3Configuration.ts index 6dfd9d3544ec..3b3ed7f3b48c 100644 --- a/packages/middleware-sdk-s3/src/s3Configuration.ts +++ b/packages/middleware-sdk-s3/src/s3Configuration.ts @@ -3,9 +3,8 @@ import type { Client, Command } from "@smithy/types"; import { S3ExpressIdentityProvider, S3ExpressIdentityProviderImpl } from "./s3-express"; /** - * @public - * * All endpoint parameters with built-in bindings of AWS::S3::* + * @public */ export interface S3InputConfig { /** @@ -28,7 +27,7 @@ export interface S3InputConfig { * This feature should only be used as a last resort if you do not know the region of your bucket(s) ahead of time. */ followRegionRedirects?: boolean; - /* + /** * Identity provider for an S3 feature. */ s3ExpressIdentityProvider?: S3ExpressIdentityProvider; @@ -39,16 +38,16 @@ export interface S3InputConfig { } /** - * @internal * This is a placeholder for the actual * S3Client type from \@aws-sdk/client-s3. It is not explicitly * imported to avoid a circular dependency. + * @internal */ type PlaceholderS3Client = Client & any; /** - * @internal * Placeholder for the constructor for CreateSessionCommand. + * @internal */ type PlaceholderCreateSessionCommandCtor = { new (args: any): Command }; @@ -70,14 +69,22 @@ export const resolveS3Config = ( } ): T & S3ResolvedConfig => { const [s3ClientProvider, CreateSessionCommandCtor] = session; - return { - ...input, - forcePathStyle: input.forcePathStyle ?? false, - useAccelerateEndpoint: input.useAccelerateEndpoint ?? false, - disableMultiregionAccessPoints: input.disableMultiregionAccessPoints ?? false, - followRegionRedirects: input.followRegionRedirects ?? false, + const { + forcePathStyle, + useAccelerateEndpoint, + disableMultiregionAccessPoints, + followRegionRedirects, + s3ExpressIdentityProvider, + bucketEndpoint, + } = input; + + return Object.assign(input, { + forcePathStyle: forcePathStyle ?? false, + useAccelerateEndpoint: useAccelerateEndpoint ?? false, + disableMultiregionAccessPoints: disableMultiregionAccessPoints ?? false, + followRegionRedirects: followRegionRedirects ?? false, s3ExpressIdentityProvider: - input.s3ExpressIdentityProvider ?? + s3ExpressIdentityProvider ?? new S3ExpressIdentityProviderImpl(async (key: string) => s3ClientProvider().send( new CreateSessionCommandCtor({ @@ -85,6 +92,6 @@ export const resolveS3Config = ( }) ) ), - bucketEndpoint: input.bucketEndpoint ?? false, - }; + bucketEndpoint: bucketEndpoint ?? false, + }); }; diff --git a/packages/middleware-sdk-sqs/src/queue-url.spec.ts b/packages/middleware-sdk-sqs/src/queue-url.spec.ts index 7750ac3fa109..889fbe984c13 100644 --- a/packages/middleware-sdk-sqs/src/queue-url.spec.ts +++ b/packages/middleware-sdk-sqs/src/queue-url.spec.ts @@ -2,7 +2,7 @@ import { HttpRequest } from "@aws-sdk/protocol-http"; import { FinalizeHandlerArguments, HandlerExecutionContext } from "@aws-sdk/types"; import { afterEach, beforeEach, describe, expect, test as it, vi } from "vitest"; -import { queueUrlMiddleware } from "./queue-url"; +import { queueUrlMiddleware, resolveQueueUrlConfig } from "./queue-url"; describe("queueUrlMiddleware", () => { const mockNextHandler = vi.fn(); @@ -27,6 +27,13 @@ describe("queueUrlMiddleware", () => { vi.resetAllMocks(); }); + describe("config resolver", () => { + it("maintains object custody", () => { + const input = {}; + expect(resolveQueueUrlConfig(input)).toBe(input); + }); + }); + it("should use the QueueUrl hostname as the endpoint if useQueueUrlAsEndpoint is true", async () => { const middleware = queueUrlMiddleware({ useQueueUrlAsEndpoint: true }); const input = { QueueUrl: "https://xyz.com/123/MyQueue" }; diff --git a/packages/middleware-sdk-sqs/src/queue-url.ts b/packages/middleware-sdk-sqs/src/queue-url.ts index 659029b6a280..901960f751ff 100644 --- a/packages/middleware-sdk-sqs/src/queue-url.ts +++ b/packages/middleware-sdk-sqs/src/queue-url.ts @@ -36,10 +36,9 @@ export interface PreviouslyResolved { export const resolveQueueUrlConfig = ( config: T & PreviouslyResolved & QueueUrlInputConfig ): T & QueueUrlResolvedConfig => { - return { - ...config, + return Object.assign(config, { useQueueUrlAsEndpoint: config.useQueueUrlAsEndpoint ?? true, - }; + }); }; /** diff --git a/packages/middleware-sdk-sts/src/index.ts b/packages/middleware-sdk-sts/src/index.ts index b2c43704182c..436d83603525 100644 --- a/packages/middleware-sdk-sts/src/index.ts +++ b/packages/middleware-sdk-sts/src/index.ts @@ -47,8 +47,10 @@ export interface StsAuthConfigOptions { export const resolveStsAuthConfig = ( input: T & PreviouslyResolved & StsAuthInputConfig, { stsClientCtor }: StsAuthConfigOptions -): T & StsAuthResolvedConfig => - resolveAwsAuthConfig({ - ...input, - stsClientCtor, - }); +): T & StsAuthResolvedConfig => { + return resolveAwsAuthConfig( + Object.assign(input, { + stsClientCtor, + }) + ); +}; diff --git a/packages/middleware-sdk-sts/src/middleware-sdk-sts.integ.spec.ts b/packages/middleware-sdk-sts/src/middleware-sdk-sts.integ.spec.ts index bf0618073200..61a1932f5258 100644 --- a/packages/middleware-sdk-sts/src/middleware-sdk-sts.integ.spec.ts +++ b/packages/middleware-sdk-sts/src/middleware-sdk-sts.integ.spec.ts @@ -1,6 +1,8 @@ import { STS, STSClient } from "@aws-sdk/client-sts"; import { describe, expect, test as it } from "vitest"; +import { resolveStsAuthConfig } from "./index"; + describe("middleware-sdk-sts", () => { describe(STS.name, () => { it("sets the sts constructor in config", async () => { @@ -10,5 +12,13 @@ describe("middleware-sdk-sts", () => { expect(client.config.stsClientCtor).toBe(STSClient); }); + + it("maintains object custody", () => { + const client = new STS({ + region: "us-west-2", + }); + const input = client.config; + expect(resolveStsAuthConfig(input, { stsClientCtor: STSClient })).toBe(input); + }); }); }); diff --git a/packages/middleware-signing/src/awsAuthConfiguration.spec.ts b/packages/middleware-signing/src/awsAuthConfiguration.spec.ts index 1423d1b3de85..aa10fe8c3969 100644 --- a/packages/middleware-signing/src/awsAuthConfiguration.spec.ts +++ b/packages/middleware-signing/src/awsAuthConfiguration.spec.ts @@ -12,7 +12,7 @@ describe("AuthConfig", () => { }; describe("resolveAwsAuthConfig", () => { - const inputParams = { + const inputParams = () => ({ credentialDefaultProvider: () => () => Promise.resolve({ accessKeyId: "key", secretAccessKey: "secret" }), region: vi.fn().mockImplementation(() => Promise.resolve("us-foo-1")), regionInfoProvider: () => Promise.resolve({ hostname: "foo.com", partition: "aws" }), @@ -24,27 +24,29 @@ describe("AuthConfig", () => { credentials: vi.fn().mockResolvedValue({ accessKeyId: "key", secretAccessKey: "secret" }), useFipsEndpoint: () => Promise.resolve(false), useDualstackEndpoint: () => Promise.resolve(false), - }; + }); beforeEach(() => { vi.clearAllMocks(); }); it("should memoize custom credential provider", async () => { - const { signer: signerProvider } = resolveAwsAuthConfig(inputParams); + const input = inputParams(); + const spy = input.credentials; + const { signer: signerProvider } = resolveAwsAuthConfig(input); const signer = await signerProvider(authScheme); const request = new HttpRequest({}); const repeats = 10; for (let i = 0; i < repeats; i++) { await signer.sign(request); } - expect(inputParams.credentials).toBeCalledTimes(1); + expect(spy).toBeCalledTimes(1); }); it("should refresh custom credential provider if expired", async () => { const FOUR_MINUTES_AND_59_SEC = 299 * 1000; const input = { - ...inputParams, + ...inputParams(), credentials: vi .fn() .mockResolvedValueOnce({ @@ -54,6 +56,7 @@ describe("AuthConfig", () => { }) .mockResolvedValue({ accessKeyId: "key", secretAccessKey: "secret" }), }; + const spy = input.credentials; const { signer: signerProvider } = resolveAwsAuthConfig(input); const signer = await signerProvider(authScheme); const request = new HttpRequest({}); @@ -61,12 +64,12 @@ describe("AuthConfig", () => { for (let i = 0; i < repeats; i++) { await signer.sign(request); } - expect(input.credentials).toBeCalledTimes(2); + expect(spy).toBeCalledTimes(2); }); }); describe("resolveSigV4AuthConfig", () => { - const inputParams = { + const inputParams = () => ({ credentialDefaultProvider: () => () => Promise.resolve({ accessKeyId: "key", secretAccessKey: "secret" }), region: vi.fn().mockImplementation(() => Promise.resolve("us-foo-1")), signingName: "foo", @@ -75,27 +78,29 @@ describe("AuthConfig", () => { digest: vi.fn().mockReturnValue("SHA256 hash"), }), credentials: vi.fn().mockResolvedValue({ accessKeyId: "key", secretAccessKey: "secret" }), - }; + }); beforeEach(() => { vi.clearAllMocks(); }); it("should memoize custom credential provider", async () => { - const { signer: signerProvider } = resolveSigV4AuthConfig(inputParams); + const input = inputParams(); + const spy = input.credentials; + const { signer: signerProvider } = resolveSigV4AuthConfig(input); const signer = await signerProvider(authScheme); const request = new HttpRequest({}); const repeats = 10; for (let i = 0; i < repeats; i++) { await signer.sign(request); } - expect(inputParams.credentials).toBeCalledTimes(1); + expect(spy).toBeCalledTimes(1); }); it("should refresh custom credential provider if expired", async () => { const FOUR_MINUTES_AND_59_SEC = 299 * 1000; const input = { - ...inputParams, + ...inputParams(), credentials: vi .fn() .mockResolvedValueOnce({ @@ -105,14 +110,16 @@ describe("AuthConfig", () => { }) .mockResolvedValue({ accessKeyId: "key", secretAccessKey: "secret" }), }; - const { signer: signerProvider } = resolveSigV4AuthConfig(input); + const spy = input.credentials; + const { signer: signerProvider, credentials } = resolveSigV4AuthConfig(input); const signer = await signerProvider(authScheme); const request = new HttpRequest({}); const repeats = 10; for (let i = 0; i < repeats; i++) { await signer.sign(request); } - expect(input.credentials).toBeCalledTimes(2); + console.log("what is credentials", credentials); + expect(spy).toBeCalledTimes(2); }); }); }); diff --git a/packages/middleware-signing/src/awsAuthConfiguration.ts b/packages/middleware-signing/src/awsAuthConfiguration.ts index 010d55a5c1c4..1e8321804c48 100644 --- a/packages/middleware-signing/src/awsAuthConfiguration.ts +++ b/packages/middleware-signing/src/awsAuthConfiguration.ts @@ -246,13 +246,12 @@ export const resolveAwsAuthConfig = ( }; } - return { - ...input, + return Object.assign(input, { systemClockOffset, signingEscapePath, credentials: normalizedCreds, signer, - }; + }); }; /** @@ -279,13 +278,12 @@ export const resolveSigV4AuthConfig = ( }) ); } - return { - ...input, + return Object.assign(input, { systemClockOffset, signingEscapePath, credentials: normalizedCreds, signer, - }; + }); }; /** diff --git a/packages/middleware-token/src/resolveTokenConfig.spec.ts b/packages/middleware-token/src/resolveTokenConfig.spec.ts index 18ab6f5b5886..f10284e1b83d 100644 --- a/packages/middleware-token/src/resolveTokenConfig.spec.ts +++ b/packages/middleware-token/src/resolveTokenConfig.spec.ts @@ -21,6 +21,11 @@ describe(resolveTokenConfig.name, () => { vi.clearAllMocks(); }); + it("maintains object custody", () => { + const input = {}; + expect(resolveTokenConfig(input)).toBe(input); + }); + describe("sets token from normalizeTokenProvider if token is provided", () => { beforeEach(() => { vi.mocked(normalizeTokenProvider).mockReturnValue(mockOutputToken); diff --git a/packages/middleware-token/src/resolveTokenConfig.ts b/packages/middleware-token/src/resolveTokenConfig.ts index d783821f5b0f..cc45ba3baafe 100644 --- a/packages/middleware-token/src/resolveTokenConfig.ts +++ b/packages/middleware-token/src/resolveTokenConfig.ts @@ -5,7 +5,9 @@ import { tokenDefaultProvider } from "./tokenDefaultProvider"; /** * @internal */ -export const resolveTokenConfig = (input: T & TokenInputConfig): T & TokenResolvedConfig => ({ - ...input, - token: input.token ? normalizeTokenProvider(input.token) : tokenDefaultProvider(input as any), -}); +export const resolveTokenConfig = (input: T & TokenInputConfig): T & TokenResolvedConfig => { + const { token } = input; + return Object.assign(input, { + token: token ? normalizeTokenProvider(token) : tokenDefaultProvider(input as any), + }); +}; diff --git a/packages/middleware-user-agent/src/configurations.spec.ts b/packages/middleware-user-agent/src/configurations.spec.ts new file mode 100644 index 000000000000..7f433b5c1772 --- /dev/null +++ b/packages/middleware-user-agent/src/configurations.spec.ts @@ -0,0 +1,13 @@ +import { describe, expect, test as it } from "vitest"; + +import { resolveUserAgentConfig } from "./configurations"; + +describe(resolveUserAgentConfig.name, () => { + it("maintains object custody", () => { + const input = { + defaultUserAgentProvider: async () => [["", ""] as [string, string?]], + runtime: "node", + }; + expect(resolveUserAgentConfig(input)).toBe(input); + }); +}); diff --git a/packages/middleware-user-agent/src/configurations.ts b/packages/middleware-user-agent/src/configurations.ts index af973ba931d5..654c8e781b24 100644 --- a/packages/middleware-user-agent/src/configurations.ts +++ b/packages/middleware-user-agent/src/configurations.ts @@ -57,9 +57,11 @@ export function resolveUserAgentConfig( input: T & PreviouslyResolved & UserAgentInputConfig ): T & UserAgentResolvedConfig { const normalizedAppIdProvider = normalizeProvider(input.userAgentAppId ?? DEFAULT_UA_APP_ID); - return { - ...input, - customUserAgent: typeof input.customUserAgent === "string" ? [[input.customUserAgent]] : input.customUserAgent, + const { customUserAgent } = input; + + return Object.assign(input, { + customUserAgent: + typeof customUserAgent === "string" ? ([[customUserAgent]] as [string, string?][]) : customUserAgent, userAgentAppId: async () => { const appId = await normalizedAppIdProvider(); if (!isValidUserAgentAppId(appId)) { @@ -72,5 +74,5 @@ export function resolveUserAgentConfig( } return appId; }, - }; + }); } diff --git a/packages/middleware-websocket/src/websocket-configuration.spec.ts b/packages/middleware-websocket/src/websocket-configuration.spec.ts new file mode 100644 index 000000000000..a5c75d07eb71 --- /dev/null +++ b/packages/middleware-websocket/src/websocket-configuration.spec.ts @@ -0,0 +1,13 @@ +import { describe, expect, test as it, vi } from "vitest"; + +import { resolveWebSocketConfig } from "./websocket-configuration"; + +describe(resolveWebSocketConfig.name, () => { + it("maintains object custody", () => { + const input = { + signer: vi.fn(), + requestHandler: vi.mocked(vi.fn()) as any, + }; + expect(resolveWebSocketConfig(input)).toBe(input); + }); +}); diff --git a/packages/middleware-websocket/src/websocket-configuration.ts b/packages/middleware-websocket/src/websocket-configuration.ts index 189483cd4784..ca1976338123 100644 --- a/packages/middleware-websocket/src/websocket-configuration.ts +++ b/packages/middleware-websocket/src/websocket-configuration.ts @@ -26,15 +26,18 @@ export interface WebSocketResolvedConfig { export const resolveWebSocketConfig = ( input: T & WebSocketInputConfig & PreviouslyResolved -): T & WebSocketResolvedConfig => ({ - ...input, - signer: async (authScheme: AuthScheme) => { - const signerObj = await input.signer(authScheme); - if (validateSigner(signerObj)) { - return new WebsocketSignatureV4({ signer: signerObj }); - } - throw new Error("Expected WebsocketSignatureV4 signer, please check the client constructor."); - }, -}); +): T & WebSocketResolvedConfig => { + const { signer } = input; + + return Object.assign(input, { + signer: async (authScheme: AuthScheme) => { + const signerObj = await signer(authScheme); + if (validateSigner(signerObj)) { + return new WebsocketSignatureV4({ signer: signerObj }); + } + throw new Error("Expected WebsocketSignatureV4 signer, please check the client constructor."); + }, + }); +}; const validateSigner = (signer: any): signer is BaseSignatureV4 => !!signer; diff --git a/packages/region-config-resolver/src/extensions/index.ts b/packages/region-config-resolver/src/extensions/index.ts index 27c40a409f60..c37b5fd1e235 100644 --- a/packages/region-config-resolver/src/extensions/index.ts +++ b/packages/region-config-resolver/src/extensions/index.ts @@ -7,23 +7,12 @@ export type RegionExtensionRuntimeConfigType = Partial<{ region: string | Provid * @internal */ export const getAwsRegionExtensionConfiguration = (runtimeConfig: RegionExtensionRuntimeConfigType) => { - let runtimeConfigRegion: Provider = async () => { - if (runtimeConfig.region === undefined) { - throw new Error("Region is missing from runtimeConfig"); - } - const region = runtimeConfig.region!; - if (typeof region === "string") { - return region; - } - return region(); - }; - return { setRegion(region: Provider): void { - runtimeConfigRegion = region; + runtimeConfig.region = region; }, region(): Provider { - return runtimeConfigRegion; + return runtimeConfig.region as Provider; }, }; }; diff --git a/packages/region-config-resolver/src/regionConfig/resolveRegionConfig.spec.ts b/packages/region-config-resolver/src/regionConfig/resolveRegionConfig.spec.ts index b3aef695b8ff..599819ef750f 100644 --- a/packages/region-config-resolver/src/regionConfig/resolveRegionConfig.spec.ts +++ b/packages/region-config-resolver/src/regionConfig/resolveRegionConfig.spec.ts @@ -22,6 +22,13 @@ describe("RegionConfig", () => { vi.clearAllMocks(); }); + it("maintains object custody", () => { + const input = { + region: "mockRegion", + }; + expect(resolveRegionConfig(input)).toBe(input); + }); + describe("region", () => { it("return normalized value with real region if passed as a string", async () => { const resolvedRegionConfig = resolveRegionConfig({ region: mockRegion, useFipsEndpoint: mockUseFipsEndpoint }); diff --git a/packages/region-config-resolver/src/regionConfig/resolveRegionConfig.ts b/packages/region-config-resolver/src/regionConfig/resolveRegionConfig.ts index d1ee3c8561b1..a062736b8967 100644 --- a/packages/region-config-resolver/src/regionConfig/resolveRegionConfig.ts +++ b/packages/region-config-resolver/src/regionConfig/resolveRegionConfig.ts @@ -48,8 +48,7 @@ export const resolveRegionConfig = (input: T & RegionInputConfig & Previously throw new Error("Region is missing"); } - return { - ...input, + return Object.assign(input, { region: async () => { if (typeof region === "string") { return getRealRegion(region); @@ -64,5 +63,5 @@ export const resolveRegionConfig = (input: T & RegionInputConfig & Previously } return typeof useFipsEndpoint !== "function" ? Promise.resolve(!!useFipsEndpoint) : useFipsEndpoint(); }, - }; + }); };