CloudFormation
          1,385 lines of IaC template
          {
  "AWSTemplateFormatVersion": "2010-09-09",
  "Transform": "AWS::Serverless-2016-10-31",
  "Description": "Example: kitchen sink",
  "Resources": {
    "Role": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": "lambda.amazonaws.com"
              },
              "Action": "sts:AssumeRole"
            }
          ]
        },
        "Policies": [
          {
            "PolicyName": "ArcGlobalPolicy",
            "PolicyDocument": {
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": [
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents",
                    "logs:DescribeLogStreams"
                  ],
                  "Resource": "arn:aws:logs:*:*:*"
                }
              ]
            }
          },
          {
            "PolicyName": "ArcStaticBucketPolicy",
            "PolicyDocument": {
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": [
                    "s3:GetObject",
                    "s3:PutObject",
                    "s3:PutObjectAcl",
                    "s3:DeleteObject",
                    "s3:ListBucket"
                  ],
                  "Resource": [
                    {
                      "Fn::Sub": [
                        "arn:aws:s3:::${bukkit}",
                        {
                          "bukkit": {
                            "Ref": "StaticBucket"
                          }
                        }
                      ]
                    },
                    {
                      "Fn::Sub": [
                        "arn:aws:s3:::${bukkit}/*",
                        {
                          "bukkit": {
                            "Ref": "StaticBucket"
                          }
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          },
          {
            "PolicyName": "ArcDynamoPolicy",
            "PolicyDocument": {
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": "dynamodb:*",
                  "Resource": [
                    {
                      "Fn::Sub": [
                        "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tablename}",
                        {
                          "tablename": {
                            "Ref": "LikesTable"
                          }
                        }
                      ]
                    },
                    {
                      "Fn::Sub": [
                        "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tablename}/*",
                        {
                          "tablename": {
                            "Ref": "LikesTable"
                          }
                        }
                      ]
                    }
                  ]
                },
                {
                  "Effect": "Deny",
                  "Action": "dynamodb:DeleteTable",
                  "Resource": {
                    "Fn::Sub": "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/*"
                  }
                }
              ]
            }
          },
          {
            "PolicyName": "ArcSimpleNotificationServicePolicy",
            "PolicyDocument": {
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": [
                    "sns:Publish"
                  ],
                  "Resource": {
                    "Fn::Sub": [
                      "arn:aws:sns:${AWS::Region}:${AWS::AccountId}:${AWS::StackName}*",
                      {}
                    ]
                  }
                }
              ]
            }
          }
        ]
      }
    },
    "LikesParam": {
      "Type": "AWS::SSM::Parameter",
      "Properties": {
        "Type": "String",
        "Name": {
          "Fn::Sub": [
            "/${AWS::StackName}/tables/${tablename}",
            {
              "tablename": "likes"
            }
          ]
        },
        "Value": {
          "Ref": "LikesTable"
        }
      }
    },
    "HitCounterEventTopicParam": {
      "Type": "AWS::SSM::Parameter",
      "Properties": {
        "Type": "String",
        "Name": {
          "Fn::Sub": [
            "/${AWS::StackName}/events/${event}",
            {
              "event": "hit-counter"
            }
          ]
        },
        "Value": {
          "Ref": "HitCounterEventTopic"
        }
      }
    },
    "StaticBucketParam": {
      "Type": "AWS::SSM::Parameter",
      "Properties": {
        "Type": "String",
        "Name": {
          "Fn::Sub": [
            "/${AWS::StackName}/static/${key}",
            {
              "key": "bucket"
            }
          ]
        },
        "Value": {
          "Ref": "StaticBucket"
        }
      }
    },
    "StaticFingerprintParam": {
      "Type": "AWS::SSM::Parameter",
      "Properties": {
        "Type": "String",
        "Name": {
          "Fn::Sub": [
            "/${AWS::StackName}/static/${key}",
            {
              "key": "fingerprint"
            }
          ]
        },
        "Value": "true"
      }
    },
    "ParameterStorePolicy": {
      "Type": "AWS::IAM::Policy",
      "DependsOn": "Role",
      "Properties": {
        "PolicyName": "ArcParameterStorePolicy",
        "PolicyDocument": {
          "Statement": [
            {
              "Effect": "Allow",
              "Action": [
                "ssm:GetParametersByPath",
                "ssm:GetParameter"
              ],
              "Resource": {
                "Fn::Sub": [
                  "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${AWS::StackName}",
                  {}
                ]
              }
            },
            {
              "Effect": "Allow",
              "Action": [
                "ssm:GetParametersByPath",
                "ssm:GetParameter"
              ],
              "Resource": {
                "Fn::Sub": [
                  "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${AWS::StackName}/*",
                  {}
                ]
              }
            },
            {
              "Effect": "Allow",
              "Action": [
                "ssm:GetParametersByPath",
                "ssm:GetParameter"
              ],
              "Resource": {
                "Fn::Sub": [
                  "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${AWS::StackName}/*/*",
                  {}
                ]
              }
            }
          ]
        },
        "Roles": [
          {
            "Ref": "Role"
          }
        ]
      }
    },
    "HTTP": {
      "Type": "AWS::Serverless::HttpApi",
      "Properties": {
        "StageName": "$default",
        "DefinitionBody": {
          "openapi": "3.0.1",
          "info": {
            "title": {
              "Ref": "AWS::StackName"
            }
          },
          "paths": {
            "/likes": {
              "get": {
                "x-amazon-apigateway-integration": {
                  "payloadFormatVersion": "2.0",
                  "type": "aws_proxy",
                  "httpMethod": "POST",
                  "uri": {
                    "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetLikesHTTPLambda.Arn}/invocations"
                  },
                  "connectionType": "INTERNET"
                }
              },
              "post": {
                "x-amazon-apigateway-integration": {
                  "payloadFormatVersion": "2.0",
                  "type": "aws_proxy",
                  "httpMethod": "POST",
                  "uri": {
                    "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PostLikesHTTPLambda.Arn}/invocations"
                  },
                  "connectionType": "INTERNET"
                }
              }
            },
            "/": {
              "get": {
                "x-amazon-apigateway-integration": {
                  "payloadFormatVersion": "2.0",
                  "type": "aws_proxy",
                  "httpMethod": "POST",
                  "uri": {
                    "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetIndexHTTPLambda.Arn}/invocations"
                  },
                  "connectionType": "INTERNET"
                }
              }
            },
            "/_static/{proxy+}": {
              "get": {
                "x-amazon-apigateway-integration": {
                  "payloadFormatVersion": "1.0",
                  "type": "http_proxy",
                  "httpMethod": "GET",
                  "uri": {
                    "Fn::Sub": [
                      "https://${bukkit}.s3.${AWS::Region}.amazonaws.com/{proxy}",
                      {
                        "bukkit": {
                          "Ref": "StaticBucket"
                        }
                      }
                    ]
                  },
                  "connectionType": "INTERNET",
                  "timeoutInMillis": 30000
                }
              }
            }
          }
        }
      }
    },
    "GetLikesHTTPLambda": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "Handler": "index.handler",
        "CodeUri": "/var/task/src/http/get-likes",
        "Runtime": "nodejs20.x",
        "Architectures": [
          "arm64"
        ],
        "MemorySize": 1152,
        "EphemeralStorage": {
          "Size": 512
        },
        "Timeout": 5,
        "Environment": {
          "Variables": {
            "ARC_APP_NAME": "hello",
            "ARC_ENV": "staging",
            "ARC_ROLE": {
              "Ref": "Role"
            },
            "ARC_SESSION_TABLE_NAME": "jwe",
            "ARC_STACK_NAME": {
              "Ref": "AWS::StackName"
            },
            "ARC_STATIC_BUCKET": {
              "Ref": "StaticBucket"
            },
            "ARC_WSS_URL": {
              "Fn::Sub": [
                "wss://${WS}.execute-api.${AWS::Region}.amazonaws.com/staging",
                {}
              ]
            }
          }
        },
        "Role": {
          "Fn::Sub": [
            "arn:aws:iam::${AWS::AccountId}:role/${roleName}",
            {
              "roleName": {
                "Ref": "Role"
              }
            }
          ]
        },
        "Events": {
          "GetLikesHTTPEvent": {
            "Type": "HttpApi",
            "Properties": {
              "Path": "/likes",
              "Method": "GET",
              "ApiId": {
                "Ref": "HTTP"
              }
            }
          }
        }
      },
      "ArcMetadata": {
        "pragma": "http",
        "name": "get /likes",
        "method": "get",
        "path": "/likes"
      }
    },
    "GetIndexHTTPLambda": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "Handler": "index.handler",
        "CodeUri": "/var/task/src/http/get-index",
        "Runtime": "nodejs20.x",
        "Architectures": [
          "arm64"
        ],
        "MemorySize": 1152,
        "EphemeralStorage": {
          "Size": 512
        },
        "Timeout": 5,
        "Environment": {
          "Variables": {
            "ARC_APP_NAME": "hello",
            "ARC_ENV": "staging",
            "ARC_ROLE": {
              "Ref": "Role"
            },
            "ARC_SESSION_TABLE_NAME": "jwe",
            "ARC_STACK_NAME": {
              "Ref": "AWS::StackName"
            },
            "ARC_STATIC_BUCKET": {
              "Ref": "StaticBucket"
            },
            "ARC_WSS_URL": {
              "Fn::Sub": [
                "wss://${WS}.execute-api.${AWS::Region}.amazonaws.com/staging",
                {}
              ]
            },
            "ARC_STATIC_SPA": false
          }
        },
        "Role": {
          "Fn::Sub": [
            "arn:aws:iam::${AWS::AccountId}:role/${roleName}",
            {
              "roleName": {
                "Ref": "Role"
              }
            }
          ]
        },
        "Events": {
          "GetIndexHTTPEvent": {
            "Type": "HttpApi",
            "Properties": {
              "Path": "/",
              "Method": "GET",
              "ApiId": {
                "Ref": "HTTP"
              }
            }
          }
        }
      },
      "ArcMetadata": {
        "pragma": "http",
        "name": "get /",
        "method": "get",
        "path": "/"
      }
    },
    "PostLikesHTTPLambda": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "Handler": "index.handler",
        "CodeUri": "/var/task/src/http/post-likes",
        "Runtime": "nodejs20.x",
        "Architectures": [
          "arm64"
        ],
        "MemorySize": 1152,
        "EphemeralStorage": {
          "Size": 512
        },
        "Timeout": 5,
        "Environment": {
          "Variables": {
            "ARC_APP_NAME": "hello",
            "ARC_ENV": "staging",
            "ARC_ROLE": {
              "Ref": "Role"
            },
            "ARC_SESSION_TABLE_NAME": "jwe",
            "ARC_STACK_NAME": {
              "Ref": "AWS::StackName"
            },
            "ARC_STATIC_BUCKET": {
              "Ref": "StaticBucket"
            },
            "ARC_WSS_URL": {
              "Fn::Sub": [
                "wss://${WS}.execute-api.${AWS::Region}.amazonaws.com/staging",
                {}
              ]
            }
          }
        },
        "Role": {
          "Fn::Sub": [
            "arn:aws:iam::${AWS::AccountId}:role/${roleName}",
            {
              "roleName": {
                "Ref": "Role"
              }
            }
          ]
        },
        "Events": {
          "PostLikesHTTPEvent": {
            "Type": "HttpApi",
            "Properties": {
              "Path": "/likes",
              "Method": "POST",
              "ApiId": {
                "Ref": "HTTP"
              }
            }
          }
        }
      },
      "ArcMetadata": {
        "pragma": "http",
        "name": "post /likes",
        "method": "post",
        "path": "/likes"
      }
    },
    "LikesTable": {
      "Type": "AWS::DynamoDB::Table",
      "Properties": {
        "KeySchema": [
          {
            "AttributeName": "likeID",
            "KeyType": "HASH"
          }
        ],
        "AttributeDefinitions": [
          {
            "AttributeName": "likeID",
            "AttributeType": "S"
          },
          {
            "AttributeName": "date",
            "AttributeType": "S"
          }
        ],
        "BillingMode": "PAY_PER_REQUEST",
        "GlobalSecondaryIndexes": [
          {
            "IndexName": "date-index",
            "KeySchema": [
              {
                "AttributeName": "date",
                "KeyType": "HASH"
              }
            ],
            "Projection": {
              "ProjectionType": "ALL"
            }
          }
        ],
        "StreamSpecification": {
          "StreamViewType": "NEW_AND_OLD_IMAGES"
        }
      }
    },
    "HitCounterEventLambda": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "Handler": "index.handler",
        "CodeUri": "/var/task/src/events/hit-counter",
        "Runtime": "nodejs20.x",
        "Architectures": [
          "arm64"
        ],
        "MemorySize": 1152,
        "EphemeralStorage": {
          "Size": 512
        },
        "Timeout": 5,
        "Environment": {
          "Variables": {
            "ARC_APP_NAME": "hello",
            "ARC_ENV": "staging",
            "ARC_ROLE": {
              "Ref": "Role"
            },
            "ARC_SESSION_TABLE_NAME": "jwe",
            "ARC_STACK_NAME": {
              "Ref": "AWS::StackName"
            },
            "ARC_STATIC_BUCKET": {
              "Ref": "StaticBucket"
            },
            "ARC_WSS_URL": {
              "Fn::Sub": [
                "wss://${WS}.execute-api.${AWS::Region}.amazonaws.com/staging",
                {}
              ]
            }
          }
        },
        "Role": {
          "Fn::Sub": [
            "arn:aws:iam::${AWS::AccountId}:role/${roleName}",
            {
              "roleName": {
                "Ref": "Role"
              }
            }
          ]
        },
        "Events": {
          "HitCounterEvent": {
            "Type": "SNS",
            "Properties": {
              "Topic": {
                "Ref": "HitCounterEventTopic"
              }
            }
          }
        }
      },
      "ArcMetadata": {
        "pragma": "events",
        "name": "hit-counter"
      }
    },
    "HitCounterEventTopic": {
      "Type": "AWS::SNS::Topic",
      "Properties": {
        "DisplayName": "HitCounter",
        "Subscription": []
      }
    },
    "DailyAffirmationScheduledLambda": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "Handler": "index.handler",
        "CodeUri": "/var/task/src/scheduled/daily-affirmation",
        "Runtime": "nodejs20.x",
        "Architectures": [
          "arm64"
        ],
        "MemorySize": 1152,
        "EphemeralStorage": {
          "Size": 512
        },
        "Timeout": 5,
        "Environment": {
          "Variables": {
            "ARC_APP_NAME": "hello",
            "ARC_ENV": "staging",
            "ARC_ROLE": {
              "Ref": "Role"
            },
            "ARC_SESSION_TABLE_NAME": "jwe",
            "ARC_STACK_NAME": {
              "Ref": "AWS::StackName"
            },
            "ARC_STATIC_BUCKET": {
              "Ref": "StaticBucket"
            },
            "ARC_WSS_URL": {
              "Fn::Sub": [
                "wss://${WS}.execute-api.${AWS::Region}.amazonaws.com/staging",
                {}
              ]
            }
          }
        },
        "Role": {
          "Fn::Sub": [
            "arn:aws:iam::${AWS::AccountId}:role/${roleName}",
            {
              "roleName": {
                "Ref": "Role"
              }
            }
          ]
        },
        "Events": {}
      },
      "ArcMetadata": {
        "pragma": "scheduled",
        "name": "daily-affirmation"
      }
    },
    "DailyAffirmationScheduledEvent": {
      "Type": "AWS::Events::Rule",
      "Properties": {
        "ScheduleExpression": "rate(1 day)",
        "Targets": [
          {
            "Arn": {
              "Fn::GetAtt": [
                "DailyAffirmationScheduledLambda",
                "Arn"
              ]
            },
            "Id": "DailyAffirmationScheduledLambda"
          }
        ]
      }
    },
    "DailyAffirmationScheduledPermission": {
      "Type": "AWS::Lambda::Permission",
      "Properties": {
        "Action": "lambda:InvokeFunction",
        "FunctionName": {
          "Ref": "DailyAffirmationScheduledLambda"
        },
        "Principal": "events.amazonaws.com",
        "SourceArn": {
          "Fn::GetAtt": [
            "DailyAffirmationScheduledEvent",
            "Arn"
          ]
        }
      }
    },
    "StaticBucket": {
      "Type": "AWS::S3::Bucket",
      "Properties": {
        "OwnershipControls": {
          "Rules": [
            {
              "ObjectOwnership": "BucketOwnerEnforced"
            }
          ]
        },
        "WebsiteConfiguration": {
          "IndexDocument": "index.html",
          "ErrorDocument": "404.html"
        },
        "PublicAccessBlockConfiguration": {
          "BlockPublicAcls": false,
          "BlockPublicPolicy": false,
          "IgnorePublicAcls": false,
          "RestrictPublicBuckets": false
        }
      }
    },
    "StaticBucketPolicy": {
      "Type": "AWS::S3::BucketPolicy",
      "Properties": {
        "Bucket": {
          "Ref": "StaticBucket"
        },
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Action": [
                "s3:GetObject"
              ],
              "Effect": "Allow",
              "Principal": "*",
              "Resource": [
                {
                  "Fn::Sub": [
                    "arn:aws:s3:::${bukkit}/*",
                    {
                      "bukkit": {
                        "Ref": "StaticBucket"
                      }
                    }
                  ]
                }
              ],
              "Sid": "PublicReadGetObject"
            }
          ]
        }
      }
    },
    "LikesTableStreamLambda": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "Handler": "index.handler",
        "CodeUri": "/var/task/src/tables-streams/likes",
        "Runtime": "nodejs20.x",
        "Architectures": [
          "arm64"
        ],
        "MemorySize": 1152,
        "EphemeralStorage": {
          "Size": 512
        },
        "Timeout": 5,
        "Environment": {
          "Variables": {
            "ARC_APP_NAME": "hello",
            "ARC_ENV": "staging",
            "ARC_ROLE": {
              "Ref": "Role"
            },
            "ARC_SESSION_TABLE_NAME": "jwe",
            "ARC_STACK_NAME": {
              "Ref": "AWS::StackName"
            },
            "ARC_STATIC_BUCKET": {
              "Ref": "StaticBucket"
            },
            "ARC_WSS_URL": {
              "Fn::Sub": [
                "wss://${WS}.execute-api.${AWS::Region}.amazonaws.com/staging",
                {}
              ]
            }
          }
        },
        "Role": {
          "Fn::Sub": [
            "arn:aws:iam::${AWS::AccountId}:role/${roleName}",
            {
              "roleName": {
                "Ref": "Role"
              }
            }
          ]
        },
        "Events": {}
      },
      "ArcMetadata": {
        "pragma": "tables-streams",
        "name": "likes"
      }
    },
    "LikesTableStreamEvent": {
      "Type": "AWS::Lambda::EventSourceMapping",
      "Properties": {
        "BatchSize": 10,
        "EventSourceArn": {
          "Fn::GetAtt": [
            "LikesTable",
            "StreamArn"
          ]
        },
        "FunctionName": {
          "Fn::GetAtt": [
            "LikesTableStreamLambda",
            "Arn"
          ]
        },
        "StartingPosition": "TRIM_HORIZON"
      }
    },
    "WS": {
      "Type": "AWS::ApiGatewayV2::Api",
      "Properties": {
        "Name": "HelloWebsocketStaging",
        "ProtocolType": "WEBSOCKET",
        "RouteSelectionExpression": "$request.body.action"
      }
    },
    "WebsocketDeployment": {
      "Type": "AWS::ApiGatewayV2::Deployment",
      "DependsOn": [
        "ConnectWSRoute",
        "DefaultWSRoute",
        "DisconnectWSRoute"
      ],
      "Properties": {
        "ApiId": {
          "Ref": "WS"
        }
      }
    },
    "WebsocketStage": {
      "Type": "AWS::ApiGatewayV2::Stage",
      "Properties": {
        "StageName": "staging",
        "DeploymentId": {
          "Ref": "WebsocketDeployment"
        },
        "ApiId": {
          "Ref": "WS"
        }
      }
    },
    "WebSocketPolicy": {
      "Type": "AWS::IAM::Policy",
      "DependsOn": "Role",
      "Properties": {
        "PolicyName": "ArcWebSocketPolicy",
        "PolicyDocument": {
          "Statement": [
            {
              "Effect": "Allow",
              "Action": [
                "execute-api:Invoke",
                "execute-api:ManageConnections"
              ],
              "Resource": [
                {
                  "Fn::Sub": [
                    "arn:aws:execute-api:${AWS::Region}:*:${api}/*",
                    {
                      "api": {
                        "Ref": "WS"
                      }
                    }
                  ]
                }
              ]
            }
          ]
        },
        "Roles": [
          {
            "Ref": "Role"
          }
        ]
      }
    },
    "ActionWSLambda": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "Handler": "index.handler",
        "CodeUri": "/var/task/src/ws/action",
        "Runtime": "nodejs20.x",
        "Architectures": [
          "arm64"
        ],
        "MemorySize": 1152,
        "EphemeralStorage": {
          "Size": 512
        },
        "Timeout": 5,
        "Environment": {
          "Variables": {
            "ARC_APP_NAME": "hello",
            "ARC_ENV": "staging",
            "ARC_ROLE": {
              "Ref": "Role"
            },
            "ARC_SESSION_TABLE_NAME": "jwe",
            "ARC_STACK_NAME": {
              "Ref": "AWS::StackName"
            },
            "ARC_STATIC_BUCKET": {
              "Ref": "StaticBucket"
            },
            "ARC_WSS_URL": {
              "Fn::Sub": [
                "wss://${WS}.execute-api.${AWS::Region}.amazonaws.com/staging",
                {}
              ]
            }
          }
        },
        "Role": {
          "Fn::Sub": [
            "arn:aws:iam::${AWS::AccountId}:role/${roleName}",
            {
              "roleName": {
                "Ref": "Role"
              }
            }
          ]
        },
        "Events": {}
      },
      "ArcMetadata": {
        "pragma": "ws",
        "name": "action"
      }
    },
    "ActionWSRoute": {
      "Type": "AWS::ApiGatewayV2::Route",
      "Properties": {
        "ApiId": {
          "Ref": "WS"
        },
        "RouteKey": "action",
        "OperationName": "ActionWSRoute",
        "Target": {
          "Fn::Join": [
            "/",
            [
              "integrations",
              {
                "Ref": "ActionWSIntegration"
              }
            ]
          ]
        }
      }
    },
    "ActionWSIntegration": {
      "Type": "AWS::ApiGatewayV2::Integration",
      "Properties": {
        "ApiId": {
          "Ref": "WS"
        },
        "IntegrationType": "AWS_PROXY",
        "IntegrationUri": {
          "Fn::Sub": [
            "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ActionWSLambda.Arn}/invocations",
            {}
          ]
        }
      }
    },
    "ActionWSPermission": {
      "Type": "AWS::Lambda::Permission",
      "DependsOn": [
        "WS",
        "ActionWSLambda"
      ],
      "Properties": {
        "Action": "lambda:InvokeFunction",
        "FunctionName": {
          "Ref": "ActionWSLambda"
        },
        "Principal": "apigateway.amazonaws.com"
      }
    },
    "ConnectWSLambda": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "Handler": "index.handler",
        "CodeUri": "/var/task/src/ws/connect",
        "Runtime": "nodejs20.x",
        "Architectures": [
          "arm64"
        ],
        "MemorySize": 1152,
        "EphemeralStorage": {
          "Size": 512
        },
        "Timeout": 5,
        "Environment": {
          "Variables": {
            "ARC_APP_NAME": "hello",
            "ARC_ENV": "staging",
            "ARC_ROLE": {
              "Ref": "Role"
            },
            "ARC_SESSION_TABLE_NAME": "jwe",
            "ARC_STACK_NAME": {
              "Ref": "AWS::StackName"
            },
            "ARC_STATIC_BUCKET": {
              "Ref": "StaticBucket"
            },
            "ARC_WSS_URL": {
              "Fn::Sub": [
                "wss://${WS}.execute-api.${AWS::Region}.amazonaws.com/staging",
                {}
              ]
            }
          }
        },
        "Role": {
          "Fn::Sub": [
            "arn:aws:iam::${AWS::AccountId}:role/${roleName}",
            {
              "roleName": {
                "Ref": "Role"
              }
            }
          ]
        },
        "Events": {}
      },
      "ArcMetadata": {
        "pragma": "ws",
        "name": "connect"
      }
    },
    "ConnectWSRoute": {
      "Type": "AWS::ApiGatewayV2::Route",
      "Properties": {
        "ApiId": {
          "Ref": "WS"
        },
        "RouteKey": "$connect",
        "OperationName": "ConnectWSRoute",
        "Target": {
          "Fn::Join": [
            "/",
            [
              "integrations",
              {
                "Ref": "ConnectWSIntegration"
              }
            ]
          ]
        }
      }
    },
    "ConnectWSIntegration": {
      "Type": "AWS::ApiGatewayV2::Integration",
      "Properties": {
        "ApiId": {
          "Ref": "WS"
        },
        "IntegrationType": "AWS_PROXY",
        "IntegrationUri": {
          "Fn::Sub": [
            "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ConnectWSLambda.Arn}/invocations",
            {}
          ]
        }
      }
    },
    "ConnectWSPermission": {
      "Type": "AWS::Lambda::Permission",
      "DependsOn": [
        "WS",
        "ConnectWSLambda"
      ],
      "Properties": {
        "Action": "lambda:InvokeFunction",
        "FunctionName": {
          "Ref": "ConnectWSLambda"
        },
        "Principal": "apigateway.amazonaws.com"
      }
    },
    "DefaultWSLambda": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "Handler": "index.handler",
        "CodeUri": "/var/task/src/ws/default",
        "Runtime": "nodejs20.x",
        "Architectures": [
          "arm64"
        ],
        "MemorySize": 1152,
        "EphemeralStorage": {
          "Size": 512
        },
        "Timeout": 5,
        "Environment": {
          "Variables": {
            "ARC_APP_NAME": "hello",
            "ARC_ENV": "staging",
            "ARC_ROLE": {
              "Ref": "Role"
            },
            "ARC_SESSION_TABLE_NAME": "jwe",
            "ARC_STACK_NAME": {
              "Ref": "AWS::StackName"
            },
            "ARC_STATIC_BUCKET": {
              "Ref": "StaticBucket"
            },
            "ARC_WSS_URL": {
              "Fn::Sub": [
                "wss://${WS}.execute-api.${AWS::Region}.amazonaws.com/staging",
                {}
              ]
            }
          }
        },
        "Role": {
          "Fn::Sub": [
            "arn:aws:iam::${AWS::AccountId}:role/${roleName}",
            {
              "roleName": {
                "Ref": "Role"
              }
            }
          ]
        },
        "Events": {}
      },
      "ArcMetadata": {
        "pragma": "ws",
        "name": "default"
      }
    },
    "DefaultWSRoute": {
      "Type": "AWS::ApiGatewayV2::Route",
      "Properties": {
        "ApiId": {
          "Ref": "WS"
        },
        "RouteKey": "$default",
        "OperationName": "DefaultWSRoute",
        "Target": {
          "Fn::Join": [
            "/",
            [
              "integrations",
              {
                "Ref": "DefaultWSIntegration"
              }
            ]
          ]
        }
      }
    },
    "DefaultWSIntegration": {
      "Type": "AWS::ApiGatewayV2::Integration",
      "Properties": {
        "ApiId": {
          "Ref": "WS"
        },
        "IntegrationType": "AWS_PROXY",
        "IntegrationUri": {
          "Fn::Sub": [
            "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${DefaultWSLambda.Arn}/invocations",
            {}
          ]
        }
      }
    },
    "DefaultWSPermission": {
      "Type": "AWS::Lambda::Permission",
      "DependsOn": [
        "WS",
        "DefaultWSLambda"
      ],
      "Properties": {
        "Action": "lambda:InvokeFunction",
        "FunctionName": {
          "Ref": "DefaultWSLambda"
        },
        "Principal": "apigateway.amazonaws.com"
      }
    },
    "DisconnectWSLambda": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "Handler": "index.handler",
        "CodeUri": "/var/task/src/ws/disconnect",
        "Runtime": "nodejs20.x",
        "Architectures": [
          "arm64"
        ],
        "MemorySize": 1152,
        "EphemeralStorage": {
          "Size": 512
        },
        "Timeout": 5,
        "Environment": {
          "Variables": {
            "ARC_APP_NAME": "hello",
            "ARC_ENV": "staging",
            "ARC_ROLE": {
              "Ref": "Role"
            },
            "ARC_SESSION_TABLE_NAME": "jwe",
            "ARC_STACK_NAME": {
              "Ref": "AWS::StackName"
            },
            "ARC_STATIC_BUCKET": {
              "Ref": "StaticBucket"
            },
            "ARC_WSS_URL": {
              "Fn::Sub": [
                "wss://${WS}.execute-api.${AWS::Region}.amazonaws.com/staging",
                {}
              ]
            }
          }
        },
        "Role": {
          "Fn::Sub": [
            "arn:aws:iam::${AWS::AccountId}:role/${roleName}",
            {
              "roleName": {
                "Ref": "Role"
              }
            }
          ]
        },
        "Events": {}
      },
      "ArcMetadata": {
        "pragma": "ws",
        "name": "disconnect"
      }
    },
    "DisconnectWSRoute": {
      "Type": "AWS::ApiGatewayV2::Route",
      "Properties": {
        "ApiId": {
          "Ref": "WS"
        },
        "RouteKey": "$disconnect",
        "OperationName": "DisconnectWSRoute",
        "Target": {
          "Fn::Join": [
            "/",
            [
              "integrations",
              {
                "Ref": "DisconnectWSIntegration"
              }
            ]
          ]
        }
      }
    },
    "DisconnectWSIntegration": {
      "Type": "AWS::ApiGatewayV2::Integration",
      "Properties": {
        "ApiId": {
          "Ref": "WS"
        },
        "IntegrationType": "AWS_PROXY",
        "IntegrationUri": {
          "Fn::Sub": [
            "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${DisconnectWSLambda.Arn}/invocations",
            {}
          ]
        }
      }
    },
    "DisconnectWSPermission": {
      "Type": "AWS::Lambda::Permission",
      "DependsOn": [
        "WS",
        "DisconnectWSLambda"
      ],
      "Properties": {
        "Action": "lambda:InvokeFunction",
        "FunctionName": {
          "Ref": "DisconnectWSLambda"
        },
        "Principal": "apigateway.amazonaws.com"
      }
    }
  },
  "Outputs": {
    "API": {
      "Description": "API Gateway (HTTP)",
      "Value": {
        "Fn::Sub": [
          "https://${ApiId}.execute-api.${AWS::Region}.amazonaws.com",
          {
            "ApiId": {
              "Ref": "HTTP"
            }
          }
        ]
      }
    },
    "ApiId": {
      "Description": "API ID (ApiId)",
      "Value": {
        "Ref": "HTTP"
      }
    },
    "HitCounterEventTopic": {
      "Description": "An SNS Topic",
      "Value": {
        "Ref": "HitCounterEventTopic"
      }
    },
    "BucketURL": {
      "Description": "Bucket URL",
      "Value": {
        "Fn::Sub": [
          "http://${bukkit}.s3-website-${AWS::Region}.amazonaws.com",
          {
            "bukkit": {
              "Ref": "StaticBucket"
            }
          }
        ]
      }
    },
    "WSS": {
      "Description": "WebSocket Endpoint",
      "Value": {
        "Fn::Sub": [
          "wss://${WS}.execute-api.${AWS::Region}.amazonaws.com/staging",
          {}
        ]
      }
    }
  }
}