From 4f805e3efa9682c8ac374c68b5d2a6e72dd29ff1 Mon Sep 17 00:00:00 2001
From: rddimon <rddimon@gmail.com>
Date: Tue, 6 Feb 2024 15:40:52 +0200
Subject: [PATCH 1/8] AT-11105: $default stage for the HTTP api and default
 base path https://amplify-education.atlassian.net/browse/AT-11105

---
 CHANGELOG.md                                  |  5 ++
 dependabot.yml                                |  6 --
 package-lock.json                             | 66 ++++++++-----------
 package.json                                  |  2 +-
 src/models/domain-config.ts                   |  8 +--
 test/integration-tests/debug/debug.test.ts    |  6 +-
 .../debug/pr-example/serverless.yml           | 21 +++---
 .../deploy/http-api/serverless.yml            |  2 +
 8 files changed, 52 insertions(+), 64 deletions(-)
 delete mode 100644 dependabot.yml

diff --git a/CHANGELOG.md b/CHANGELOG.md
index c66cf1c5..46b0b652 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
+## [7.3.5] - 2023-02-06
+
+### Fixed 
+- Hardcoded `$default` stage for the HTTP API and default base path. More info [here](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-stages.html)
+
 ## [7.3.4] - 2023-01-30
 
 ### Fixed 
diff --git a/dependabot.yml b/dependabot.yml
deleted file mode 100644
index aff82a10..00000000
--- a/dependabot.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-version: 2
-updates:
-  - package-ecosystem: "npm"
-    directory: "/"
-    schedule:
-      interval: "weekly"
diff --git a/package-lock.json b/package-lock.json
index a97d45bf..fa742fcb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "serverless-domain-manager",
-  "version": "7.3.3",
+  "version": "7.3.4",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "serverless-domain-manager",
-      "version": "7.3.3",
+      "version": "7.3.4",
       "license": "MIT",
       "dependencies": {
         "@aws-sdk/client-acm": "^3.460.0",
@@ -1709,18 +1709,6 @@
         "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
       }
     },
-    "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
-      "version": "3.4.3",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
-      "dev": true,
-      "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/eslint"
-      }
-    },
     "node_modules/@eslint-community/regexpp": {
       "version": "4.10.0",
       "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
@@ -1786,9 +1774,9 @@
       }
     },
     "node_modules/@eslint/eslintrc/node_modules/globals": {
-      "version": "13.23.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz",
-      "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==",
+      "version": "13.24.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+      "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
       "dev": true,
       "dependencies": {
         "type-fest": "^0.20.2"
@@ -3523,18 +3511,6 @@
         "url": "https://opencollective.com/typescript-eslint"
       }
     },
-    "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
-      "version": "3.4.3",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
-      "dev": true,
-      "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/eslint"
-      }
-    },
     "node_modules/2-thenable": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/2-thenable/-/2-thenable-1.0.0.tgz",
@@ -3558,9 +3534,9 @@
       }
     },
     "node_modules/acorn": {
-      "version": "8.8.2",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
-      "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+      "version": "8.11.3",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
+      "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
       "dev": true,
       "bin": {
         "acorn": "bin/acorn"
@@ -6001,12 +5977,15 @@
       }
     },
     "node_modules/eslint-visitor-keys": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
-      "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
       "dev": true,
       "engines": {
-        "node": ">=10"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
       }
     },
     "node_modules/eslint/node_modules/@babel/code-frame": {
@@ -6053,6 +6032,15 @@
         "concat-map": "0.0.1"
       }
     },
+    "node_modules/eslint/node_modules/eslint-visitor-keys": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+      "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/eslint/node_modules/globals": {
       "version": "13.23.0",
       "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz",
@@ -6121,9 +6109,9 @@
       }
     },
     "node_modules/eslint/node_modules/semver": {
-      "version": "7.5.4",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
-      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+      "version": "7.6.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
+      "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
       "dev": true,
       "dependencies": {
         "lru-cache": "^6.0.0"
diff --git a/package.json b/package.json
index bb66bf99..1dba3ebe 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "serverless-domain-manager",
-  "version": "7.3.4",
+  "version": "7.3.5",
   "engines": {
     "node": ">=14"
   },
diff --git a/src/models/domain-config.ts b/src/models/domain-config.ts
index 6eacdfd6..be5020e2 100644
--- a/src/models/domain-config.ts
+++ b/src/models/domain-config.ts
@@ -54,8 +54,8 @@ class DomainConfig {
     this.preserveExternalPathMappings = evaluateBoolean(config.preserveExternalPathMappings, false);
     this.basePath = DomainConfig._getBasePath(config.basePath);
     this.apiType = DomainConfig._getApiType(config.apiType);
-    // apiType should be defined before stage
-    this.stage = DomainConfig._getStage(config.stage, this.apiType);
+    // apiType and basePath should be defined before stage
+    this.stage = DomainConfig._getStage(config.stage, this.apiType, this.basePath);
     this.endpointType = DomainConfig._getEndpointType(config.endpointType);
     this.tlsTruststoreUri = DomainConfig._getTLSTruststoreUri(config.tlsTruststoreUri, this.endpointType);
     this.tlsTruststoreVersion = config.tlsTruststoreVersion;
@@ -64,8 +64,8 @@ class DomainConfig {
     this.splitHorizonDns = !this.hostedZoneId && !this.hostedZonePrivate && evaluateBoolean(config.splitHorizonDns, false);
   }
 
-  private static _getStage (stage: string, apiType: string) {
-    if (apiType === Globals.apiTypes.http && !stage) {
+  private static _getStage (stage: string, apiType: string, basePath: string) {
+    if (apiType === Globals.apiTypes.http && (basePath === Globals.defaultBasePath || !stage)) {
       return Globals.defaultStage;
     }
     return stage || Globals.getBaseStage();
diff --git a/test/integration-tests/debug/debug.test.ts b/test/integration-tests/debug/debug.test.ts
index 0c5d128a..75460106 100644
--- a/test/integration-tests/debug/debug.test.ts
+++ b/test/integration-tests/debug/debug.test.ts
@@ -1,6 +1,7 @@
 import "mocha";
 import utilities = require("../test-utilities");
 import { TEMP_DIR } from "../base";
+import { exec } from "../test-utilities";
 
 const CONFIGS_FOLDER = "debug";
 const TIMEOUT_MINUTES = 15 * 60 * 1000; // 15 minutes in milliseconds
@@ -14,10 +15,11 @@ describe("Integration Tests", function () {
 
     try {
       await utilities.createTempDir(TEMP_DIR, configFolder);
-      await utilities.slsCreateDomain(TEMP_DIR, true);
+      // await utilities.slsCreateDomain(TEMP_DIR, true);
       await utilities.slsDeploy(TEMP_DIR, true);
     } finally {
-      await utilities.destroyResources(testName);
+      await exec(`rm -rf ${TEMP_DIR}`);
+      // await utilities.destroyResources(testName);
     }
   });
 });
diff --git a/test/integration-tests/debug/pr-example/serverless.yml b/test/integration-tests/debug/pr-example/serverless.yml
index d16aa98e..24e20572 100644
--- a/test/integration-tests/debug/pr-example/serverless.yml
+++ b/test/integration-tests/debug/pr-example/serverless.yml
@@ -10,7 +10,7 @@ functions:
   helloWorld:
     handler: handler.helloWorld
     events:
-      - http:
+      - httpApi:
           path: /hello-world
           method: get
 
@@ -18,17 +18,14 @@ plugins:
   - serverless-domain-manager
 
 custom:
-  customDomains:
-    - rest:
-      autoDomain: true
-      basePath: "path1"
-      domainName: ${env:PLUGIN_IDENTIFIER}-rest-debug.${env:TEST_DOMAIN}
-      allowPathMatching: true
-    - rest:
-      autoDomain: true
-      basePath: "path2"
-      domainName: ${env:PLUGIN_IDENTIFIER}-rest-debug.${env:TEST_DOMAIN}
-      allowPathMatching: true
+  customDomain:
+    domainName: ${env:PLUGIN_IDENTIFIER}-pr-example.${env:TEST_DOMAIN}
+    basePath: ''
+    createRoute53Record: true
+    stage: 'production'
+    endpointType: 'regional'
+    apiType: http
+    autoDomain: true
 
 package:
   patterns:
diff --git a/test/integration-tests/deploy/http-api/serverless.yml b/test/integration-tests/deploy/http-api/serverless.yml
index 22123808..69755091 100644
--- a/test/integration-tests/deploy/http-api/serverless.yml
+++ b/test/integration-tests/deploy/http-api/serverless.yml
@@ -20,6 +20,8 @@ custom:
     domainName: ${env:PLUGIN_IDENTIFIER}-http-api-${env:RANDOM_STRING}.${env:TEST_DOMAIN}
     endpointType: REGIONAL
     apiType: http
+    # the stage should be set to $default for the base path (none)
+    stage: dummy_stage
 
 package:
   patterns:

From 12ff22be4276c52908afa757b4878fde0fb09b95 Mon Sep 17 00:00:00 2001
From: rddimon <rddimon@gmail.com>
Date: Tue, 6 Feb 2024 15:44:23 +0200
Subject: [PATCH 2/8] AT-11105: add sleep
 https://amplify-education.atlassian.net/browse/AT-11105

---
 src/aws/acm-wrapper.ts                   | 128 ++++-----
 src/aws/api-gateway-v1-wrapper.ts        | 250 ++++++++---------
 src/aws/api-gateway-v2-wrapper.ts        | 336 +++++++++++------------
 src/aws/cloud-formation-wrapper.ts       | 296 ++++++++++----------
 src/aws/route53-wrapper.ts               | 272 +++++++++---------
 src/aws/s3-wrapper.ts                    |  72 ++---
 test/integration-tests/test-utilities.ts |   5 +-
 7 files changed, 681 insertions(+), 678 deletions(-)

diff --git a/src/aws/acm-wrapper.ts b/src/aws/acm-wrapper.ts
index 7d8ea72f..2ec21b67 100644
--- a/src/aws/acm-wrapper.ts
+++ b/src/aws/acm-wrapper.ts
@@ -18,81 +18,81 @@ const certStatuses = [
 ];
 
 class ACMWrapper {
-    public acm: ACMClient;
+  public acm: ACMClient;
 
-    constructor (credentials: any, endpointType: string) {
-      const isEdge = endpointType === Globals.endpointTypes.edge;
-      this.acm = new ACMClient({
-        credentials,
-        region: isEdge ? Globals.defaultRegion : Globals.getRegion(),
-        retryStrategy: Globals.getRetryStrategy(),
-        requestHandler: Globals.getRequestHandler()
-      });
-    }
+  constructor (credentials: any, endpointType: string) {
+    const isEdge = endpointType === Globals.endpointTypes.edge;
+    this.acm = new ACMClient({
+      credentials,
+      region: isEdge ? Globals.defaultRegion : Globals.getRegion(),
+      retryStrategy: Globals.getRetryStrategy(),
+      requestHandler: Globals.getRequestHandler()
+    });
+  }
 
-    public async getCertArn (domain: DomainConfig): Promise<string> {
-      let certificateArn; // The arn of the selected certificate
-      let certificateName = domain.certificateName; // The certificate name
+  public async getCertArn (domain: DomainConfig): Promise<string> {
+    let certificateArn; // The arn of the selected certificate
+    let certificateName = domain.certificateName; // The certificate name
 
-      try {
-        const certificates = await getAWSPagedResults<CertificateSummary, ListCertificatesCommandInput, ListCertificatesCommandOutput>(
-          this.acm,
-          "CertificateSummaryList",
-          "NextToken",
-          "NextToken",
-          new ListCertificatesCommand({ CertificateStatuses: certStatuses })
-        );
-        // enhancement idea: weight the choice of cert so longer expires
-        // and RenewalEligibility = ELIGIBLE is more preferable
-        if (certificateName) {
-          certificateArn = this.getCertArnByCertName(certificates, certificateName);
-        } else {
-          certificateName = domain.givenDomainName;
-          certificateArn = ACMWrapper.getCertArnByDomainName(certificates, certificateName);
-        }
-        Logging.logInfo(`Found a certificate ARN: '${certificateArn}'`);
-      } catch (err) {
-        throw Error(`Could not search certificates in Certificate Manager.\n${err.message}`);
-      }
-      if (certificateArn == null) {
-        throw Error(`Could not find an in-date certificate for '${certificateName}'.`);
+    try {
+      const certificates = await getAWSPagedResults<CertificateSummary, ListCertificatesCommandInput, ListCertificatesCommandOutput>(
+        this.acm,
+        "CertificateSummaryList",
+        "NextToken",
+        "NextToken",
+        new ListCertificatesCommand({ CertificateStatuses: certStatuses })
+      );
+      // enhancement idea: weight the choice of cert so longer expires
+      // and RenewalEligibility = ELIGIBLE is more preferable
+      if (certificateName) {
+        certificateArn = this.getCertArnByCertName(certificates, certificateName);
+      } else {
+        certificateName = domain.givenDomainName;
+        certificateArn = ACMWrapper.getCertArnByDomainName(certificates, certificateName);
       }
-      return certificateArn;
+      Logging.logInfo(`Found a certificate ARN: '${certificateArn}'`);
+    } catch (err) {
+      throw Error(`Could not search certificates in Certificate Manager.\n${err.message}`);
     }
+    if (certificateArn == null) {
+      throw Error(`Could not find an in-date certificate for '${certificateName}'.`);
+    }
+    return certificateArn;
+  }
 
-    private getCertArnByCertName (certificates, certName): string {
-      const found = certificates.find((c) => c.DomainName === certName);
-      if (found) {
-        return found.CertificateArn;
-      }
-      return null;
+  private getCertArnByCertName (certificates, certName): string {
+    const found = certificates.find((c) => c.DomainName === certName);
+    if (found) {
+      return found.CertificateArn;
     }
+    return null;
+  }
 
-    private static getCertArnByDomainName (certificates, domainName): string {
-      // The more specific name will be the longest
-      let nameLength = 0;
-      let certificateArn;
-      for (const currCert of certificates) {
-        const allDomainsForCert = [
-          currCert.DomainName,
-          ...(currCert.SubjectAlternativeNameSummaries || [])
-        ];
-        for (const currCertDomain of allDomainsForCert) {
-          let certificateListName = currCertDomain;
-          // Looks for wild card and take it out when checking
-          if (certificateListName[0] === "*") {
-            certificateListName = certificateListName.substring(1);
-          }
-          // Looks to see if the name in the list is within the given domain
-          // Also checks if the name is more specific than previous ones
-          if (domainName.includes(certificateListName) && certificateListName.length > nameLength) {
-            nameLength = certificateListName.length;
-            certificateArn = currCert.CertificateArn;
-          }
+  private static getCertArnByDomainName (certificates, domainName): string {
+    // The more specific name will be the longest
+    let nameLength = 0;
+    let certificateArn;
+    for (const currCert of certificates) {
+      const allDomainsForCert = [
+        currCert.DomainName,
+        ...(currCert.SubjectAlternativeNameSummaries || [])
+      ];
+      for (const currCertDomain of allDomainsForCert) {
+        let certificateListName = currCertDomain;
+        // Looks for wild card and take it out when checking
+        if (certificateListName[0] === "*") {
+          certificateListName = certificateListName.substring(1);
+        }
+        // Looks to see if the name in the list is within the given domain
+        // Also checks if the name is more specific than previous ones
+        if (domainName.includes(certificateListName) && certificateListName.length > nameLength) {
+          nameLength = certificateListName.length;
+          certificateArn = currCert.CertificateArn;
         }
       }
-      return certificateArn;
     }
+    return certificateArn;
+  }
 }
 
 export = ACMWrapper;
diff --git a/src/aws/api-gateway-v1-wrapper.ts b/src/aws/api-gateway-v1-wrapper.ts
index b4f86fdf..11b5450e 100644
--- a/src/aws/api-gateway-v1-wrapper.ts
+++ b/src/aws/api-gateway-v1-wrapper.ts
@@ -25,137 +25,137 @@ import Logging from "../logging";
 import { getAWSPagedResults } from "../utils";
 
 class APIGatewayV1Wrapper extends APIGatewayBase {
-    public readonly apiGateway: APIGatewayClient;
+  public readonly apiGateway: APIGatewayClient;
 
-    constructor (credentials?: any) {
-      super();
-      this.apiGateway = new APIGatewayClient({
-        credentials,
-        region: Globals.getRegion(),
-        retryStrategy: Globals.getRetryStrategy(),
-        requestHandler: Globals.getRequestHandler()
-      });
-    }
+  constructor (credentials?: any) {
+    super();
+    this.apiGateway = new APIGatewayClient({
+      credentials,
+      region: Globals.getRegion(),
+      retryStrategy: Globals.getRetryStrategy(),
+      requestHandler: Globals.getRequestHandler()
+    });
+  }
 
-    public async createCustomDomain (domain: DomainConfig): Promise<DomainInfo> {
-      const providerTags = {
-        ...Globals.serverless.service.provider.stackTags,
-        ...Globals.serverless.service.provider.tags
-      };
+  public async createCustomDomain (domain: DomainConfig): Promise<DomainInfo> {
+    const providerTags = {
+      ...Globals.serverless.service.provider.stackTags,
+      ...Globals.serverless.service.provider.tags
+    };
 
-      const params: any = {
-        domainName: domain.givenDomainName,
-        endpointConfiguration: {
-          types: [domain.endpointType]
-        },
-        securityPolicy: domain.securityPolicy,
-        tags: providerTags
-      };
+    const params: any = {
+      domainName: domain.givenDomainName,
+      endpointConfiguration: {
+        types: [domain.endpointType]
+      },
+      securityPolicy: domain.securityPolicy,
+      tags: providerTags
+    };
 
-      const isEdgeType = domain.endpointType === Globals.endpointTypes.edge;
-      if (isEdgeType) {
-        params.certificateArn = domain.certificateArn;
-      } else {
-        params.regionalCertificateArn = domain.certificateArn;
+    const isEdgeType = domain.endpointType === Globals.endpointTypes.edge;
+    if (isEdgeType) {
+      params.certificateArn = domain.certificateArn;
+    } else {
+      params.regionalCertificateArn = domain.certificateArn;
 
-        if (domain.tlsTruststoreUri) {
-          params.mutualTlsAuthentication = {
-            truststoreUri: domain.tlsTruststoreUri
-          };
+      if (domain.tlsTruststoreUri) {
+        params.mutualTlsAuthentication = {
+          truststoreUri: domain.tlsTruststoreUri
+        };
 
-          if (domain.tlsTruststoreVersion) {
-            params.mutualTlsAuthentication.truststoreVersion = domain.tlsTruststoreVersion;
-          }
+        if (domain.tlsTruststoreVersion) {
+          params.mutualTlsAuthentication.truststoreVersion = domain.tlsTruststoreVersion;
         }
       }
+    }
 
-      try {
-        const domainInfo: CreateDomainNameCommandOutput = await this.apiGateway.send(
-          new CreateDomainNameCommand(params)
-        );
-        return new DomainInfo(domainInfo);
-      } catch (err) {
-        throw new Error(
-                `V1 - Failed to create custom domain '${domain.givenDomainName}':\n${err.message}`
-        );
-      }
+    try {
+      const domainInfo: CreateDomainNameCommandOutput = await this.apiGateway.send(
+        new CreateDomainNameCommand(params)
+      );
+      return new DomainInfo(domainInfo);
+    } catch (err) {
+      throw new Error(
+        `V1 - Failed to create custom domain '${domain.givenDomainName}':\n${err.message}`
+      );
     }
+  }
 
-    public async getCustomDomain (domain: DomainConfig): Promise<DomainInfo> {
-      // Make API call
-      try {
-        const domainInfo: GetDomainNameCommandOutput = await this.apiGateway.send(
-          new GetDomainNameCommand({
-            domainName: domain.givenDomainName
-          })
+  public async getCustomDomain (domain: DomainConfig): Promise<DomainInfo> {
+    // Make API call
+    try {
+      const domainInfo: GetDomainNameCommandOutput = await this.apiGateway.send(
+        new GetDomainNameCommand({
+          domainName: domain.givenDomainName
+        })
+      );
+      return new DomainInfo(domainInfo);
+    } catch (err) {
+      if (!err.$metadata || err.$metadata.httpStatusCode !== 404) {
+        throw new Error(
+          `V1 - Unable to fetch information about '${domain.givenDomainName}':\n${err.message}`
         );
-        return new DomainInfo(domainInfo);
-      } catch (err) {
-        if (!err.$metadata || err.$metadata.httpStatusCode !== 404) {
-          throw new Error(
-                    `V1 - Unable to fetch information about '${domain.givenDomainName}':\n${err.message}`
-          );
-        }
-        Logging.logWarning(`V1 - '${domain.givenDomainName}' does not exist.`);
       }
+      Logging.logWarning(`V1 - '${domain.givenDomainName}' does not exist.`);
     }
+  }
 
-    public async deleteCustomDomain (domain: DomainConfig): Promise<void> {
-      // Make API call
-      try {
-        await this.apiGateway.send(new DeleteDomainNameCommand({
-          domainName: domain.givenDomainName
-        }));
-      } catch (err) {
-        throw new Error(`V1 - Failed to delete custom domain '${domain.givenDomainName}':\n${err.message}`);
-      }
+  public async deleteCustomDomain (domain: DomainConfig): Promise<void> {
+    // Make API call
+    try {
+      await this.apiGateway.send(new DeleteDomainNameCommand({
+        domainName: domain.givenDomainName
+      }));
+    } catch (err) {
+      throw new Error(`V1 - Failed to delete custom domain '${domain.givenDomainName}':\n${err.message}`);
     }
+  }
 
-    public async createBasePathMapping (domain: DomainConfig): Promise<void> {
-      try {
-        await this.apiGateway.send(new CreateBasePathMappingCommand({
-          basePath: domain.basePath,
-          domainName: domain.givenDomainName,
-          restApiId: domain.apiId,
-          stage: domain.stage
-        }));
-        Logging.logInfo(`V1 - Created API mapping '${domain.basePath}' for '${domain.givenDomainName}'`);
-      } catch (err) {
-        throw new Error(
-                `V1 - Make sure the '${domain.givenDomainName}' exists.
+  public async createBasePathMapping (domain: DomainConfig): Promise<void> {
+    try {
+      await this.apiGateway.send(new CreateBasePathMappingCommand({
+        basePath: domain.basePath,
+        domainName: domain.givenDomainName,
+        restApiId: domain.apiId,
+        stage: domain.stage
+      }));
+      Logging.logInfo(`V1 - Created API mapping '${domain.basePath}' for '${domain.givenDomainName}'`);
+    } catch (err) {
+      throw new Error(
+        `V1 - Make sure the '${domain.givenDomainName}' exists.
                  Unable to create base path mapping for '${domain.givenDomainName}':\n${err.message}`
-        );
-      }
+      );
     }
+  }
 
-    public async getBasePathMappings (domain: DomainConfig): Promise<ApiGatewayMap[]> {
-      try {
-        const items = await getAWSPagedResults<BasePathMapping, GetBasePathMappingsCommandInput, GetBasePathMappingsCommandOutput>(
-          this.apiGateway,
-          "items",
-          "position",
-          "position",
-          new GetBasePathMappingsCommand({
-            domainName: domain.givenDomainName
-          })
-        );
-        return items.map((item) => {
+  public async getBasePathMappings (domain: DomainConfig): Promise<ApiGatewayMap[]> {
+    try {
+      const items = await getAWSPagedResults<BasePathMapping, GetBasePathMappingsCommandInput, GetBasePathMappingsCommandOutput>(
+        this.apiGateway,
+        "items",
+        "position",
+        "position",
+        new GetBasePathMappingsCommand({
+          domainName: domain.givenDomainName
+        })
+      );
+      return items.map((item) => {
           return new ApiGatewayMap(item.restApiId, item.basePath, item.stage, null);
         }
-        );
-      } catch (err) {
-        throw new Error(
-                `V1 - Make sure the '${domain.givenDomainName}' exists.
+      );
+    } catch (err) {
+      throw new Error(
+        `V1 - Make sure the '${domain.givenDomainName}' exists.
                  Unable to get Base Path Mappings:\n${err.message}`
-        );
-      }
+      );
     }
+  }
 
-    public async updateBasePathMapping (domain: DomainConfig): Promise<void> {
-      Logging.logInfo(`V1 - Updating API mapping from '${domain.apiMapping.basePath}'
+  public async updateBasePathMapping (domain: DomainConfig): Promise<void> {
+    Logging.logInfo(`V1 - Updating API mapping from '${domain.apiMapping.basePath}'
             to '${domain.basePath}' for '${domain.givenDomainName}'`);
-      try {
-        await this.apiGateway.send(new UpdateBasePathMappingCommand({
+    try {
+      await this.apiGateway.send(new UpdateBasePathMappingCommand({
           basePath: domain.apiMapping.basePath,
           domainName: domain.givenDomainName,
           patchOperations: [{
@@ -164,29 +164,29 @@ class APIGatewayV1Wrapper extends APIGatewayBase {
             value: domain.basePath
           }]
         }
-        ));
-      } catch (err) {
-        throw new Error(
-          `V1 - Unable to update base path mapping for '${domain.givenDomainName}':\n${err.message}`
-        );
-      }
+      ));
+    } catch (err) {
+      throw new Error(
+        `V1 - Unable to update base path mapping for '${domain.givenDomainName}':\n${err.message}`
+      );
     }
+  }
 
-    public async deleteBasePathMapping (domain: DomainConfig): Promise<void> {
-      try {
-        await this.apiGateway.send(
-          new DeleteBasePathMappingCommand({
-            basePath: domain.apiMapping.basePath,
-            domainName: domain.givenDomainName
-          })
-        );
-        Logging.logInfo(`V1 - Removed '${domain.apiMapping.basePath}' base path mapping`);
-      } catch (err) {
-        throw new Error(
-                `V1 - Unable to remove base path mapping for '${domain.givenDomainName}':\n${err.message}`
-        );
-      }
+  public async deleteBasePathMapping (domain: DomainConfig): Promise<void> {
+    try {
+      await this.apiGateway.send(
+        new DeleteBasePathMappingCommand({
+          basePath: domain.apiMapping.basePath,
+          domainName: domain.givenDomainName
+        })
+      );
+      Logging.logInfo(`V1 - Removed '${domain.apiMapping.basePath}' base path mapping`);
+    } catch (err) {
+      throw new Error(
+        `V1 - Unable to remove base path mapping for '${domain.givenDomainName}':\n${err.message}`
+      );
     }
+  }
 }
 
 export = APIGatewayV1Wrapper;
diff --git a/src/aws/api-gateway-v2-wrapper.ts b/src/aws/api-gateway-v2-wrapper.ts
index fa761b64..7dc58bf9 100644
--- a/src/aws/api-gateway-v2-wrapper.ts
+++ b/src/aws/api-gateway-v2-wrapper.ts
@@ -25,197 +25,197 @@ import Logging from "../logging";
 import { getAWSPagedResults } from "../utils";
 
 class APIGatewayV2Wrapper extends APIGatewayBase {
-    public readonly apiGateway: ApiGatewayV2Client;
+  public readonly apiGateway: ApiGatewayV2Client;
 
-    constructor (credentials?: any) {
-      super();
-      this.apiGateway = new ApiGatewayV2Client({
-        credentials,
-        region: Globals.getRegion(),
-        retryStrategy: Globals.getRetryStrategy(),
-        requestHandler: Globals.getRequestHandler()
-      });
-    }
+  constructor (credentials?: any) {
+    super();
+    this.apiGateway = new ApiGatewayV2Client({
+      credentials,
+      region: Globals.getRegion(),
+      retryStrategy: Globals.getRetryStrategy(),
+      requestHandler: Globals.getRequestHandler()
+    });
+  }
 
-    /**
-     * Creates Custom Domain Name
-     * @param domain: DomainConfig
-     */
-    public async createCustomDomain (domain: DomainConfig): Promise<DomainInfo> {
-      const providerTags = {
-        ...Globals.serverless.service.provider.stackTags,
-        ...Globals.serverless.service.provider.tags
-      };
+  /**
+   * Creates Custom Domain Name
+   * @param domain: DomainConfig
+   */
+  public async createCustomDomain (domain: DomainConfig): Promise<DomainInfo> {
+    const providerTags = {
+      ...Globals.serverless.service.provider.stackTags,
+      ...Globals.serverless.service.provider.tags
+    };
 
-      const params: any = {
-        DomainName: domain.givenDomainName,
-        DomainNameConfigurations: [{
-          CertificateArn: domain.certificateArn,
-          EndpointType: domain.endpointType,
-          SecurityPolicy: domain.securityPolicy
-        }],
-        Tags: providerTags
-      };
+    const params: any = {
+      DomainName: domain.givenDomainName,
+      DomainNameConfigurations: [{
+        CertificateArn: domain.certificateArn,
+        EndpointType: domain.endpointType,
+        SecurityPolicy: domain.securityPolicy
+      }],
+      Tags: providerTags
+    };
 
-      const isEdgeType = domain.endpointType === Globals.endpointTypes.edge;
-      if (!isEdgeType && domain.tlsTruststoreUri) {
-        params.MutualTlsAuthentication = {
-          TruststoreUri: domain.tlsTruststoreUri
-        };
-
-        if (domain.tlsTruststoreVersion) {
-          params.MutualTlsAuthentication.TruststoreVersion = domain.tlsTruststoreVersion;
-        }
-      }
+    const isEdgeType = domain.endpointType === Globals.endpointTypes.edge;
+    if (!isEdgeType && domain.tlsTruststoreUri) {
+      params.MutualTlsAuthentication = {
+        TruststoreUri: domain.tlsTruststoreUri
+      };
 
-      try {
-        const domainInfo: CreateDomainNameCommandOutput = await this.apiGateway.send(
-          new CreateDomainNameCommand(params)
-        );
-        return new DomainInfo(domainInfo);
-      } catch (err) {
-        throw new Error(
-                `V2 - Failed to create custom domain '${domain.givenDomainName}':\n${err.message}`
-        );
+      if (domain.tlsTruststoreVersion) {
+        params.MutualTlsAuthentication.TruststoreVersion = domain.tlsTruststoreVersion;
       }
     }
 
-    /**
-     * Get Custom Domain Info
-     * @param domain: DomainConfig
-     */
-    public async getCustomDomain (domain: DomainConfig): Promise<DomainInfo> {
-      // Make API call
-      try {
-        const domainInfo: GetDomainNameCommandOutput = await this.apiGateway.send(
-          new GetDomainNameCommand({
-            DomainName: domain.givenDomainName
-          })
-        );
-        return new DomainInfo(domainInfo);
-      } catch (err) {
-        if (!err.$metadata || err.$metadata.httpStatusCode !== 404) {
-          throw new Error(
-                    `V2 - Unable to fetch information about '${domain.givenDomainName}':\n${err.message}`
-          );
-        }
-        Logging.logInfo(`V2 - '${domain.givenDomainName}' does not exist.`);
-      }
+    try {
+      const domainInfo: CreateDomainNameCommandOutput = await this.apiGateway.send(
+        new CreateDomainNameCommand(params)
+      );
+      return new DomainInfo(domainInfo);
+    } catch (err) {
+      throw new Error(
+        `V2 - Failed to create custom domain '${domain.givenDomainName}':\n${err.message}`
+      );
     }
+  }
 
-    /**
-     * Delete Custom Domain Name
-     * @param domain: DomainConfig
-     */
-    public async deleteCustomDomain (domain: DomainConfig): Promise<void> {
-      // Make API call
-      try {
-        await this.apiGateway.send(
-          new DeleteDomainNameCommand({
-            DomainName: domain.givenDomainName
-          })
-        );
-      } catch (err) {
+  /**
+   * Get Custom Domain Info
+   * @param domain: DomainConfig
+   */
+  public async getCustomDomain (domain: DomainConfig): Promise<DomainInfo> {
+    // Make API call
+    try {
+      const domainInfo: GetDomainNameCommandOutput = await this.apiGateway.send(
+        new GetDomainNameCommand({
+          DomainName: domain.givenDomainName
+        })
+      );
+      return new DomainInfo(domainInfo);
+    } catch (err) {
+      if (!err.$metadata || err.$metadata.httpStatusCode !== 404) {
         throw new Error(
-                `V2 - Failed to delete custom domain '${domain.givenDomainName}':\n${err.message}`
+          `V2 - Unable to fetch information about '${domain.givenDomainName}':\n${err.message}`
         );
       }
+      Logging.logInfo(`V2 - '${domain.givenDomainName}' does not exist.`);
     }
+  }
 
-    /**
-     * Create Base Path Mapping
-     * @param domain: DomainConfig
-     */
-    public async createBasePathMapping (domain: DomainConfig): Promise<void> {
-      if (domain.apiType === Globals.apiTypes.http && domain.stage !== Globals.defaultStage) {
-        Logging.logWarning(
-                `Using a HTTP API with a stage name other than '${Globals.defaultStage}'. ` +
-                `HTTP APIs require a stage named '${Globals.defaultStage}'. ` +
-                "Please make sure that stage exists in the API Gateway. " +
-                "See https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-stages.html"
-        );
-      }
-      try {
-        await this.apiGateway.send(
-          new CreateApiMappingCommand({
-            ApiId: domain.apiId,
-            ApiMappingKey: domain.basePath,
-            DomainName: domain.givenDomainName,
-            Stage: domain.stage
-          })
-        );
-        Logging.logInfo(`V2 - Created API mapping '${domain.basePath}' for '${domain.givenDomainName}'`);
-      } catch (err) {
-        throw new Error(
-                `V2 - Unable to create base path mapping for '${domain.givenDomainName}':\n${err.message}`
-        );
-      }
+  /**
+   * Delete Custom Domain Name
+   * @param domain: DomainConfig
+   */
+  public async deleteCustomDomain (domain: DomainConfig): Promise<void> {
+    // Make API call
+    try {
+      await this.apiGateway.send(
+        new DeleteDomainNameCommand({
+          DomainName: domain.givenDomainName
+        })
+      );
+    } catch (err) {
+      throw new Error(
+        `V2 - Failed to delete custom domain '${domain.givenDomainName}':\n${err.message}`
+      );
     }
+  }
 
-    /**
-     * Get APi Mapping
-     * @param domain: DomainConfig
-     */
-    public async getBasePathMappings (domain: DomainConfig): Promise<ApiGatewayMap[]> {
-      try {
-        const items = await getAWSPagedResults<ApiMapping, GetApiMappingsCommandInput, GetApiMappingsCommandOutput>(
-          this.apiGateway,
-          "Items",
-          "NextToken",
-          "NextToken",
-          new GetApiMappingsCommand({
-            DomainName: domain.givenDomainName
-          })
-        );
-        return items.map(
-          (item) => new ApiGatewayMap(item.ApiId, item.ApiMappingKey, item.Stage, item.ApiMappingId)
-        );
-      } catch (err) {
-        throw new Error(
-                `V2 - Make sure the '${domain.givenDomainName}' exists. Unable to get API Mappings:\n${err.message}`
-        );
-      }
+  /**
+   * Create Base Path Mapping
+   * @param domain: DomainConfig
+   */
+  public async createBasePathMapping (domain: DomainConfig): Promise<void> {
+    if (domain.apiType === Globals.apiTypes.http && domain.stage !== Globals.defaultStage) {
+      Logging.logWarning(
+        `Using a HTTP API with a stage name other than '${Globals.defaultStage}'. ` +
+        `HTTP APIs require a stage named '${Globals.defaultStage}'. ` +
+        "Please make sure that stage exists in the API Gateway. " +
+        "See https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-stages.html"
+      );
+    }
+    try {
+      await this.apiGateway.send(
+        new CreateApiMappingCommand({
+          ApiId: domain.apiId,
+          ApiMappingKey: domain.basePath,
+          DomainName: domain.givenDomainName,
+          Stage: domain.stage
+        })
+      );
+      Logging.logInfo(`V2 - Created API mapping '${domain.basePath}' for '${domain.givenDomainName}'`);
+    } catch (err) {
+      throw new Error(
+        `V2 - Unable to create base path mapping for '${domain.givenDomainName}':\n${err.message}`
+      );
     }
+  }
 
-    /**
-     * Update APi Mapping
-     * @param domain: DomainConfig
-     */
-    public async updateBasePathMapping (domain: DomainConfig): Promise<void> {
-      try {
-        await this.apiGateway.send(
-          new UpdateApiMappingCommand({
-            ApiId: domain.apiId,
-            ApiMappingId: domain.apiMapping.apiMappingId,
-            ApiMappingKey: domain.basePath,
-            DomainName: domain.givenDomainName,
-            Stage: domain.stage
-          })
-        );
-        Logging.logInfo(`V2 - Updated API mapping to '${domain.basePath}' for '${domain.givenDomainName}'`);
-      } catch (err) {
-        throw new Error(
-                `V2 - Unable to update base path mapping for '${domain.givenDomainName}':\n${err.message}`
-        );
-      }
+  /**
+   * Get APi Mapping
+   * @param domain: DomainConfig
+   */
+  public async getBasePathMappings (domain: DomainConfig): Promise<ApiGatewayMap[]> {
+    try {
+      const items = await getAWSPagedResults<ApiMapping, GetApiMappingsCommandInput, GetApiMappingsCommandOutput>(
+        this.apiGateway,
+        "Items",
+        "NextToken",
+        "NextToken",
+        new GetApiMappingsCommand({
+          DomainName: domain.givenDomainName
+        })
+      );
+      return items.map(
+        (item) => new ApiGatewayMap(item.ApiId, item.ApiMappingKey, item.Stage, item.ApiMappingId)
+      );
+    } catch (err) {
+      throw new Error(
+        `V2 - Make sure the '${domain.givenDomainName}' exists. Unable to get API Mappings:\n${err.message}`
+      );
     }
+  }
 
-    /**
-     * Delete Api Mapping
-     */
-    public async deleteBasePathMapping (domain: DomainConfig): Promise<void> {
-      try {
-        await this.apiGateway.send(new DeleteApiMappingCommand({
+  /**
+   * Update APi Mapping
+   * @param domain: DomainConfig
+   */
+  public async updateBasePathMapping (domain: DomainConfig): Promise<void> {
+    try {
+      await this.apiGateway.send(
+        new UpdateApiMappingCommand({
+          ApiId: domain.apiId,
           ApiMappingId: domain.apiMapping.apiMappingId,
-          DomainName: domain.givenDomainName
-        }));
-        Logging.logInfo(`V2 - Removed API Mapping with id: '${domain.apiMapping.apiMappingId}'`);
-      } catch (err) {
-        throw new Error(
-                `V2 - Unable to remove base path mapping for '${domain.givenDomainName}':\n${err.message}`
-        );
-      }
+          ApiMappingKey: domain.basePath,
+          DomainName: domain.givenDomainName,
+          Stage: domain.stage
+        })
+      );
+      Logging.logInfo(`V2 - Updated API mapping to '${domain.basePath}' for '${domain.givenDomainName}'`);
+    } catch (err) {
+      throw new Error(
+        `V2 - Unable to update base path mapping for '${domain.givenDomainName}':\n${err.message}`
+      );
+    }
+  }
+
+  /**
+   * Delete Api Mapping
+   */
+  public async deleteBasePathMapping (domain: DomainConfig): Promise<void> {
+    try {
+      await this.apiGateway.send(new DeleteApiMappingCommand({
+        ApiMappingId: domain.apiMapping.apiMappingId,
+        DomainName: domain.givenDomainName
+      }));
+      Logging.logInfo(`V2 - Removed API Mapping with id: '${domain.apiMapping.apiMappingId}'`);
+    } catch (err) {
+      throw new Error(
+        `V2 - Unable to remove base path mapping for '${domain.givenDomainName}':\n${err.message}`
+      );
     }
+  }
 }
 
 export = APIGatewayV2Wrapper;
diff --git a/src/aws/cloud-formation-wrapper.ts b/src/aws/cloud-formation-wrapper.ts
index 57292a49..ccbafa8c 100644
--- a/src/aws/cloud-formation-wrapper.ts
+++ b/src/aws/cloud-formation-wrapper.ts
@@ -20,181 +20,181 @@ import Logging from "../logging";
 import { getAWSPagedResults } from "../utils";
 
 class CloudFormationWrapper {
-    public cloudFormation: CloudFormationClient;
-    public stackName: string;
-
-    constructor (credentials?: any) {
-      // for the CloudFormation stack we should use the `base` stage not the plugin custom stage
-      const defaultStackName = Globals.serverless.service.service + "-" + Globals.getBaseStage();
-      this.stackName = Globals.serverless.service.provider.stackName || defaultStackName;
-      this.cloudFormation = new CloudFormationClient({
-        credentials,
-        region: Globals.getRegion(),
-        retryStrategy: Globals.getRetryStrategy(),
-        requestHandler: Globals.getRequestHandler()
-      });
+  public cloudFormation: CloudFormationClient;
+  public stackName: string;
+
+  constructor (credentials?: any) {
+    // for the CloudFormation stack we should use the `base` stage not the plugin custom stage
+    const defaultStackName = Globals.serverless.service.service + "-" + Globals.getBaseStage();
+    this.stackName = Globals.serverless.service.provider.stackName || defaultStackName;
+    this.cloudFormation = new CloudFormationClient({
+      credentials,
+      region: Globals.getRegion(),
+      retryStrategy: Globals.getRetryStrategy(),
+      requestHandler: Globals.getRequestHandler()
+    });
+  }
+
+  /**
+   * Get an API id from the existing config or CloudFormation stack resources or outputs
+   */
+  public async findApiId (apiType: string): Promise<string> {
+    const configApiId = await this.getConfigId(apiType);
+    if (configApiId) {
+      return configApiId;
     }
 
-    /**
-     * Get an API id from the existing config or CloudFormation stack resources or outputs
-     */
-    public async findApiId (apiType: string): Promise<string> {
-      const configApiId = await this.getConfigId(apiType);
-      if (configApiId) {
-        return configApiId;
-      }
-
-      return await this.getStackApiId(apiType);
-    }
+    return await this.getStackApiId(apiType);
+  }
 
-    /**
-     * Get an API id from the existing config or CloudFormation stack based on provider.apiGateway params
-     */
-    private async getConfigId (apiType: string): Promise<string | null> {
-      const apiGateway = Globals.serverless.service.provider.apiGateway || {};
-      const apiIdKey = Globals.gatewayAPIIdKeys[apiType];
-      const apiGatewayValue = apiGateway[apiIdKey];
-
-      if (apiGatewayValue) {
-        if (typeof apiGatewayValue === "string") {
-          return apiGatewayValue;
-        }
+  /**
+   * Get an API id from the existing config or CloudFormation stack based on provider.apiGateway params
+   */
+  private async getConfigId (apiType: string): Promise<string | null> {
+    const apiGateway = Globals.serverless.service.provider.apiGateway || {};
+    const apiIdKey = Globals.gatewayAPIIdKeys[apiType];
+    const apiGatewayValue = apiGateway[apiIdKey];
 
-        return await this.getCloudformationId(apiGatewayValue, apiType);
+    if (apiGatewayValue) {
+      if (typeof apiGatewayValue === "string") {
+        return apiGatewayValue;
       }
 
-      return null;
+      return await this.getCloudformationId(apiGatewayValue, apiType);
     }
 
-    private async getCloudformationId (apiGatewayValue: object, apiType: string): Promise<string | null> {
-      // in case object and Fn::ImportValue try to get API id from the CloudFormation outputs
-      const importName = apiGatewayValue[Globals.CFFuncNames.fnImport];
-      if (importName) {
-        const importValues = await this.getImportValues([importName]);
-        const nameValue = importValues[importName];
-        if (!nameValue) {
-          Logging.logWarning(`CloudFormation ImportValue '${importName}' not found in the outputs`);
-        }
-        return nameValue;
-      }
-
-      const ref = apiGatewayValue[Globals.CFFuncNames.ref];
-      if (ref) {
-        try {
-          return await this.getStackApiId(apiType, ref);
-        } catch (error) {
-          Logging.logWarning(`Unable to get ref ${ref} value.\n ${error.message}`);
-          return null;
-        }
+    return null;
+  }
+
+  private async getCloudformationId (apiGatewayValue: object, apiType: string): Promise<string | null> {
+    // in case object and Fn::ImportValue try to get API id from the CloudFormation outputs
+    const importName = apiGatewayValue[Globals.CFFuncNames.fnImport];
+    if (importName) {
+      const importValues = await this.getImportValues([importName]);
+      const nameValue = importValues[importName];
+      if (!nameValue) {
+        Logging.logWarning(`CloudFormation ImportValue '${importName}' not found in the outputs`);
       }
-
-      // log warning not supported restApiId
-      Logging.logWarning(`Unsupported apiGateway.${apiType} object`);
-
-      return null;
+      return nameValue;
     }
 
-    /**
-     * Gets rest API id from CloudFormation stack or nested stack
-     */
-    public async getStackApiId (apiType: string, logicalResourceId: string = null): Promise<string> {
-      if (!logicalResourceId) {
-        logicalResourceId = Globals.CFResourceIds[apiType];
-      }
-
-      let response;
+    const ref = apiGatewayValue[Globals.CFFuncNames.ref];
+    if (ref) {
       try {
-        // trying to get information for specified stack name
-        response = await this.getStack(logicalResourceId, this.stackName);
-      } catch {
-        // in case error trying to get information from some of nested stacks
-        response = await this.getNestedStack(logicalResourceId, this.stackName);
+        return await this.getStackApiId(apiType, ref);
+      } catch (error) {
+        Logging.logWarning(`Unable to get ref ${ref} value.\n ${error.message}`);
+        return null;
       }
+    }
 
-      if (!response) {
-        throw new Error(`Failed to find a stack ${this.stackName}\n`);
-      }
+    // log warning not supported restApiId
+    Logging.logWarning(`Unsupported apiGateway.${apiType} object`);
 
-      const apiId = response.StackResourceDetail.PhysicalResourceId;
-      if (!apiId) {
-        throw new Error(`No ApiId associated with CloudFormation stack ${this.stackName}`);
-      }
+    return null;
+  }
 
-      return apiId;
+  /**
+   * Gets rest API id from CloudFormation stack or nested stack
+   */
+  public async getStackApiId (apiType: string, logicalResourceId: string = null): Promise<string> {
+    if (!logicalResourceId) {
+      logicalResourceId = Globals.CFResourceIds[apiType];
     }
 
-    /**
-     * Gets values by names from cloudformation exports
-     */
-    public async getImportValues (names: string[]): Promise<any> {
-      const exports = await getAWSPagedResults<Export, ListExportsCommandInput, ListExportsCommandOutput>(
-        this.cloudFormation,
-        "Exports",
-        "NextToken",
-        "NextToken",
-        new ListExportsCommand({})
-      );
-        // filter Exports by names which we need
-      const filteredExports = exports.filter((item) => names.indexOf(item.Name) !== -1);
-      // converting a list of unique values to dict
-      // [{Name: "export-name", Value: "export-value"}, ...] - > {"export-name": "export-value"}
-      return filteredExports.reduce((prev, current) => ({ ...prev, [current.Name]: current.Value }), {});
+    let response;
+    try {
+      // trying to get information for specified stack name
+      response = await this.getStack(logicalResourceId, this.stackName);
+    } catch {
+      // in case error trying to get information from some of nested stacks
+      response = await this.getNestedStack(logicalResourceId, this.stackName);
     }
 
-    /**
-     * Returns a description of the specified resource in the specified stack.
-     */
-    public async getStack (logicalResourceId: string, stackName: string): Promise<DescribeStackResourceCommandOutput> {
-      try {
-        return await this.cloudFormation.send(
-          new DescribeStackResourceCommand({
-            LogicalResourceId: logicalResourceId,
-            StackName: stackName
-          })
-        );
-      } catch (err) {
-        throw new Error(`Failed to find CloudFormation resources with an error: ${err.message}\n`);
-      }
+    if (!response) {
+      throw new Error(`Failed to find a stack ${this.stackName}\n`);
     }
 
-    /**
-     * Returns a description of the specified resource in the specified nested stack.
-     */
-    public async getNestedStack (logicalResourceId: string, stackName: string) {
-      // get all stacks from the CloudFormation
-      const stacks = await getAWSPagedResults<Stack, DescribeStacksCommandInput, DescribeStacksCommandOutput>(
-        this.cloudFormation,
-        "Stacks",
-        "NextToken",
-        "NextToken",
-        new DescribeStacksCommand({})
-      );
+    const apiId = response.StackResourceDetail.PhysicalResourceId;
+    if (!apiId) {
+      throw new Error(`No ApiId associated with CloudFormation stack ${this.stackName}`);
+    }
 
-      // filter stacks by given stackName and check by nested stack RootId
-      const regex = new RegExp("/" + stackName + "/");
-      const filteredStackNames = stacks
-        .reduce((acc, stack) => {
-          if (!stack.RootId) {
-            return acc;
-          }
-          const match = stack.RootId.match(regex);
-          if (match) {
-            acc.push(stack.StackName);
-          }
+    return apiId;
+  }
+
+  /**
+   * Gets values by names from cloudformation exports
+   */
+  public async getImportValues (names: string[]): Promise<any> {
+    const exports = await getAWSPagedResults<Export, ListExportsCommandInput, ListExportsCommandOutput>(
+      this.cloudFormation,
+      "Exports",
+      "NextToken",
+      "NextToken",
+      new ListExportsCommand({})
+    );
+    // filter Exports by names which we need
+    const filteredExports = exports.filter((item) => names.indexOf(item.Name) !== -1);
+    // converting a list of unique values to dict
+    // [{Name: "export-name", Value: "export-value"}, ...] - > {"export-name": "export-value"}
+    return filteredExports.reduce((prev, current) => ({ ...prev, [current.Name]: current.Value }), {});
+  }
+
+  /**
+   * Returns a description of the specified resource in the specified stack.
+   */
+  public async getStack (logicalResourceId: string, stackName: string): Promise<DescribeStackResourceCommandOutput> {
+    try {
+      return await this.cloudFormation.send(
+        new DescribeStackResourceCommand({
+          LogicalResourceId: logicalResourceId,
+          StackName: stackName
+        })
+      );
+    } catch (err) {
+      throw new Error(`Failed to find CloudFormation resources with an error: ${err.message}\n`);
+    }
+  }
+
+  /**
+   * Returns a description of the specified resource in the specified nested stack.
+   */
+  public async getNestedStack (logicalResourceId: string, stackName: string) {
+    // get all stacks from the CloudFormation
+    const stacks = await getAWSPagedResults<Stack, DescribeStacksCommandInput, DescribeStacksCommandOutput>(
+      this.cloudFormation,
+      "Stacks",
+      "NextToken",
+      "NextToken",
+      new DescribeStacksCommand({})
+    );
+
+    // filter stacks by given stackName and check by nested stack RootId
+    const regex = new RegExp("/" + stackName + "/");
+    const filteredStackNames = stacks
+      .reduce((acc, stack) => {
+        if (!stack.RootId) {
           return acc;
-        }, []);
-
-      for (const name of filteredStackNames) {
-        try {
-          // stop the loop and return the stack details in case the first one found
-          // in case of error continue the looping
-          return await this.getStack(logicalResourceId, name);
-        } catch (err) {
-          Logging.logWarning(err.message);
         }
+        const match = stack.RootId.match(regex);
+        if (match) {
+          acc.push(stack.StackName);
+        }
+        return acc;
+      }, []);
+
+    for (const name of filteredStackNames) {
+      try {
+        // stop the loop and return the stack details in case the first one found
+        // in case of error continue the looping
+        return await this.getStack(logicalResourceId, name);
+      } catch (err) {
+        Logging.logWarning(err.message);
       }
-      return null;
     }
+    return null;
+  }
 }
 
 export = CloudFormationWrapper;
diff --git a/src/aws/route53-wrapper.ts b/src/aws/route53-wrapper.ts
index be105e5c..0807a0bb 100644
--- a/src/aws/route53-wrapper.ts
+++ b/src/aws/route53-wrapper.ts
@@ -12,159 +12,159 @@ import {
 import { getAWSPagedResults } from "../utils";
 
 class Route53Wrapper {
-    public route53: Route53Client;
-    private readonly region: string;
+  public route53: Route53Client;
+  private readonly region: string;
 
-    constructor (credentials?: any, region?: string) {
-      // not null and not undefined
-      if (credentials) {
-        this.region = region || Globals.getRegion();
-        this.route53 = new Route53Client({
-          credentials,
-          region: this.region,
-          retryStrategy: Globals.getRetryStrategy(),
-          requestHandler: Globals.getRequestHandler()
-        });
-      } else {
-        this.region = Globals.getRegion();
-        this.route53 = new Route53Client({
-          region: this.region,
-          retryStrategy: Globals.getRetryStrategy(),
-          requestHandler: Globals.getRequestHandler()
-        });
-      }
+  constructor (credentials?: any, region?: string) {
+    // not null and not undefined
+    if (credentials) {
+      this.region = region || Globals.getRegion();
+      this.route53 = new Route53Client({
+        credentials,
+        region: this.region,
+        retryStrategy: Globals.getRetryStrategy(),
+        requestHandler: Globals.getRequestHandler()
+      });
+    } else {
+      this.region = Globals.getRegion();
+      this.route53 = new Route53Client({
+        region: this.region,
+        retryStrategy: Globals.getRetryStrategy(),
+        requestHandler: Globals.getRequestHandler()
+      });
     }
+  }
 
-    /**
-     * Gets Route53 HostedZoneId from user or from AWS
-     */
-    public async getRoute53HostedZoneId (domain: DomainConfig, isHostedZonePrivate?: boolean): Promise<string> {
-      if (domain.hostedZoneId) {
-        Logging.logInfo(`Selected specific hostedZoneId ${domain.hostedZoneId}`);
-        return domain.hostedZoneId;
-      }
+  /**
+   * Gets Route53 HostedZoneId from user or from AWS
+   */
+  public async getRoute53HostedZoneId (domain: DomainConfig, isHostedZonePrivate?: boolean): Promise<string> {
+    if (domain.hostedZoneId) {
+      Logging.logInfo(`Selected specific hostedZoneId ${domain.hostedZoneId}`);
+      return domain.hostedZoneId;
+    }
 
-      const isPrivateDefined = typeof isHostedZonePrivate !== "undefined";
-      if (isPrivateDefined) {
-        const zoneTypeString = isHostedZonePrivate ? "private" : "public";
-        Logging.logInfo(`Filtering to only ${zoneTypeString} zones.`);
-      }
+    const isPrivateDefined = typeof isHostedZonePrivate !== "undefined";
+    if (isPrivateDefined) {
+      const zoneTypeString = isHostedZonePrivate ? "private" : "public";
+      Logging.logInfo(`Filtering to only ${zoneTypeString} zones.`);
+    }
 
-      let hostedZones = [];
-      try {
-        hostedZones = await getAWSPagedResults<HostedZone, ListHostedZonesCommandInput, ListHostedZonesCommandOutput>(
-          this.route53,
-          "HostedZones",
-          "Marker",
-          "NextMarker",
-          new ListHostedZonesCommand({})
-        );
-        Logging.logInfo(`Founded hosted zones list: ${hostedZones.map((zone) => zone.Name)}.`);
-      } catch (err) {
-        throw new Error(`Unable to list hosted zones in Route53.\n${err.message}`);
-      }
+    let hostedZones = [];
+    try {
+      hostedZones = await getAWSPagedResults<HostedZone, ListHostedZonesCommandInput, ListHostedZonesCommandOutput>(
+        this.route53,
+        "HostedZones",
+        "Marker",
+        "NextMarker",
+        new ListHostedZonesCommand({})
+      );
+      Logging.logInfo(`Founded hosted zones list: ${hostedZones.map((zone) => zone.Name)}.`);
+    } catch (err) {
+      throw new Error(`Unable to list hosted zones in Route53.\n${err.message}`);
+    }
 
-      // removing the first part of the domain name, api.test.com => test.com
-      const domainNameHost = domain.givenDomainName.substring(domain.givenDomainName.indexOf(".") + 1);
-      const targetHostedZone = hostedZones
-        .filter((hostedZone) => {
-          return !isPrivateDefined || isHostedZonePrivate === hostedZone.Config.PrivateZone;
-        })
-        .filter((hostedZone) => {
-          const hostedZoneName = hostedZone.Name.replace(/\.$/, "");
-          return domain.givenDomainName === hostedZoneName || domainNameHost.endsWith(hostedZoneName);
-        })
-        .sort((zone1, zone2) => zone2.Name.length - zone1.Name.length)
-        .shift();
+    // removing the first part of the domain name, api.test.com => test.com
+    const domainNameHost = domain.givenDomainName.substring(domain.givenDomainName.indexOf(".") + 1);
+    const targetHostedZone = hostedZones
+      .filter((hostedZone) => {
+        return !isPrivateDefined || isHostedZonePrivate === hostedZone.Config.PrivateZone;
+      })
+      .filter((hostedZone) => {
+        const hostedZoneName = hostedZone.Name.replace(/\.$/, "");
+        return domain.givenDomainName === hostedZoneName || domainNameHost.endsWith(hostedZoneName);
+      })
+      .sort((zone1, zone2) => zone2.Name.length - zone1.Name.length)
+      .shift();
 
-      if (targetHostedZone) {
-        return targetHostedZone.Id.replace("/hostedzone/", "");
-      } else {
-        throw new Error(`Could not find hosted zone '${domain.givenDomainName}'`);
-      }
+    if (targetHostedZone) {
+      return targetHostedZone.Id.replace("/hostedzone/", "");
+    } else {
+      throw new Error(`Could not find hosted zone '${domain.givenDomainName}'`);
     }
+  }
 
-    /**
-     * Change A Alias record through Route53 based on given action
-     * @param action: String descriptor of change to be made. Valid actions are ['UPSERT', 'DELETE']
-     * @param domain: DomainInfo object containing info about custom domain
-     */
-    public async changeResourceRecordSet (action: ChangeAction, domain: DomainConfig): Promise<void> {
-      if (domain.createRoute53Record === false) {
-        Logging.logInfo(`Skipping ${action === ChangeAction.DELETE ? "removal" : "creation"} of Route53 record.`);
-        return;
-      }
-      Logging.logInfo(`Creating/updating route53 record for '${domain.givenDomainName}'.`);
-      // Set up parameters
-      const route53HostedZoneId = await this.getRoute53HostedZoneId(domain, domain.hostedZonePrivate);
-      const route53Params = domain.route53Params;
-      const route53healthCheck = route53Params.healthCheckId ? { HealthCheckId: route53Params.healthCheckId } : {};
-      const domainInfo = domain.domainInfo ?? {
-        domainName: domain.givenDomainName,
-        hostedZoneId: route53HostedZoneId
-      };
-
-      let routingOptions = {};
-      if (route53Params.routingPolicy === Globals.routingPolicies.latency) {
-        routingOptions = {
-          Region: this.region,
-          SetIdentifier: route53Params.setIdentifier ?? domainInfo.domainName,
-          ...route53healthCheck
-        };
-      }
+  /**
+   * Change A Alias record through Route53 based on given action
+   * @param action: String descriptor of change to be made. Valid actions are ['UPSERT', 'DELETE']
+   * @param domain: DomainInfo object containing info about custom domain
+   */
+  public async changeResourceRecordSet (action: ChangeAction, domain: DomainConfig): Promise<void> {
+    if (domain.createRoute53Record === false) {
+      Logging.logInfo(`Skipping ${action === ChangeAction.DELETE ? "removal" : "creation"} of Route53 record.`);
+      return;
+    }
+    Logging.logInfo(`Creating/updating route53 record for '${domain.givenDomainName}'.`);
+    // Set up parameters
+    const route53HostedZoneId = await this.getRoute53HostedZoneId(domain, domain.hostedZonePrivate);
+    const route53Params = domain.route53Params;
+    const route53healthCheck = route53Params.healthCheckId ? { HealthCheckId: route53Params.healthCheckId } : {};
+    const domainInfo = domain.domainInfo ?? {
+      domainName: domain.givenDomainName,
+      hostedZoneId: route53HostedZoneId
+    };
 
-      if (route53Params.routingPolicy === Globals.routingPolicies.weighted) {
-        routingOptions = {
-          Weight: route53Params.weight,
-          SetIdentifier: route53Params.setIdentifier ?? domainInfo.domainName,
-          ...route53healthCheck
-        };
-      }
+    let routingOptions = {};
+    if (route53Params.routingPolicy === Globals.routingPolicies.latency) {
+      routingOptions = {
+        Region: this.region,
+        SetIdentifier: route53Params.setIdentifier ?? domainInfo.domainName,
+        ...route53healthCheck
+      };
+    }
 
-      let hostedZoneIds: string[];
-      if (domain.splitHorizonDns) {
-        hostedZoneIds = await Promise.all([
-          this.getRoute53HostedZoneId(domain, false),
-          this.getRoute53HostedZoneId(domain, true)
-        ]);
-      } else {
-        hostedZoneIds = [route53HostedZoneId];
-      }
+    if (route53Params.routingPolicy === Globals.routingPolicies.weighted) {
+      routingOptions = {
+        Weight: route53Params.weight,
+        SetIdentifier: route53Params.setIdentifier ?? domainInfo.domainName,
+        ...route53healthCheck
+      };
+    }
 
-      const recordsToCreate = domain.createRoute53IPv6Record ? [RRType.A, RRType.AAAA] : [RRType.A];
-      for (const hostedZoneId of hostedZoneIds) {
-        const changes = recordsToCreate.map((Type) => ({
-          Action: action,
-          ResourceRecordSet: {
-            AliasTarget: {
-              DNSName: domainInfo.domainName,
-              EvaluateTargetHealth: false,
-              HostedZoneId: domainInfo.hostedZoneId
-            },
-            Name: domain.givenDomainName,
-            Type,
-            ...routingOptions
-          }
-        }));
+    let hostedZoneIds: string[];
+    if (domain.splitHorizonDns) {
+      hostedZoneIds = await Promise.all([
+        this.getRoute53HostedZoneId(domain, false),
+        this.getRoute53HostedZoneId(domain, true)
+      ]);
+    } else {
+      hostedZoneIds = [route53HostedZoneId];
+    }
 
-        const params = {
-          ChangeBatch: {
-            Changes: changes,
-            Comment: `Record created by "${Globals.pluginName}"`
+    const recordsToCreate = domain.createRoute53IPv6Record ? [RRType.A, RRType.AAAA] : [RRType.A];
+    for (const hostedZoneId of hostedZoneIds) {
+      const changes = recordsToCreate.map((Type) => ({
+        Action: action,
+        ResourceRecordSet: {
+          AliasTarget: {
+            DNSName: domainInfo.domainName,
+            EvaluateTargetHealth: false,
+            HostedZoneId: domainInfo.hostedZoneId
           },
-          HostedZoneId: hostedZoneId
-        };
-        // Make API call
-        try {
-          await this.route53.send(new ChangeResourceRecordSetsCommand(params));
-        } catch (err) {
-          throw new Error(
-                    `Failed to ${action} ${recordsToCreate.join(",")} Alias for '${domain.givenDomainName}':\n
-                    ${err.message}`
-          );
+          Name: domain.givenDomainName,
+          Type,
+          ...routingOptions
         }
+      }));
+
+      const params = {
+        ChangeBatch: {
+          Changes: changes,
+          Comment: `Record created by "${Globals.pluginName}"`
+        },
+        HostedZoneId: hostedZoneId
+      };
+      // Make API call
+      try {
+        await this.route53.send(new ChangeResourceRecordSetsCommand(params));
+      } catch (err) {
+        throw new Error(
+          `Failed to ${action} ${recordsToCreate.join(",")} Alias for '${domain.givenDomainName}':\n
+                    ${err.message}`
+        );
       }
     }
+  }
 }
 
 export = Route53Wrapper;
diff --git a/src/aws/s3-wrapper.ts b/src/aws/s3-wrapper.ts
index 11ec7ccb..4ec39023 100644
--- a/src/aws/s3-wrapper.ts
+++ b/src/aws/s3-wrapper.ts
@@ -4,47 +4,47 @@ import { HeadObjectCommand, HeadObjectRequest, S3Client } from "@aws-sdk/client-
 import Globals from "../globals";
 
 class S3Wrapper {
-    public s3: S3Client;
-
-    constructor (credentials?: any) {
-      this.s3 = new S3Client({
-        credentials,
-        region: Globals.getRegion(),
-        requestHandler: Globals.getRequestHandler()
-      });
+  public s3: S3Client;
+
+  constructor (credentials?: any) {
+    this.s3 = new S3Client({
+      credentials,
+      region: Globals.getRegion(),
+      requestHandler: Globals.getRequestHandler()
+    });
+  }
+
+  /**
+   * * Checks whether the Mutual TLS certificate exists in S3 or not
+   */
+  public async assertTlsCertObjectExists (domain: DomainConfig): Promise<void> {
+    const { Bucket, Key } = S3Wrapper.extractBucketAndKey(domain.tlsTruststoreUri);
+    const params: HeadObjectRequest = { Bucket, Key };
+
+    if (domain.tlsTruststoreVersion) {
+      params.VersionId = domain.tlsTruststoreVersion;
     }
 
-    /**
-     * * Checks whether the Mutual TLS certificate exists in S3 or not
-     */
-    public async assertTlsCertObjectExists (domain: DomainConfig): Promise<void> {
-      const { Bucket, Key } = S3Wrapper.extractBucketAndKey(domain.tlsTruststoreUri);
-      const params: HeadObjectRequest = { Bucket, Key };
-
-      if (domain.tlsTruststoreVersion) {
-        params.VersionId = domain.tlsTruststoreVersion;
+    try {
+      await this.s3.send(new HeadObjectCommand(params));
+    } catch (err) {
+      if (!err.$metadata || err.$metadata.httpStatusCode !== 403) {
+        throw Error(`Could not head S3 object at ${domain.tlsTruststoreUri}.\n${err.message}`);
       }
 
-      try {
-        await this.s3.send(new HeadObjectCommand(params));
-      } catch (err) {
-        if (!err.$metadata || err.$metadata.httpStatusCode !== 403) {
-          throw Error(`Could not head S3 object at ${domain.tlsTruststoreUri}.\n${err.message}`);
-        }
-
-        Logging.logWarning(
-                `Forbidden to check the existence of the S3 object ${domain.tlsTruststoreUri} due to\n${err}`
-        );
-      }
-    }
-
-    /**
-     * * Extracts Bucket and Key from the given s3 uri
-     */
-    private static extractBucketAndKey (uri: string): { Bucket: string; Key: string } {
-      const { hostname, pathname } = new URL(uri);
-      return { Bucket: hostname, Key: pathname.substring(1) };
+      Logging.logWarning(
+        `Forbidden to check the existence of the S3 object ${domain.tlsTruststoreUri} due to\n${err}`
+      );
     }
+  }
+
+  /**
+   * * Extracts Bucket and Key from the given s3 uri
+   */
+  private static extractBucketAndKey (uri: string): { Bucket: string; Key: string } {
+    const { hostname, pathname } = new URL(uri);
+    return { Bucket: hostname, Key: pathname.substring(1) };
+  }
 }
 
 export = S3Wrapper;
diff --git a/test/integration-tests/test-utilities.ts b/test/integration-tests/test-utilities.ts
index 2da6889b..4eeb2846 100644
--- a/test/integration-tests/test-utilities.ts
+++ b/test/integration-tests/test-utilities.ts
@@ -3,6 +3,8 @@
 import shell = require("shelljs");
 import { TEMP_DIR } from "./base";
 
+const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
+
 /**
  * Executes given shell command.
  * @param cmd shell command to execute
@@ -52,7 +54,8 @@ function slsCreateDomain (tempDir, debug: boolean = false) {
  * @param debug - enable loging
  * @returns {Promise<void>}
  */
-function slsDeploy (tempDir, debug: boolean = false) {
+async function slsDeploy (tempDir, debug: boolean = false) {
+  await sleep(5000);
   return exec(`cd ${tempDir} && npx serverless deploy` + (debug ? " --verbose" : ""));
 }
 

From b031caf2da7fc48249c4576bc8cbec252c28dafc Mon Sep 17 00:00:00 2001
From: rddimon <rddimon@gmail.com>
Date: Tue, 6 Feb 2024 15:53:00 +0200
Subject: [PATCH 3/8] AT-11105: Fix lint
 https://amplify-education.atlassian.net/browse/AT-11105

---
 src/aws/api-gateway-v1-wrapper.ts          | 22 ++++++++++------------
 test/integration-tests/debug/debug.test.ts |  3 ++-
 2 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/src/aws/api-gateway-v1-wrapper.ts b/src/aws/api-gateway-v1-wrapper.ts
index 11b5450e..b43d49f6 100644
--- a/src/aws/api-gateway-v1-wrapper.ts
+++ b/src/aws/api-gateway-v1-wrapper.ts
@@ -140,9 +140,8 @@ class APIGatewayV1Wrapper extends APIGatewayBase {
         })
       );
       return items.map((item) => {
-          return new ApiGatewayMap(item.restApiId, item.basePath, item.stage, null);
-        }
-      );
+        return new ApiGatewayMap(item.restApiId, item.basePath, item.stage, null);
+      });
     } catch (err) {
       throw new Error(
         `V1 - Make sure the '${domain.givenDomainName}' exists.
@@ -156,15 +155,14 @@ class APIGatewayV1Wrapper extends APIGatewayBase {
             to '${domain.basePath}' for '${domain.givenDomainName}'`);
     try {
       await this.apiGateway.send(new UpdateBasePathMappingCommand({
-          basePath: domain.apiMapping.basePath,
-          domainName: domain.givenDomainName,
-          patchOperations: [{
-            op: "replace",
-            path: "/basePath",
-            value: domain.basePath
-          }]
-        }
-      ));
+        basePath: domain.apiMapping.basePath,
+        domainName: domain.givenDomainName,
+        patchOperations: [{
+          op: "replace",
+          path: "/basePath",
+          value: domain.basePath
+        }]
+      }));
     } catch (err) {
       throw new Error(
         `V1 - Unable to update base path mapping for '${domain.givenDomainName}':\n${err.message}`
diff --git a/test/integration-tests/debug/debug.test.ts b/test/integration-tests/debug/debug.test.ts
index 75460106..e9031ba8 100644
--- a/test/integration-tests/debug/debug.test.ts
+++ b/test/integration-tests/debug/debug.test.ts
@@ -15,7 +15,8 @@ describe("Integration Tests", function () {
 
     try {
       await utilities.createTempDir(TEMP_DIR, configFolder);
-      // await utilities.slsCreateDomain(TEMP_DIR, true);
+      await utilities.slsCreateDomain(TEMP_DIR, true);
+      await utilities.slsDeploy(TEMP_DIR, true);
       await utilities.slsDeploy(TEMP_DIR, true);
     } finally {
       await exec(`rm -rf ${TEMP_DIR}`);

From df05f89e3b389b729bfaba2a9bcf70e1d138e1a4 Mon Sep 17 00:00:00 2001
From: rddimon <rddimon@gmail.com>
Date: Tue, 6 Feb 2024 15:54:42 +0200
Subject: [PATCH 4/8] AT-11105: Fix lint
 https://amplify-education.atlassian.net/browse/AT-11105

---
 test/integration-tests/debug/debug.test.ts | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/test/integration-tests/debug/debug.test.ts b/test/integration-tests/debug/debug.test.ts
index e9031ba8..f8e48dfa 100644
--- a/test/integration-tests/debug/debug.test.ts
+++ b/test/integration-tests/debug/debug.test.ts
@@ -19,8 +19,7 @@ describe("Integration Tests", function () {
       await utilities.slsDeploy(TEMP_DIR, true);
       await utilities.slsDeploy(TEMP_DIR, true);
     } finally {
-      await exec(`rm -rf ${TEMP_DIR}`);
-      // await utilities.destroyResources(testName);
+      await utilities.destroyResources(testName);
     }
   });
 });

From 3b807aa1352f844700d835893efdceb2c8176da5 Mon Sep 17 00:00:00 2001
From: rddimon <rddimon@gmail.com>
Date: Tue, 6 Feb 2024 15:55:26 +0200
Subject: [PATCH 5/8] AT-11105: remove unused code
 https://amplify-education.atlassian.net/browse/AT-11105

---
 test/integration-tests/debug/debug.test.ts | 1 -
 1 file changed, 1 deletion(-)

diff --git a/test/integration-tests/debug/debug.test.ts b/test/integration-tests/debug/debug.test.ts
index f8e48dfa..53373678 100644
--- a/test/integration-tests/debug/debug.test.ts
+++ b/test/integration-tests/debug/debug.test.ts
@@ -1,7 +1,6 @@
 import "mocha";
 import utilities = require("../test-utilities");
 import { TEMP_DIR } from "../base";
-import { exec } from "../test-utilities";
 
 const CONFIGS_FOLDER = "debug";
 const TIMEOUT_MINUTES = 15 * 60 * 1000; // 15 minutes in milliseconds

From 281f2a47fe4140113f3062da83a6eef9ebf0abc1 Mon Sep 17 00:00:00 2001
From: rddimon <rddimon@gmail.com>
Date: Tue, 6 Feb 2024 16:45:38 +0200
Subject: [PATCH 6/8] AT-11105: Fix test
 https://amplify-education.atlassian.net/browse/AT-11105

---
 test/integration-tests/basic/deploy-idempotent2/serverless.yml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/test/integration-tests/basic/deploy-idempotent2/serverless.yml b/test/integration-tests/basic/deploy-idempotent2/serverless.yml
index df6f94db..25b002b1 100644
--- a/test/integration-tests/basic/deploy-idempotent2/serverless.yml
+++ b/test/integration-tests/basic/deploy-idempotent2/serverless.yml
@@ -25,7 +25,6 @@ custom:
       domainName: ${env:PLUGIN_IDENTIFIER}-deploy-idempotent2-${env:RANDOM_STRING}.${env:TEST_DOMAIN}
       allowPathMatching: true
     - rest:
-      autoDomain: true
       basePath: "path2"
       domainName: ${env:PLUGIN_IDENTIFIER}-deploy-idempotent2-${env:RANDOM_STRING}.${env:TEST_DOMAIN}
       allowPathMatching: true

From d260f7c4d6ee6b8c8bd3235e4c84f2984920b583 Mon Sep 17 00:00:00 2001
From: rddimon <rddimon@gmail.com>
Date: Tue, 6 Feb 2024 17:21:38 +0200
Subject: [PATCH 7/8] AT-11105: Add comments
 https://amplify-education.atlassian.net/browse/AT-11105

---
 test/integration-tests/debug/debug.test.ts | 1 +
 test/integration-tests/test-utilities.ts   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/test/integration-tests/debug/debug.test.ts b/test/integration-tests/debug/debug.test.ts
index 53373678..c0195ad8 100644
--- a/test/integration-tests/debug/debug.test.ts
+++ b/test/integration-tests/debug/debug.test.ts
@@ -16,6 +16,7 @@ describe("Integration Tests", function () {
       await utilities.createTempDir(TEMP_DIR, configFolder);
       await utilities.slsCreateDomain(TEMP_DIR, true);
       await utilities.slsDeploy(TEMP_DIR, true);
+      // run again to make sure the deployment is succeeded
       await utilities.slsDeploy(TEMP_DIR, true);
     } finally {
       await utilities.destroyResources(testName);
diff --git a/test/integration-tests/test-utilities.ts b/test/integration-tests/test-utilities.ts
index 4eeb2846..4219b75f 100644
--- a/test/integration-tests/test-utilities.ts
+++ b/test/integration-tests/test-utilities.ts
@@ -55,6 +55,7 @@ function slsCreateDomain (tempDir, debug: boolean = false) {
  * @returns {Promise<void>}
  */
 async function slsDeploy (tempDir, debug: boolean = false) {
+  // sleep to avoid `to many requests` error as we run a lot of tests one after another
   await sleep(5000);
   return exec(`cd ${tempDir} && npx serverless deploy` + (debug ? " --verbose" : ""));
 }

From 09149dcbd3c93e85c454dfdaad0273781b0924b9 Mon Sep 17 00:00:00 2001
From: rddimon <rddimon@gmail.com>
Date: Tue, 6 Feb 2024 20:08:49 +0200
Subject: [PATCH 8/8] AT-11105: remove debug test
 https://amplify-education.atlassian.net/browse/AT-11105

---
 package.json                                  |  1 -
 test/integration-tests/debug/debug.test.ts    | 25 ---------------
 .../debug/pr-example/handler.js               | 13 --------
 .../debug/pr-example/serverless.yml           | 32 -------------------
 4 files changed, 71 deletions(-)
 delete mode 100644 test/integration-tests/debug/debug.test.ts
 delete mode 100644 test/integration-tests/debug/pr-example/handler.js
 delete mode 100644 test/integration-tests/debug/pr-example/serverless.yml

diff --git a/package.json b/package.json
index 1dba3ebe..111ee794 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,6 @@
   "scripts": {
     "integration-basic": "nyc mocha -r ts-node/register --project tsconfig.json test/integration-tests/basic/basic.test.ts",
     "integration-deploy": "nyc mocha -r ts-node/register --project tsconfig.json test/integration-tests/deploy/deploy.test.ts",
-    "integration-debug": "nyc mocha -r ts-node/register --project tsconfig.json test/integration-tests/debug/debug.test.ts",
     "test": "find ./test/unit-tests -name '*.test.ts' | xargs nyc mocha -r ts-node/register --project tsconfig.json --timeout 5000 && nyc report --reporter=text-summary",
     "test:debug": "NODE_OPTIONS='--inspect-brk' mocha -j 1 -r ts-node/register --project tsconfig.json test/unit-tests/index.test.ts",
     "integration-test": "npm run integration-basic && npm run integration-deploy",
diff --git a/test/integration-tests/debug/debug.test.ts b/test/integration-tests/debug/debug.test.ts
deleted file mode 100644
index c0195ad8..00000000
--- a/test/integration-tests/debug/debug.test.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import "mocha";
-import utilities = require("../test-utilities");
-import { TEMP_DIR } from "../base";
-
-const CONFIGS_FOLDER = "debug";
-const TIMEOUT_MINUTES = 15 * 60 * 1000; // 15 minutes in milliseconds
-
-describe("Integration Tests", function () {
-  this.timeout(TIMEOUT_MINUTES);
-
-  it("Creates pr-example", async () => {
-    const testName = "pr-example";
-    const configFolder = `${CONFIGS_FOLDER}/${testName}`;
-
-    try {
-      await utilities.createTempDir(TEMP_DIR, configFolder);
-      await utilities.slsCreateDomain(TEMP_DIR, true);
-      await utilities.slsDeploy(TEMP_DIR, true);
-      // run again to make sure the deployment is succeeded
-      await utilities.slsDeploy(TEMP_DIR, true);
-    } finally {
-      await utilities.destroyResources(testName);
-    }
-  });
-});
diff --git a/test/integration-tests/debug/pr-example/handler.js b/test/integration-tests/debug/pr-example/handler.js
deleted file mode 100644
index 1729e0e1..00000000
--- a/test/integration-tests/debug/pr-example/handler.js
+++ /dev/null
@@ -1,13 +0,0 @@
-"use strict";
-
-module.exports.helloWorld = (event, _context, callback) => {
-  const response = {
-    statusCode: 200,
-    body: JSON.stringify({
-      message: "Go Serverless! Your function executed successfully!",
-      input: event,
-    }),
-  };
-
-  callback(null, response);
-};
diff --git a/test/integration-tests/debug/pr-example/serverless.yml b/test/integration-tests/debug/pr-example/serverless.yml
deleted file mode 100644
index 24e20572..00000000
--- a/test/integration-tests/debug/pr-example/serverless.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-service: ${env:PLUGIN_IDENTIFIER}-pr-example
-provider:
-  name: aws
-  iam:
-    role: arn:aws:iam::${aws:accountId}:role/sls_domain_manager_lambda
-  runtime: nodejs16.x
-  region: us-west-2
-  stage: test
-functions:
-  helloWorld:
-    handler: handler.helloWorld
-    events:
-      - httpApi:
-          path: /hello-world
-          method: get
-
-plugins:
-  - serverless-domain-manager
-
-custom:
-  customDomain:
-    domainName: ${env:PLUGIN_IDENTIFIER}-pr-example.${env:TEST_DOMAIN}
-    basePath: ''
-    createRoute53Record: true
-    stage: 'production'
-    endpointType: 'regional'
-    apiType: http
-    autoDomain: true
-
-package:
-  patterns:
-    - '!node_modules/**'