name: basic-lambda
description: Simple AWS Lambda function with CloudWatch logging and basic permissions
version: 1.0.0
author: CFN-Forge
cfnForgeVersion: 1.0.0

variables:
  projectName:
    prompt: "Project name"
    default: "my-lambda-function"
  description:
    prompt: "Project description"
    default: "A basic AWS Lambda function"
  runtime:
    prompt: "Lambda runtime"
    default: "nodejs18.x"
    options: ["nodejs18.x", "nodejs20.x", "python3.9", "python3.10", "python3.11", "python3.12"]
  memorySize:
    prompt: "Memory size (MB)"
    default: "128"
    type: "number"
  timeout:
    prompt: "Timeout (seconds)"
    default: "30"
    type: "number"
  triggerType:
    prompt: "Trigger type"
    default: "manual"
    options: ["manual", "s3", "eventbridge", "sqs"]

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

    Conditions:
      HasS3Trigger: !Equals ["{{triggerType}}", "s3"]
      HasEventBridgeTrigger: !Equals ["{{triggerType}}", "eventbridge"]
      HasSQSTrigger: !Equals ["{{triggerType}}", "sqs"]

    Resources:
      # Lambda Function
      {{projectName}}Function:
        Type: AWS::Serverless::Function
        Properties:
          FunctionName: !Sub "${AWS::StackName}-function"
          CodeUri: src/
          Handler: !If 
            - !Equals ["{{runtime}}", "python3.9"]
            - "handler.lambda_handler"
            - !If
              - !Equals ["{{runtime}}", "python3.10"] 
              - "handler.lambda_handler"
              - !If
                - !Equals ["{{runtime}}", "python3.11"]
                - "handler.lambda_handler"
                - !If
                  - !Equals ["{{runtime}}", "python3.12"]
                  - "handler.lambda_handler"
                  - "index.handler"
          Runtime: {{runtime}}
          MemorySize: {{memorySize}}
          Timeout: {{timeout}}
          Environment:
            Variables:
              ENVIRONMENT: !Ref Environment
              LOG_LEVEL: INFO
          Events:
            # S3 Trigger (conditional)
            S3Event:
              Type: S3
              Condition: HasS3Trigger
              Properties:
                Bucket: !Ref S3Bucket
                Events: s3:ObjectCreated:*
                Filter:
                  S3Key:
                    Rules:
                      - Name: prefix
                        Value: uploads/
            # EventBridge Trigger (conditional)
            EventBridgeRule:
              Type: EventBridgeRule
              Condition: HasEventBridgeTrigger
              Properties:
                Pattern:
                  source: ["custom.application"]
                  detail-type: ["Custom Event"]
            # SQS Trigger (conditional)
            SQSEvent:
              Type: SQS
              Condition: HasSQSTrigger
              Properties:
                Queue: !GetAtt SQSQueue.Arn
                BatchSize: 10

      # S3 Bucket (if S3 trigger selected)
      S3Bucket:
        Type: AWS::S3::Bucket
        Condition: HasS3Trigger
        Properties:
          BucketName: !Sub "${AWS::StackName}-trigger-bucket"
          NotificationConfiguration:
            LambdaConfigurations:
              - Event: s3:ObjectCreated:*
                Function: !GetAtt {{projectName}}Function.Arn
                Filter:
                  S3Key:
                    Rules:
                      - Name: prefix
                        Value: uploads/

      # SQS Queue (if SQS trigger selected)
      SQSQueue:
        Type: AWS::SQS::Queue
        Condition: HasSQSTrigger
        Properties:
          QueueName: !Sub "${AWS::StackName}-queue"
          VisibilityTimeoutSeconds: !Ref {{timeout}}

      # CloudWatch Log Group
      LogGroup:
        Type: AWS::Logs::LogGroup
        Properties:
          LogGroupName: !Sub "/aws/lambda/${AWS::StackName}-function"
          RetentionInDays: 14

    Outputs:
      FunctionName:
        Description: Lambda Function Name
        Value: !Ref {{projectName}}Function
        Export:
          Name: !Sub "${AWS::StackName}-FunctionName"
      
      FunctionArn:
        Description: Lambda Function ARN
        Value: !GetAtt {{projectName}}Function.Arn
        Export:
          Name: !Sub "${AWS::StackName}-FunctionArn"
      
      S3BucketName:
        Condition: HasS3Trigger
        Description: S3 Trigger Bucket Name
        Value: !Ref S3Bucket
        Export:
          Name: !Sub "${AWS::StackName}-S3Bucket"
      
      SQSQueueUrl:
        Condition: HasSQSTrigger
        Description: SQS Queue URL
        Value: !Ref SQSQueue
        Export:
          Name: !Sub "${AWS::StackName}-SQSQueue"

  .cfn-forge.yaml: |
    project:
      name: {{projectName}}
      description: {{description}}
      type: basic-lambda

    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/index.js",
      "scripts": {
        "start": "sam local start-lambda",
        "invoke": "sam local invoke",
        "build": "sam build",
        "deploy": "cfn-forge deploy",
        "watch": "cfn-forge watch",
        "validate": "cfn-forge validate",
        "test": "jest",
        "test:watch": "jest --watch",
        "lint": "eslint src/",
        "logs": "sam logs -n {{projectName}}Function --stack-name {{projectName}}-dev"
      },
      "dependencies": {
        "aws-sdk": "^2.1490.0"
      },
      "devDependencies": {
        "jest": "^29.0.0",
        "eslint": "^8.0.0"
      },
      "keywords": ["lambda", "aws", "serverless"],
      "author": "{{author}}",
      "license": "MIT"
    }

  src/index.js: |
    // Basic Lambda function handler for Node.js
    exports.handler = async (event, context) => {
        console.log('Event:', JSON.stringify(event, null, 2));
        console.log('Context:', JSON.stringify(context, null, 2));
        
        try {
            // Your business logic here
            const result = {
                message: 'Hello from {{projectName}}!',
                timestamp: new Date().toISOString(),
                environment: process.env.ENVIRONMENT,
                eventType: event.Records ? 'triggered' : 'direct',
                requestId: context.awsRequestId
            };
            
            console.log('Result:', JSON.stringify(result, null, 2));
            
            return {
                statusCode: 200,
                body: JSON.stringify(result)
            };
        } catch (error) {
            console.error('Error:', error);
            
            return {
                statusCode: 500,
                body: JSON.stringify({
                    message: 'Internal server error',
                    error: error.message
                })
            };
        }
    };

  src/handler.py: |
    # Basic Lambda function handler for Python
    import json
    import logging
    import os
    from datetime import datetime

    # Configure logging
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)

    def lambda_handler(event, context):
        logger.info(f"Event: {json.dumps(event)}")
        logger.info(f"Context: {vars(context)}")
        
        try:
            # Your business logic here
            result = {
                'message': 'Hello from {{projectName}}!',
                'timestamp': datetime.now().isoformat(),
                'environment': os.environ.get('ENVIRONMENT'),
                'eventType': 'triggered' if 'Records' in event else 'direct',
                'requestId': context.aws_request_id
            }
            
            logger.info(f"Result: {json.dumps(result)}")
            
            return {
                'statusCode': 200,
                'body': json.dumps(result)
            }
        except Exception as error:
            logger.error(f"Error: {str(error)}")
            
            return {
                'statusCode': 500,
                'body': json.dumps({
                    'message': 'Internal server error',
                    'error': str(error)
                })
            }

  tests/test-handler.js: |
    const { handler } = require('../src/index');

    describe('Lambda Handler', () => {
        const mockContext = {
            awsRequestId: 'test-request-id',
            getRemainingTimeInMillis: () => 30000
        };

        test('should handle direct invocation', async () => {
            const event = { test: 'data' };
            
            const result = await handler(event, mockContext);
            
            expect(result.statusCode).toBe(200);
            expect(JSON.parse(result.body).message).toContain('Hello from {{projectName}}');
        });

        test('should handle S3 event', async () => {
            const event = {
                Records: [{
                    eventSource: 'aws:s3',
                    s3: {
                        bucket: { name: 'test-bucket' },
                        object: { key: 'test-key' }
                    }
                }]
            };
            
            const result = await handler(event, mockContext);
            
            expect(result.statusCode).toBe(200);
            expect(JSON.parse(result.body).eventType).toBe('triggered');
        });
    });

  README.md: |
    # {{projectName}}

    {{description}}

    ## Quick Start

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

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

    3. Test locally:
       ```bash
       npm run invoke
       ```

    ## Function Details

    - **Runtime**: {{runtime}}
    - **Memory**: {{memorySize}} MB
    - **Timeout**: {{timeout}} seconds
    - **Trigger**: {{triggerType}}

    ## Project Structure

    ```
    {{projectName}}/
       src/
          index.js          # Node.js handler
          handler.py        # Python handler
       tests/
          test-handler.js   # Unit tests
       cloudformation.yaml  # AWS infrastructure
       .cfn-forge.yaml     # CFN-Forge configuration
       package.json
    ```

    ## Local Development

    ```bash
    # Start Lambda locally
    npm run start

    # Invoke function locally
    npm run invoke

    # Run tests
    npm test

    # Watch for changes
    npm run test:watch
    ```

    ## Deployment

    ### Environments

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

    ### Commands

    - `cfn-forge deploy` - Deploy to 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

    ## Monitoring

    ```bash
    # View logs
    npm run logs

    # View CloudWatch metrics in AWS Console
    aws logs describe-log-groups --log-group-name-prefix "/aws/lambda/{{projectName}}"
    ```

    ## Triggers

    This template supports multiple trigger types:

    - **manual**: Invoke directly or via API
    - **s3**: Triggered by S3 object creation
    - **eventbridge**: Triggered by EventBridge rules
    - **sqs**: Triggered by SQS messages

hooks:
  postInstall:
    - type: npm
      command: install
    - type: message
      content: "Lambda function template created! Choose the appropriate handler file for your runtime."