constructor(serverless, options) {
    this.naming = { provider: this }
    this.options = options
    this.provider = this // only load plugin in an AWS service context
    this.serverless = serverless
    // Notice: provider.sdk is used by plugins. Do not remove without deprecating first and
    //         offering a reliable alternative
    this.sdk = AWS
    this.serverless.setProvider(constants.providerName, this)

    if ('aws' in serverless.credentialProviders) {
      this.resolveCredentials = serverless.credentialProviders.aws
    } else {
      throw new Error('Credential Resolver must be defined')
    }

    this.hooks = {
      initialize: () => {
        // Support deploymentBucket configuration as an object
        const provider = this.serverless.service.provider
        if (provider && provider.deploymentBucket) {
          if (_.isObject(provider.deploymentBucket)) {
            // store the object in a new variable so that it can be reused later on
            provider.deploymentBucketObject = provider.deploymentBucket
            if (provider.deploymentBucket.name) {
              // (re)set the value of the deploymentBucket property to the name (which is a string)
              provider.deploymentBucket = provider.deploymentBucket.name
            } else {
              provider.deploymentBucket = null
            }
          }
        }
        reportDeprecatedProperties(
          'PROVIDER_IAM_SETTINGS_V3',
          {
            'provider.role': 'provider.iam.role',
            'provider.rolePermissionsBoundary':
              'provider.iam.role.permissionsBoundary',
            'provider.iam.role.permissionBoundary':
              'provider.iam.role.permissionsBoundary',
            'provider.iamManagedPolicies': 'provider.iam.role.managedPolicies',
            'provider.iamRoleStatements': 'provider.iam.role.statements',
            'provider.cfnRole': 'provider.iam.deploymentRole',
          },
          { serviceConfig: this.serverless.service },
        )
      },
    }

    if (this.serverless.service.provider.name === 'aws') {
      // Below ideally should be in hooks.initialize, but variables resolution depend on this
      this.serverless.service.provider.region = this.getRegion()
      serverless.configSchemaHandler.defineProvider('aws', {
        definitions: {
          awsAccountId: {
            type: 'string',
            pattern: '^\\d{12}$',
          },
          awsAlbListenerArn: {
            type: 'string',
            pattern: ALB_LISTENER_REGEXP.source,
          },
          awsAlexaEventToken: {
            type: 'string',
            minLength: 0,
            maxLength: 256,
            pattern: '^[a-zA-Z0-9._\\-]+$',
          },
          awsApiGatewayAbbreviatedArn: {
            type: 'string',
            pattern: '^execute-api:/',
          },
          awsApiGatewayApiKeys: {
            type: 'array',
            items: {
              anyOf: [
                { type: 'string' },
                {
                  $ref: '#/definitions/awsApiGatewayApiKeysProperties',
                },
                {
                  type: 'object',
                  maxProperties: 1,
                  additionalProperties: {
                    type: 'array',
                    items: {
                      oneOf: [
                        { type: 'string' },
                        {
                          $ref: '#/definitions/awsApiGatewayApiKeysProperties',
                        },
                      ],
                    },
                  },
                },
              ],
            },
          },
          awsApiGatewayApiKeysProperties: {
            type: 'object',
            properties: {
              name: { type: 'string' },
              value: { type: 'string' },
              description: { type: 'string' },
              customerId: { type: 'string' },
              enabled: { type: 'boolean' },
            },
            additionalProperties: false,
          },
          awsHttpApiPayload: {
            type: 'string',
            enum: ['1.0', '2.0'],
          },
          awsArn: {
            anyOf: [
              { $ref: '#/definitions/awsArnString' },
              { $ref: '#/definitions/awsCfFunction' },
            ],
          },
          awsArnString: {
            type: 'string',
            pattern: '^arn:',
          },
          awsCfArrayInstruction: {
            anyOf: [
              {
                type: 'array',
                items: { $ref: '#/definitions/awsCfInstruction' },
              },
              { $ref: '#/definitions/awsCfSplit' },
            ],
          },
          awsSecretsManagerArnString: {
            type: 'string',
            pattern:
              'arn:[a-z-]+:secretsmanager:[a-z0-9-]+:\\d+:secret:[A-Za-z0-9/_+=.@-]+',
          },
          awsCfFunction: {
            anyOf: [
              { $ref: '#/definitions/awsCfImport' },
              { $ref: '#/definitions/awsCfJoin' },
              { $ref: '#/definitions/awsCfGetAtt' },
              { $ref: '#/definitions/awsCfRef' },
              { $ref: '#/definitions/awsCfSub' },
              { $ref: '#/definitions/awsCfBase64' },
              { $ref: '#/definitions/awsCfToJsonString' },
            ],
          },
          awsCfGetAtt: {
            type: 'object',
            properties: {
              'Fn::GetAtt': {
                type: 'array',
                minItems: 2,
                maxItems: 2,
                items: { type: 'string', minLength: 1 },
              },
            },
            required: ['Fn::GetAtt'],
            additionalProperties: false,
          },
          awsCfGetAZs: {
            type: 'object',
            properties: {
              'Fn::GetAZs': {
                oneOf: [
                  { type: 'string', minLength: 1 },
                  { $ref: '#/definitions/awsCfRef' },
                ],
              },
            },
            required: ['Fn::GetAZs'],
            additionalProperties: false,
          },
          awsCfImport: {
            type: 'object',
            properties: {
              'Fn::ImportValue': {},
            },
            additionalProperties: false,
            required: ['Fn::ImportValue'],
          },
          awsCfIf: {
            type: 'object',
            properties: {
              'Fn::If': {
                type: 'array',
                minItems: 3,
                maxItems: 3,
                items: { $ref: '#/definitions/awsCfInstruction' },
              },
            },
            required: ['Fn::If'],
            additionalProperties: false,
          },
          awsCfImportLocallyResolvable: {
            type: 'object',
            properties: {
              'Fn::ImportValue': { type: 'string' },
            },
            additionalProperties: false,
            required: ['Fn::ImportValue'],
          },
          awsCfInstruction: {
            anyOf: [
              { type: 'string', minLength: 1 },
              { $ref: '#/definitions/awsCfFunction' },
            ],
          },
          awsCfJoin: {
            type: 'object',
            properties: {
              'Fn::Join': {
                type: 'array',
                minItems: 2,
                maxItems: 2,
                items: [{ type: 'string' }, { type: 'array' }],
                additionalItems: false,
              },
            },
            required: ['Fn::Join'],
            additionalProperties: false,
          },
          awsCfSelect: {
            type: 'object',
            properties: {
              'Fn::Select': {
                type: 'array',
                minItems: 2,
                maxItems: 2,
                items: {
                  anyOf: [
                    { type: 'number' },
                    { type: 'string' },
                    { type: 'array' },
                    { $ref: '#/definitions/awsCfFindInMap' },
                    { $ref: '#/definitions/awsCfGetAtt' },
                    { $ref: '#/definitions/awsCfGetAZs' },
                    { $ref: '#/definitions/awsCfIf' },
                    { $ref: '#/definitions/awsCfSplit' },
                    { $ref: '#/definitions/awsCfRef' },
                  ],
                },
              },
            },
            required: ['Fn::Select'],
            additionalProperties: false,
          },
          awsCfRef: {
            type: 'object',
            properties: {
              Ref: { type: 'string', minLength: 1 },
            },
            required: ['Ref'],
            additionalProperties: false,
          },
          awsCfSplit: {
            type: 'object',
            properties: {
              'Fn::Split': {
                type: 'array',
                minItems: 2,
                maxItems: 2,
                items: {
                  oneOf: [
                    { type: 'string' },
                    { $ref: '#/definitions/awsCfFunction' },
                  ],
                },
              },
            },
            required: ['Fn::Split'],
            additionalProperties: false,
          },
          awsCfFindInMap: {
            type: 'object',
            properties: {
              'Fn::FindInMap': {
                type: 'array',
                minItems: 3,
                maxItems: 3,
                items: {
                  oneOf: [
                    { type: 'string' },
                    { $ref: '#/definitions/awsCfFunction' },
                  ],
                },
              },
            },
            required: ['Fn::FindInMap'],
            additionalProperties: false,
          },
          awsCfSub: {
            type: 'object',
            properties: {
              'Fn::Sub': {},
            },
            required: ['Fn::Sub'],
            additionalProperties: false,
          },
          awsCfBase64: {
            type: 'object',
            properties: {
              'Fn::Base64': {},
            },
          },
          awsCfToJsonString: {
            type: 'object',
            properties: {
              'Fn::ToJsonString': {
                anyOf: [{ type: 'object' }, { type: 'array' }],
              },
            },
            required: ['Fn::ToJsonString'],
            additionalProperties: false,
          },
          awsIamPolicyAction: { type: 'array', items: { type: 'string' } },
          awsIamPolicyPrincipal: {
            anyOf: [
              { const: '*' },
              {
                type: 'object',
                properties: {
                  AWS: {
                    anyOf: [
                      { const: '*' },
                      { $ref: '#/definitions/awsCfIf' },
                      {
                        type: 'array',
                        items: {
                          anyOf: [
                            { $ref: '#/definitions/awsAccountId' },
                            { $ref: '#/definitions/awsArn' },
                          ],
                        },
                      },
                    ],
                  },
                  Federated: { type: 'array', items: { type: 'string' } },
                  Service: { type: 'array', items: { type: 'string' } },
                  CanonicalUser: { type: 'array', items: { type: 'string' } },
                },
                additionalProperties: false,
              },
            ],
          },
          awsIamPolicyResource: {
            anyOf: [
              { const: '*' },
              { $ref: '#/definitions/awsArn' },
              { $ref: '#/definitions/awsLogicalResourceId' },
              {
                type: 'array',
                items: {
                  anyOf: [
                    { const: '*' },
                    { $ref: '#/definitions/awsArn' },
                    { $ref: '#/definitions/awsLogicalResourceId' },
                  ],
                },
              },
            ],
          },
          // Definition of Statement taken from https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_grammar.html#policies-grammar-bnf
          awsIamPolicyStatements: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                Sid: { type: 'string' },
                Effect: { enum: ['Allow', 'Deny'] },
                Action: { $ref: '#/definitions/awsIamPolicyAction' },
                NotAction: { $ref: '#/definitions/awsIamPolicyAction' },
                Principal: { $ref: '#/definitions/awsIamPolicyPrincipal' },
                NotPrincipal: { $ref: '#/definitions/awsIamPolicyPrincipal' },
                Resource: { $ref: '#/definitions/awsIamPolicyResource' },
                NotResource: { $ref: '#/definitions/awsIamPolicyResource' },
                Condition: { type: 'object' },
              },
              additionalProperties: false,
              allOf: [
                { required: ['Effect'] },
                {
                  oneOf: [
                    { required: ['Action'] },
                    { required: ['NotAction'] },
                  ],
                },
                {
                  oneOf: [
                    { required: ['Resource'] },
                    { required: ['NotResource'] },
                  ],
                },
              ],
            },
          },
          awsKmsArn: {
            anyOf: [
              { $ref: '#/definitions/awsCfFunction' },
              { type: 'string', pattern: '^arn:aws[a-z-]*:kms' },
            ],
          },
          awsLambdaArchitecture: { enum: ['arm64', 'x86_64'] },
          awsLambdaEnvironment: {
            type: 'object',
            patternProperties: {
              '^[A-Za-z_][a-zA-Z0-9_]*$': {
                anyOf: [
                  { const: '' },
                  { $ref: '#/definitions/awsCfInstruction' },
                  { $ref: '#/definitions/awsCfIf' },
                  { $ref: '#/definitions/awsCfSelect' },
                ],
              },
            },
            additionalProperties: false,
          },
          awsLambdaLayers: {
            type: 'array',
            items: { $ref: '#/definitions/awsArn' },
          },
          awsLambdaMemorySize: {
            type: 'integer',
            minimum: 128,
            maximum: 10240,
          },
          awsLambdaRole: {
            anyOf: [
              { type: 'string', minLength: 1 },
              { $ref: '#/definitions/awsCfSub' },
              { $ref: '#/definitions/awsCfImport' },
              { $ref: '#/definitions/awsCfGetAtt' },
            ],
          },
          awsLambdaRuntime: {
            enum: [
              'dotnet6',
              'dotnet8',
              'go1.x',
              'java21',
              'java17',
              'java11',
              'java8',
              'java8.al2',
              'nodejs14.x',
              'nodejs16.x',
              'nodejs18.x',
              'nodejs20.x',
              'nodejs22.x',
              'provided',
              'provided.al2',
              'provided.al2023',
              'python3.7',
              'python3.8',
              'python3.9',
              'python3.10',
              'python3.11',
              'python3.12',
              'python3.13',
              'ruby2.7',
              'ruby3.2',
            ],
          },
          awsLambdaRuntimeManagement: {
            oneOf: [
              { enum: ['auto', 'onFunctionUpdate'] },
              {
                type: 'object',
                properties: {
                  mode: { enum: ['auto', 'onFunctionUpdate', 'manual'] },
                  arn: { $ref: '#/definitions/awsArn' },
                },
                additionalProperties: false,
              },
            ],
          },
          awsLambdaTimeout: { type: 'integer', minimum: 1, maximum: 900 },
          awsLambdaTracing: {
            anyOf: [{ enum: ['Active', 'PassThrough'] }, { type: 'boolean' }],
          },
          awsLambdaVersioning: { type: 'boolean' },
          awsLambdaVpcConfig: {
            type: 'object',
            properties: {
              securityGroupIds: {
                anyOf: [
                  {
                    type: 'array',
                    items: {
                      anyOf: [
                        { $ref: '#/definitions/awsCfInstruction' },
                        { $ref: '#/definitions/awsCfIf' },
                      ],
                    },
                    maxItems: 5,
                  },
                  { $ref: '#/definitions/awsCfSplit' },
                  { $ref: '#/definitions/awsCfFindInMap' },
                ],
              },
              subnetIds: {
                anyOf: [
                  {
                    type: 'array',
                    items: {
                      anyOf: [
                        { $ref: '#/definitions/awsCfInstruction' },
                        { $ref: '#/definitions/awsCfIf' },
                      ],
                    },
                    maxItems: 16,
                  },
                  { $ref: '#/definitions/awsCfSplit' },
                  { $ref: '#/definitions/awsCfFindInMap' },
                ],
              },
            },
            additionalProperties: false,
            required: ['securityGroupIds', 'subnetIds'],
          },
          awsLogicalResourceId: {
            type: 'string',
            pattern: '^[#A-Za-z0-9-_./]+[*]?$',
          },
          awsLogGroupName: {
            type: 'string',
            pattern: '^[/#A-Za-z0-9-_.]+$',
          },
          awsLogRetentionInDays: {
            type: 'number',
            // https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutRetentionPolicy.html#API_PutRetentionPolicy_RequestSyntax
            enum: [
              1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731,
              1827, 2192, 2557, 2922, 3288, 3653,
            ],
          },
          awsLambdaLoggingConfiguration: {
            type: 'object',
            properties: {
              applicationLogLevel: {
                type: 'string',
                enum: ['DEBUG', 'ERROR', 'FATAL', 'INFO', 'TRACE', 'WARN'],
              },
              logFormat: { type: 'string', enum: ['JSON', 'Text'] },
              logGroup: {
                type: 'string',
                pattern: '[\\.\\-_/#A-Za-z0-9]+',
                minLength: 1,
                maxLength: 512,
              },
              systemLogLevel: {
                type: 'string',
                enum: ['DEBUG', 'INFO', 'WARN'],
              },
            },
            additionalProperties: false,
          },
          awsLogDataProtectionPolicy: {
            type: 'object',
            properties: {
              Name: { type: 'string' },
              Description: { type: 'string' },
              Version: { type: 'string' },
              Statement: { type: 'array' },
            },
            additionalProperties: false,
            required: ['Name', 'Version', 'Statement'],
          },
          awsResourceCondition: { type: 'string' },
          awsResourceDependsOn: { type: 'array', items: { type: 'string' } },
          awsResourcePolicyResource: {
            anyOf: [
              { const: '*' },
              { $ref: '#/definitions/awsArn' },
              // API Gateway Resource Policy resource property abbreviated syntax - https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-resource-policies-examples.html
              { $ref: '#/definitions/awsApiGatewayAbbreviatedArn' },
              {
                type: 'array',
                items: {
                  anyOf: [
                    { const: '*' },
                    { $ref: '#/definitions/awsArn' },
                    // API Gateway Resource Policy resource property abbreviated syntax - https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-resource-policies-examples.html
                    { $ref: '#/definitions/awsApiGatewayAbbreviatedArn' },
                  ],
                },
              },
            ],
          },
          awsResourcePolicyStatements: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                Sid: { type: 'string' },
                Effect: { enum: ['Allow', 'Deny'] },
                Action: { $ref: '#/definitions/awsIamPolicyAction' },
                NotAction: { $ref: '#/definitions/awsIamPolicyAction' },
                Principal: { $ref: '#/definitions/awsIamPolicyPrincipal' },
                NotPrincipal: { $ref: '#/definitions/awsIamPolicyPrincipal' },
                Resource: { $ref: '#/definitions/awsResourcePolicyResource' },
                NotResource: {
                  $ref: '#/definitions/awsResourcePolicyResource',
                },
                Condition: { type: 'object' },
              },
              additionalProperties: false,
              allOf: [
                { required: ['Effect'] },
                {
                  oneOf: [
                    { required: ['Action'] },
                    { required: ['NotAction'] },
                  ],
                },
                {
                  oneOf: [
                    { required: ['Resource'] },
                    { required: ['NotResource'] },
                  ],
                },
              ],
            },
          },
          awsResourceTags: {
            type: 'object',
            patternProperties: {
              '^(?!aws:)[\\w./=+:\\-_\\x20]{1,128}$': {
                type: 'string',
                maxLength: 256,
              },
            },
            additionalProperties: false,
          },
          awsS3BucketName: {
            type: 'string',
            // pattern sourced from https://stackoverflow.com/questions/50480924/regex-for-s3-bucket-name
            pattern:
              '(?!^(\\d{1,3}\\.){3}\\d{1,3}$)(^(([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])\\.)*([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])$)',
            minLength: 3,
            maxLength: 63,
          },
          ecrImageUri: {
            type: 'string',
            pattern:
              '^\\d+\\.dkr\\.ecr\\.[a-z0-9-]+..amazonaws.com\\/([^@]+)|([^@:]+@sha256:[a-f0-9]{64})$',
          },
          filterPatterns: {
            type: 'array',
            minItems: 1,
            maxItems: 10,
            items: { type: 'object' },
          },
        },
        provider: {
          properties: {
            alb: {
              type: 'object',
              properties: {
                targetGroupPrefix: { type: 'string', maxLength: 16 },
                authorizers: {
                  type: 'object',
                  additionalProperties: {
                    anyOf: [oidcAlbAuthorizer, cognitoAlbAuthorizer],
                  },
                },
              },
              additionalProperties: false,
            },
            apiGateway: {
              type: 'object',
              properties: {
                apiKeys: { $ref: '#/definitions/awsApiGatewayApiKeys' },
                apiKeySourceType: {
                  anyOf: ['HEADER', 'AUTHORIZER'].map(caseInsensitive),
                },
                binaryMediaTypes: {
                  type: 'array',
                  items: { type: 'string', pattern: '^\\S+\\/\\S+$' },
                },
                description: { type: 'string' },
                disableDefaultEndpoint: { type: 'boolean' },
                metrics: { type: 'boolean' },
                minimumCompressionSize: {
                  type: 'integer',
                  minimum: 0,
                  maximum: 10485760,
                },
                resourcePolicy: {
                  $ref: '#/definitions/awsResourcePolicyStatements',
                },
                restApiId: { $ref: '#/definitions/awsCfInstruction' },
                restApiResources: {
                  anyOf: [
                    {
                      type: 'array',
                      items: {
                        type: 'object',
                        properties: {
                          path: { type: 'string' },
                          resourceId: { type: 'string' },
                        },
                        required: [],
                        additionalProperties: false,
                      },
                    },
                    { type: 'object' },
                  ],
                },
                restApiRootResourceId: {
                  $ref: '#/definitions/awsCfInstruction',
                },
                request: {
                  type: 'object',
                  properties: {
                    schemas: {
                      type: 'object',
                      additionalProperties: {
                        type: 'object',
                        properties: {
                          schema: { type: 'object' },
                          name: { type: 'string' },
                          description: { type: 'string' },
                        },
                        required: ['schema'],
                        additionalProperties: false,
                      },
                    },
                  },
                  additionalProperties: false,
                },
                shouldStartNameWithService: { type: 'boolean' },
                stage: { type: 'string' },
                timeoutInMillis: { type: 'integer', minimum: 50 },
                usagePlan: {
                  anyOf: [
                    apiGatewayUsagePlan,
                    {
                      type: 'array',
                      items: {
                        type: 'object',
                        additionalProperties: apiGatewayUsagePlan,
                        maxProperties: 1,
                      },
                    },
                  ],
                },
                websocketApiId: { $ref: '#/definitions/awsCfInstruction' },
              },
              additionalProperties: false,
            },
            apiName: { type: 'string' },
            architecture: { $ref: '#/definitions/awsLambdaArchitecture' },
            cfnRole: { $ref: '#/definitions/awsArn' },
            cloudFront: {
              type: 'object',
              properties: {
                cachePolicies: {
                  type: 'object',
                  additionalProperties: {
                    type: 'object',
                    properties: {
                      Comment: { type: 'string' },
                      DefaultTTL: { type: 'integer', minimum: 0 },
                      MaxTTL: { type: 'integer', minimum: 0 },
                      MinTTL: { type: 'integer', minimum: 0 },
                      ParametersInCacheKeyAndForwardedToOrigin: {
                        type: 'object',
                        properties: {
                          CookiesConfig: {
                            type: 'object',
                            properties: {
                              CookieBehavior: {
                                enum: ['none', 'whitelist', 'allExcept', 'all'],
                              },
                              Cookies: {
                                type: 'array',
                                items: { type: 'string' },
                              },
                            },
                            required: ['CookieBehavior'],
                            additionalProperties: false,
                          },
                          EnableAcceptEncodingBrotli: { type: 'boolean' },
                          EnableAcceptEncodingGzip: { type: 'boolean' },
                          HeadersConfig: {
                            type: 'object',
                            properties: {
                              HeaderBehavior: { enum: ['none', 'whitelist'] },
                              Headers: {
                                type: 'array',
                                items: { type: 'string' },
                              },
                            },
                            required: ['HeaderBehavior'],
                            additionalProperties: false,
                          },
                          QueryStringsConfig: {
                            type: 'object',
                            properties: {
                              QueryStringBehavior: {
                                enum: ['none', 'whitelist', 'allExcept', 'all'],
                              },
                              QueryStrings: {
                                type: 'array',
                                items: { type: 'string' },
                              },
                            },
                            required: ['QueryStringBehavior'],
                            additionalProperties: false,
                          },
                        },
                        required: [
                          'CookiesConfig',
                          'EnableAcceptEncodingGzip',
                          'HeadersConfig',
                          'QueryStringsConfig',
                        ],
                        additionalProperties: false,
                      },
                    },
                    required: [
                      'DefaultTTL',
                      'MaxTTL',
                      'MinTTL',
                      'ParametersInCacheKeyAndForwardedToOrigin',
                    ],
                    additionalProperties: false,
                  },
                },
              },
              additionalProperties: false,
            },
            deploymentBucket: {
              anyOf: [
                { $ref: '#/definitions/awsS3BucketName' },
                {
                  type: 'object',
                  properties: {
                    blockPublicAccess: { type: 'boolean' },
                    skipPolicySetup: { type: 'boolean' },
                    maxPreviousDeploymentArtifacts: {
                      type: 'integer',
                      minimum: 0,
                    },
                    name: { $ref: '#/definitions/awsS3BucketName' },
                    versioning: { type: 'boolean' },
                    serverSideEncryption: { enum: ['AES256', 'aws:kms'] },
                    sseCustomerAlgorithim: { type: 'string' },
                    sseCustomerKey: { type: 'string' },
                    sseCustomerKeyMD5: { type: 'string' },
                    sseKMSKeyId: { type: 'string' },
                    tags: { $ref: '#/definitions/awsResourceTags' },
                  },
                  additionalProperties: false,
                },
              ],
            },
            deploymentPrefix: { type: 'string' },
            disableRollback: { type: 'boolean' },
            endpointType: {
              anyOf: ['REGIONAL', 'EDGE', 'PRIVATE'].map(caseInsensitive),
            },
            environment: { $ref: '#/definitions/awsLambdaEnvironment' },
            eventBridge: {
              type: 'object',
              properties: {
                useCloudFormation: { type: 'boolean' },
              },
              additionalProperties: false,
            },
            httpApi: {
              type: 'object',
              properties: {
                authorizers: {
                  type: 'object',
                  additionalProperties: {
                    oneOf: [
                      {
                        type: 'object',
                        properties: {
                          type: { const: 'jwt' },
                          name: { type: 'string' },
                          identitySource: {
                            $ref: '#/definitions/awsCfInstruction',
                          },
                          issuerUrl: { $ref: '#/definitions/awsCfInstruction' },
                          audience: {
                            anyOf: [
                              { $ref: '#/definitions/awsCfInstruction' },
                              {
                                type: 'array',
                                items: {
                                  $ref: '#/definitions/awsCfInstruction',
                                },
                              },
                            ],
                          },
                        },
                        required: ['identitySource', 'issuerUrl', 'audience'],
                        additionalProperties: false,
                      },
                      {
                        type: 'object',
                        properties: {
                          type: { const: 'request' },
                          name: { type: 'string' },
                          functionName: { type: 'string' },
                          functionArn: {
                            $ref: '#/definitions/awsCfInstruction',
                          },
                          managedExternally: { type: 'boolean' },
                          resultTtlInSeconds: {
                            type: 'integer',
                            minimum: 0,
                            maximum: 3600,
                          },
                          enableSimpleResponses: { type: 'boolean' },
                          payloadVersion: {
                            $ref: '#/definitions/awsHttpApiPayload',
                          },
                          identitySource: {
                            anyOf: [
                              { $ref: '#/definitions/awsCfInstruction' },
                              {
                                type: 'array',
                                items: {
                                  $ref: '#/definitions/awsCfInstruction',
                                },
                              },
                            ],
                          },
                        },
                        required: ['type'],
                      },
                    ],
                  },
                },
                cors: {
                  anyOf: [
                    { type: 'boolean' },
                    {
                      type: 'object',
                      properties: {
                        allowCredentials: { type: 'boolean' },
                        allowedHeaders: {
                          type: 'array',
                          items: { type: 'string' },
                        },
                        allowedMethods: {
                          type: 'array',
                          items: { type: 'string' },
                        },
                        allowedOrigins: {
                          type: 'array',
                          items: { type: 'string' },
                        },
                        exposedResponseHeaders: {
                          type: 'array',
                          items: { type: 'string' },
                        },
                        maxAge: { type: 'integer', minimum: 0 },
                      },
                      additionalProperties: false,
                    },
                  ],
                },
                id: {
                  anyOf: [
                    { type: 'string' },
                    { $ref: '#/definitions/awsCfImportLocallyResolvable' },
                  ],
                },
                name: { type: 'string' },
                payload: { type: 'string' },
                metrics: { type: 'boolean' },
                useProviderTags: { const: true },
                disableDefaultEndpoint: { type: 'boolean' },
                shouldStartNameWithService: { type: 'boolean' },
              },
              additionalProperties: false,
            },
            iam: {
              type: 'object',
              properties: {
                role: {
                  anyOf: [
                    { $ref: '#/definitions/awsLambdaRole' },
                    {
                      type: 'object',
                      properties: {
                        name: {
                          type: 'string',
                          pattern: '^[A-Za-z0-9/_+=,.@-]{1,64}$',
                        },
                        path: {
                          type: 'string',
                          pattern: '(^\\/$)|(^\\/[\u0021-\u007f]+\\/$)',
                        },
                        managedPolicies: {
                          type: 'array',
                          items: { $ref: '#/definitions/awsArn' },
                        },
                        statements: {
                          $ref: '#/definitions/awsIamPolicyStatements',
                        },
                        permissionBoundary: { $ref: '#/definitions/awsArn' },
                        permissionsBoundary: { $ref: '#/definitions/awsArn' },
                        tags: { $ref: '#/definitions/awsResourceTags' },
                      },
                      additionalProperties: false,
                    },
                  ],
                },
                deploymentRole: { $ref: '#/definitions/awsArn' },
              },
              additionalProperties: false,
            },
            iamManagedPolicies: {
              type: 'array',
              items: { $ref: '#/definitions/awsArn' },
            },
            iamRoleStatements: { $ref: '#/definitions/awsIamPolicyStatements' },
            ecr: {
              type: 'object',
              properties: {
                scanOnPush: { type: 'boolean' },
                images: {
                  type: 'object',
                  patternProperties: {
                    [imageNamePattern]: {
                      anyOf: [
                        {
                          type: 'object',
                          properties: {
                            uri: { $ref: '#/definitions/ecrImageUri' },
                            path: { type: 'string' },
                            file: { type: 'string' },
                            buildArgs: {
                              type: 'object',
                              additionalProperties: { type: 'string' },
                            },
                            buildOptions: {
                              type: 'array',
                              items: { type: 'string' },
                            },
                            cacheFrom: {
                              type: 'array',
                              items: { type: 'string' },
                            },
                            platform: { type: 'string' },
                            provenance: { type: 'string' },
                          },
                          additionalProperties: false,
                        },
                        {
                          type: 'string',
                        },
                      ],
                    },
                  },
                },
              },
              required: ['images'],
              additionalProperties: false,
            },
            kmsKeyArn: { $ref: '#/definitions/awsKmsArn' },
            lambdaHashingVersion: {
              type: 'string',
              enum: ['20200924', '20201221'],
            },
            layers: { $ref: '#/definitions/awsLambdaLayers' },
            logRetentionInDays: {
              $ref: '#/definitions/awsLogRetentionInDays',
            },
            logDataProtectionPolicy: {
              $ref: '#/definitions/awsLogDataProtectionPolicy',
            },
            logs: {
              type: 'object',
              properties: {
                frameworkLambda: { type: 'boolean' },
                lambda: { $ref: '#/definitions/awsLambdaLoggingConfiguration' },
                httpApi: {
                  anyOf: [
                    { type: 'boolean' },
                    {
                      type: 'object',
                      properties: {
                        format: { type: 'string' },
                      },
                      additionalProperties: false,
                    },
                  ],
                },
                restApi: {
                  anyOf: [
                    { type: 'boolean' },
                    {
                      type: 'object',
                      properties: {
                        accessLogging: { type: 'boolean' },
                        executionLogging: { type: 'boolean' },
                        format: { type: 'string' },
                        fullExecutionData: { type: 'boolean' },
                        level: { enum: ['INFO', 'ERROR'] },
                        role: { $ref: '#/definitions/awsArn' },
                        roleManagedExternally: { type: 'boolean' },
                      },
                      additionalProperties: false,
                    },
                  ],
                },
                websocket: {
                  anyOf: [
                    { type: 'boolean' },
                    {
                      type: 'object',
                      properties: {
                        accessLogging: { type: 'boolean' },
                        executionLogging: { type: 'boolean' },
                        format: { type: 'string' },
                        fullExecutionData: { type: 'boolean' },
                        level: { enum: ['INFO', 'ERROR'] },
                      },
                      additionalProperties: false,
                    },
                  ],
                },
              },
            },
            memorySize: { $ref: '#/definitions/awsLambdaMemorySize' },
            notificationArns: {
              type: 'array',
              items: { $ref: '#/definitions/awsArnString' },
            },
            profile: { type: 'string' },
            region: {
              enum: [
                'us-east-1',
                'us-east-2',
                'us-gov-east-1',
                'us-gov-west-1',
                'us-iso-east-1',
                'us-iso-west-1',
                'us-isob-east-1',
                'us-west-1',
                'us-west-2',
                'af-south-1',
                'ap-east-1',
                'ap-northeast-1',
                'ap-northeast-2',
                'ap-northeast-3',
                'ap-south-1',
                'ap-south-2',
                'ap-southeast-1',
                'ap-southeast-2',
                'ap-southeast-3',
                'ap-southeast-4',
                'ap-southeast-5',
                'ca-central-1',
                'ca-west-1',
                'cn-north-1',
                'cn-northwest-1',
                'eu-central-1',
                'eu-central-2',
                'eu-north-1',
                'eu-south-1',
                'eu-south-2',
                'eu-west-1',
                'eu-west-2',
                'eu-west-3',
                'il-central-1',
                'me-central-1',
                'me-south-1',
                'sa-east-1',
              ],
            },
            resolver: { type: 'string' },
            role: { $ref: '#/definitions/awsLambdaRole' },
            rolePermissionsBoundary: { $ref: '#/definitions/awsArnString' },
            rollbackConfiguration: {
              type: 'object',
              properties: {
                RollbackTriggers: {
                  type: 'array',
                  items: {
                    type: 'object',
                    properties: {
                      Arn: { $ref: '#/definitions/awsArnString' },
                      Type: { const: 'AWS::CloudWatch::Alarm' },
                    },
                    additionalProperties: false,
                    required: ['Arn', 'Type'],
                  },
                },
                MonitoringTimeInMinutes: { type: 'integer', minimum: 0 },
              },
              additionalProperties: false,
            },
            runtime: { $ref: '#/definitions/awsLambdaRuntime' },
            runtimeManagement: {
              $ref: '#/definitions/awsLambdaRuntimeManagement',
            },
            build: { type: 'string' },
            deploymentMethod: { enum: ['changesets', 'direct'] },
            s3: {
              type: 'object',
              additionalProperties: awsS3ConfigSchema,
            },
            stage: { $ref: '#/definitions/stage' },
            stackName: {
              type: 'string',
              pattern: '^[a-zA-Z][a-zA-Z0-9-]*$',
              maxLength: 128,
            },
            stackParameters: {
              type: 'array',
              items: {
                type: 'object',
                properties: {
                  ParameterKey: { type: 'string' },
                  ParameterValue: { type: 'string' },
                  UsePreviousValue: { type: 'boolean' },
                  ResolvedValue: { type: 'string' },
                },
                additionalProperties: false,
              },
            },
            stackPolicy: { $ref: '#/definitions/awsIamPolicyStatements' },
            stackTags: { $ref: '#/definitions/awsResourceTags' },
            tags: { $ref: '#/definitions/awsResourceTags' },
            timeout: { $ref: '#/definitions/awsLambdaTimeout' },
            tracing: {
              type: 'object',
              properties: {
                apiGateway: { type: 'boolean' },
                lambda: { $ref: '#/definitions/awsLambdaTracing' },
              },
              additionalProperties: false,
            },
            vpc: { $ref: '#/definitions/awsLambdaVpcConfig' },
            vpcEndpointIds: { $ref: '#/definitions/awsCfArrayInstruction' },
            versionFunctions: { $ref: '#/definitions/awsLambdaVersioning' },
            websocket: {
              type: 'object',
              properties: {
                useProviderTags: { type: 'boolean' },
              },
              additionalProperties: false,
            },
            websocketsApiName: { type: 'string' },
            kinesis: {
              type: 'object',
              properties: {
                consumerNamingMode: { const: 'serviceSpecific' },
              },
              additionalProperties: false,
            },
            websocketsApiRouteSelectionExpression: { type: 'string' },
            websocketsDescription: { type: 'string' },
          },
        },
        function: {
          properties: {
            architecture: { $ref: '#/definitions/awsLambdaArchitecture' },
            awsKmsKeyArn: { $ref: '#/definitions/awsKmsArn' },
            condition: { $ref: '#/definitions/awsResourceCondition' },
            dependsOn: { $ref: '#/definitions/awsResourceDependsOn' },
            description: { type: 'string', maxLength: 256 },
            destinations: {
              type: 'object',
              properties: {
                onSuccess: {
                  anyOf: [
                    { type: 'string', minLength: 1 },
                    {
                      type: 'object',
                      properties: {
                        arn: { $ref: '#/definitions/awsCfFunction' },
                        type: { enum: ['function', 'sns', 'sqs', 'eventBus'] },
                      },
                      additionalProperties: false,
                      required: ['arn', 'type'],
                    },
                  ],
                },
                onFailure: {
                  anyOf: [
                    { type: 'string', minLength: 1 },
                    {
                      type: 'object',
                      properties: {
                        arn: { $ref: '#/definitions/awsCfFunction' },
                        type: { enum: ['function', 'sns', 'sqs', 'eventBus'] },
                      },
                      additionalProperties: false,
                      required: ['arn', 'type'],
                    },
                  ],
                },
              },
              additionalProperties: false,
            },
            disableLogs: { type: 'boolean' },
            environment: { $ref: '#/definitions/awsLambdaEnvironment' },
            ephemeralStorageSize: {
              type: 'integer',
              minimum: 512,
              maximum: 10240,
            },
            fileSystemConfig: {
              type: 'object',
              properties: {
                arn: {
                  anyOf: [
                    {
                      type: 'string',
                      pattern:
                        '^arn:aws[a-zA-Z-]*:elasticfilesystem:[a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-[1-9]{1}:[0-9]{12}:access-point/fsap-[a-f0-9]{17}$',
                    },
                    { $ref: '#/definitions/awsCfGetAtt' },
                    { $ref: '#/definitions/awsCfJoin' },
                    { $ref: '#/definitions/awsCfImport' },
                  ],
                },
                localMountPath: {
                  type: 'string',
                  pattern: '^/mnt/[a-zA-Z0-9-_.]+$',
                },
              },
              additionalProperties: false,
              required: ['localMountPath', 'arn'],
            },
            handler: { type: 'string' },
            image: {
              anyOf: [
                { $ref: '#/definitions/ecrImageUri' },
                {
                  type: 'string',
                  pattern: imageNamePattern,
                },
                {
                  type: 'object',
                  properties: {
                    name: {
                      type: 'string',
                      pattern: imageNamePattern,
                    },
                    uri: { $ref: '#/definitions/ecrImageUri' },
                    workingDirectory: {
                      type: 'string',
                    },
                    command: {
                      type: 'array',
                      items: {
                        type: 'string',
                      },
                    },
                    entryPoint: {
                      type: 'array',
                      items: {
                        type: 'string',
                      },
                    },
                  },
                  additionalProperties: false,
                },
              ],
            },
            kmsKeyArn: { $ref: '#/definitions/awsKmsArn' },
            snapStart: { type: 'boolean' },
            layers: { $ref: '#/definitions/awsLambdaLayers' },
            logRetentionInDays: {
              $ref: '#/definitions/awsLogRetentionInDays',
            },
            logDataProtectionPolicy: {
              $ref: '#/definitions/awsLogDataProtectionPolicy',
            },
            logs: {
              $ref: '#/definitions/awsLambdaLoggingConfiguration',
            },
            maximumEventAge: { type: 'integer', minimum: 60, maximum: 21600 },
            maximumRetryAttempts: { type: 'integer', minimum: 0, maximum: 2 },
            memorySize: { $ref: '#/definitions/awsLambdaMemorySize' },
            onError: {
              anyOf: [
                { type: 'string', pattern: '^arn:aws[a-z-]*:sns' },
                { $ref: '#/definitions/awsCfFunction' },
              ],
            },
            package: {
              type: 'object',
              properties: {
                artifact: { type: 'string' },
                exclude: { type: 'array', items: { type: 'string' } },
                include: { type: 'array', items: { type: 'string' } },
                individually: { type: 'boolean' },
                patterns: { type: 'array', items: { type: 'string' } },
              },
              additionalProperties: false,
            },
            provisionedConcurrency: cfValue({ type: 'integer', minimum: 0 }),
            reservedConcurrency: cfValue({ type: 'integer', minimum: 0 }),
            role: { $ref: '#/definitions/awsLambdaRole' },
            runtime: { $ref: '#/definitions/awsLambdaRuntime' },
            build: { type: 'string' },
            runtimeManagement: {
              $ref: '#/definitions/awsLambdaRuntimeManagement',
            },
            tags: { $ref: '#/definitions/awsResourceTags' },
            timeout: { $ref: '#/definitions/awsLambdaTimeout' },
            tracing: { $ref: '#/definitions/awsLambdaTracing' },
            url: {
              anyOf: [
                { type: 'boolean' },
                {
                  type: 'object',
                  properties: {
                    authorizer: { type: 'string', enum: ['aws_iam'] },
                    cors: {
                      anyOf: [
                        { type: 'boolean' },
                        {
                          type: 'object',
                          properties: {
                            allowCredentials: { type: 'boolean' },
                            allowedHeaders: {
                              type: 'array',
                              minItems: 1,
                              maxItems: 100,
                              items: { type: 'string' },
                            },
                            allowedMethods: {
                              type: 'array',
                              minItems: 1,
                              maxItems: 6,
                              items: { type: 'string' },
                            },
                            allowedOrigins: {
                              type: 'array',
                              minItems: 1,
                              maxItems: 100,
                              items: { type: 'string' },
                            },
                            exposedResponseHeaders: {
                              type: 'array',
                              minItems: 1,
                              maxItems: 100,
                              items: { type: 'string' },
                            },
                            maxAge: { type: 'integer', minimum: 0 },
                          },
                          additionalProperties: false,
                        },
                      ],
                    },
                    invokeMode: {
                      type: 'string',
                      enum: ['BUFFERED', 'RESPONSE_STREAM'],
                    },
                  },
                  additionalProperties: false,
                },
              ],
            },
            versionFunction: { $ref: '#/definitions/awsLambdaVersioning' },
            vpc: { $ref: '#/definitions/awsLambdaVpcConfig' },
            httpApi: {
              type: 'object',
              properties: {
                payload: { $ref: '#/definitions/awsHttpApiPayload' },
              },
              additionalProperties: false,
            },
          },
          additionalProperties: false,
        },
        layers: {
          type: 'object',
          additionalProperties: {
            type: 'object',
            properties: {
              allowedAccounts: {
                type: 'array',
                items: {
                  type: 'string',
                  pattern:
                    '^(\\d{12}|\\*|arn:(aws[a-zA-Z-]*):iam::\\d{12}:root)$',
                },
              },
              compatibleArchitectures: {
                type: 'array',
                items: { $ref: '#/definitions/awsLambdaArchitecture' },
                maxItems: 2,
              },
              compatibleRuntimes: {
                type: 'array',
                items: { $ref: '#/definitions/awsLambdaRuntime' },
                maxItems: 15,
              },
              description: { type: 'string', maxLength: 256 },
              licenseInfo: { type: 'string', maxLength: 512 },
              name: {
                type: 'string',
                minLength: 1,
                maxLength: 140,
                pattern:
                  '^((arn:[a-zA-Z0-9-]+:lambda:[a-zA-Z0-9-]+:\\d{12}:layer:[a-zA-Z0-9-_]+)|[a-zA-Z0-9-_]+)$',
              },
              package: {
                type: 'object',
                properties: {
                  artifact: { type: 'string' },
                  exclude: { type: 'array', items: { type: 'string' } },
                  include: { type: 'array', items: { type: 'string' } },
                  patterns: { type: 'array', items: { type: 'string' } },
                },
                additionalProperties: false,
              },
              path: { type: 'string' },
              retain: { type: 'boolean' },
            },
            additionalProperties: false,
          },
        },
        resources: {
          type: 'object',
          properties: {
            AWSTemplateFormatVersion: {
              type: 'string',
            },
            Conditions: {
              type: 'object',
            },
            Description: {
              type: 'string',
            },
            Mappings: {
              type: 'object',
            },
            Metadata: {
              type: 'object',
            },
            // According to https://s3.amazonaws.com/cfn-resource-specifications-us-east-1-prod/schemas/2.15.0/all-spec.json
            // `Outputs` is just an "object", though it seems like this is under-specifying that section a bit.
            // See also https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html
            Outputs: {
              type: 'object',
            },
            Parameters: {
              type: 'object',
            },
            // Not replicating the full JSON schema from https://s3.amazonaws.com/cfn-resource-specifications-us-east-1-prod/schemas/2.15.0/all-spec.json
            // as that gets into the specifics for each resource type.
            //
            // The only required attribute is `Type`; `Properties` and other common attributes are optional.
            // See also https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html
            Resources: {
              type: 'object',
              properties: {
                'Fn::Transform': {
                  type: 'object',
                  properties: {
                    Name: { type: 'string' },
                    Parameters: { type: 'object' },
                  },
                  required: ['Name'],
                  additionalProperties: false,
                },
              },
              patternProperties: {
                '^[a-zA-Z0-9]{1,255}$': {
                  type: 'object',
                  properties: {
                    Type: { type: 'string' },
                    Properties: { type: 'object' },
                    CreationPolicy: { type: 'object' },
                    DeletionPolicy: { type: 'string' },
                    DependsOn: { $ref: '#/definitions/awsResourceDependsOn' },
                    Metadata: { type: 'object' },
                    UpdatePolicy: { type: 'object' },
                    UpdateReplacePolicy: { type: 'string' },
                    Condition: { $ref: '#/definitions/awsResourceCondition' },
                  },
                  required: ['Type'],
                  additionalProperties: false,
                },
              },
              additionalProperties: false,
            },
            Transform: {
              type: 'array',
              items: { type: 'string' },
            },
            extensions: {
              type: 'object',
              patternProperties: {
                // names have the same restrictions as CloudFormation Resources section
                '^[a-zA-Z0-9]{1,255}$': {
                  type: 'object',
                  // this lists the supported properties, other properties are "Not supported. An error will be thrown
                  // if you try to extend an unsupported attribute."
                  // this is different than the above schema for `Resources`, which allows the `Type` attribute.
                  // extensions are explicitly meant to extend the definition of existing resources.
                  properties: {
                    Properties: { type: 'object' },
                    CreationPolicy: { type: 'object' },
                    DeletionPolicy: { type: 'string' },
                    DependsOn: { $ref: '#/definitions/awsResourceDependsOn' },
                    Metadata: { type: 'object' },
                    UpdatePolicy: { type: 'object' },
                    UpdateReplacePolicy: { type: 'string' },
                    Condition: { $ref: '#/definitions/awsResourceCondition' },
                  },
                  additionalProperties: false,
                },
              },
              additionalProperties: false,
            },
          },
          additionalProperties: false,
        },
      })
    }

    // Store credentials in this variable to avoid creating them several times (messes up MFA).
    this.cachedCredentials = null

    // Store accountId to be used in `generateTelemetry` logic
    this.accountId = null

    Object.assign(this.naming, naming)
  }
Add credentials, if present, from a profile that is specified within the environment
@param results The prefix of the profile's declaration in the environment
@param prefix The prefix for the environment variable