name: serverless-api
description: A serverless API template with Lambda functions and API Gateway
version: 1.0.0
author: CFN-Forge
cfnForgeVersion: 1.0.0

variables:
  projectName:
    prompt: "Project name"
    default: "my-serverless-api"
  description:
    prompt: "Project description"
    default: "A serverless API built with AWS Lambda and API Gateway"
  lambdaRuntime:
    prompt: "Lambda runtime"
    default: "nodejs18.x"
    options: ["nodejs18.x", "nodejs20.x", "python3.9", "python3.10", "python3.11"]
  memorySize:
    prompt: "Lambda memory size (MB)"
    default: "128"
    type: "number"

files:
  include:
    - "**/*"
  exclude:
    - "template.yaml"
    - ".git/**"
    - "node_modules/**"

structure:
  cloudformation.yaml: |
    AWSTemplateFormatVersion: '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    Description: {{description}}

    Parameters:
      Environment:
        Type: String
        Default: dev
        AllowedValues: [dev, staging, prod]
        Description: Environment name

    Globals:
      Function:
        Timeout: 30
        Runtime: {{lambdaRuntime}}
        MemorySize: {{memorySize}}
        Environment:
          Variables:
            NODE_ENV: !Ref Environment
            LOG_LEVEL: INFO

    Resources:
      # API Gateway
      ApiGateway:
        Type: AWS::Serverless::Api
        Properties:
          StageName: !Ref Environment
          Cors:
            AllowMethods: "'GET,POST,PUT,DELETE,OPTIONS'"
            AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
            AllowOrigin: "'*'"

      # Lambda Functions
      HelloWorldFunction:
        Type: AWS::Serverless::Function
        Properties:
          FunctionName: !Sub "${AWS::StackName}-hello-world"
          CodeUri: src/handlers/hello-world/
          Handler: index.handler
          Events:
            HelloWorldApi:
              Type: Api
              Properties:
                RestApiId: !Ref ApiGateway
                Path: /hello
                Method: GET

      CreateItemFunction:
        Type: AWS::Serverless::Function
        Properties:
          FunctionName: !Sub "${AWS::StackName}-create-item"
          CodeUri: src/handlers/create-item/
          Handler: index.handler
          Policies:
            - DynamoDBCrudPolicy:
                TableName: !Ref ItemsTable
          Events:
            CreateItemApi:
              Type: Api
              Properties:
                RestApiId: !Ref ApiGateway
                Path: /items
                Method: POST

      GetItemsFunction:
        Type: AWS::Serverless::Function
        Properties:
          FunctionName: !Sub "${AWS::StackName}-get-items"
          CodeUri: src/handlers/get-items/
          Handler: index.handler
          Policies:
            - DynamoDBReadPolicy:
                TableName: !Ref ItemsTable
          Events:
            GetItemsApi:
              Type: Api
              Properties:
                RestApiId: !Ref ApiGateway
                Path: /items
                Method: GET

      # DynamoDB Table
      ItemsTable:
        Type: AWS::DynamoDB::Table
        Properties:
          TableName: !Sub "${AWS::StackName}-items"
          BillingMode: PAY_PER_REQUEST
          AttributeDefinitions:
            - AttributeName: id
              AttributeType: S
          KeySchema:
            - AttributeName: id
              KeyType: HASH

    Outputs:
      ApiUrl:
        Description: API Gateway URL
        Value: !Sub "https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/${Environment}"
        Export:
          Name: !Sub "${AWS::StackName}-ApiUrl"
      
      ItemsTableName:
        Description: DynamoDB Items Table Name
        Value: !Ref ItemsTable
        Export:
          Name: !Sub "${AWS::StackName}-ItemsTable"

  .cfn-forge.yaml: |
    project:
      name: {{projectName}}
      description: {{description}}
      type: serverless-api

    environments:
      dev:
        stackName: "{{projectName}}-dev"
        template: cloudformation.yaml
        region: us-east-1
        parameters:
          Environment: dev
      
      staging:
        stackName: "{{projectName}}-staging"
        template: cloudformation.yaml
        region: us-east-1
        parameters:
          Environment: staging
      
      prod:
        stackName: "{{projectName}}-prod"
        template: cloudformation.yaml
        region: us-east-1
        parameters:
          Environment: prod

    deployment:
      packagingBucket: "{{projectName}}-deployment-artifacts"
      createBucket: true
      git:
        watchBranches: ["main", "develop"]
        deployOnPush: true

  package.json: |
    {
      "name": "{{projectName}}",
      "version": "1.0.0",
      "description": "{{description}}",
      "main": "src/handlers/hello-world/index.js",
      "scripts": {
        "start": "sam local start-api",
        "build": "sam build",
        "deploy": "cfn-forge deploy",
        "watch": "cfn-forge watch",
        "validate": "cfn-forge validate",
        "test": "jest",
        "test:watch": "jest --watch",
        "lint": "eslint src/"
      },
      "dependencies": {
        "aws-sdk": "^2.1490.0"
      },
      "devDependencies": {
        "jest": "^29.0.0",
        "eslint": "^8.0.0"
      },
      "keywords": ["serverless", "aws", "lambda", "api-gateway"],
      "author": "{{author}}",
      "license": "MIT"
    }

  src/handlers/hello-world/index.js: |
    exports.handler = async (event) => {
        console.log('Event:', JSON.stringify(event, null, 2));
        
        return {
            statusCode: 200,
            headers: {
                'Content-Type': 'application/json',
                'Access-Control-Allow-Origin': '*'
            },
            body: JSON.stringify({
                message: 'Hello from {{projectName}}!',
                timestamp: new Date().toISOString(),
                environment: process.env.NODE_ENV
            })
        };
    };

  src/handlers/create-item/index.js: |
    const AWS = require('aws-sdk');
    const { v4: uuidv4 } = require('uuid');
    
    const dynamodb = new AWS.DynamoDB.DocumentClient();
    const tableName = process.env.ITEMS_TABLE || '{{projectName}}-dev-items';
    
    exports.handler = async (event) => {
        console.log('Event:', JSON.stringify(event, null, 2));
        
        try {
            const body = JSON.parse(event.body || '{}');
            
            const item = {
                id: uuidv4(),
                ...body,
                createdAt: new Date().toISOString(),
                updatedAt: new Date().toISOString()
            };
            
            await dynamodb.put({
                TableName: tableName,
                Item: item
            }).promise();
            
            return {
                statusCode: 201,
                headers: {
                    'Content-Type': 'application/json',
                    'Access-Control-Allow-Origin': '*'
                },
                body: JSON.stringify({
                    message: 'Item created successfully',
                    item
                })
            };
        } catch (error) {
            console.error('Error:', error);
            return {
                statusCode: 500,
                headers: {
                    'Content-Type': 'application/json',
                    'Access-Control-Allow-Origin': '*'
                },
                body: JSON.stringify({
                    message: 'Internal server error',
                    error: error.message
                })
            };
        }
    };

  src/handlers/get-items/index.js: |
    const AWS = require('aws-sdk');
    
    const dynamodb = new AWS.DynamoDB.DocumentClient();
    const tableName = process.env.ITEMS_TABLE || '{{projectName}}-dev-items';
    
    exports.handler = async (event) => {
        console.log('Event:', JSON.stringify(event, null, 2));
        
        try {
            const result = await dynamodb.scan({
                TableName: tableName
            }).promise();
            
            return {
                statusCode: 200,
                headers: {
                    'Content-Type': 'application/json',
                    'Access-Control-Allow-Origin': '*'
                },
                body: JSON.stringify({
                    items: result.Items,
                    count: result.Count
                })
            };
        } catch (error) {
            console.error('Error:', error);
            return {
                statusCode: 500,
                headers: {
                    'Content-Type': 'application/json',
                    'Access-Control-Allow-Origin': '*'
                },
                body: JSON.stringify({
                    message: 'Internal server error',
                    error: error.message
                })
            };
        }
    };

  README.md: |
    # {{projectName}}

    {{description}}

    ## Quick Start

    1. Install dependencies:
       ```bash
       npm install
       ```

    2. Deploy to AWS:
       ```bash
       cfn-forge deploy
       ```

    3. Start local development:
       ```bash
       cfn-forge watch
       ```

    ## API Endpoints

    - `GET /hello` - Hello world endpoint
    - `GET /items` - Get all items
    - `POST /items` - Create a new item

    ## Project Structure

    ```
    {{projectName}}/
       src/
          handlers/
              hello-world/
              create-item/
              get-items/
       cloudformation.yaml
       .cfn-forge.yaml
       package.json
    ```

    ## Deployment

    This project uses CFN-Forge for deployment. The configuration is in `.cfn-forge.yaml`.

    ### Environments

    - **dev**: Development environment
    - **staging**: Staging environment  
    - **prod**: Production environment

    ### Commands

    - `cfn-forge deploy` - Deploy to the default environment
    - `cfn-forge deploy --env prod` - Deploy to production
    - `cfn-forge watch` - Watch for changes and auto-deploy
    - `cfn-forge validate` - Validate CloudFormation template

hooks:
  postInstall:
    - type: npm
      command: install