npm package: @june24/core-aws
Description: A comprehensive AWS development toolkit for DynamoDB, S3, and serverless applications with TypeScript support.
Author: baasandorj
Latest version: 1.1.5

# @june24/core-aws

A comprehensive AWS development toolkit for DynamoDB, S3, and serverless applications with TypeScript support.

## 🚀 Quick Start

### Installation

```bash
npm install @june24/core-aws
```

## 📋 CLI Commands

The package includes powerful CLI tools for project creation and table configuration management.

### 🏗️ Create New Project

Generate a complete project structure based on the examples folder:

```bash
# Create new project
npx @june24/core-aws create-project --name my-new-project

# Create project in specific folder
npx @june24/core-aws create-project --name my-project --output-folder ./projects
```

**Generated Structure:**

```
my-new-project/
├── src/
│   ├── controllers/          # API controllers with factory pattern
│   │   ├── controller.factory.ts
│   │   ├── user.controller.ts
│   │   └── index.ts
│   ├── services/            # Business logic with factory pattern
│   │   ├── service.factory.ts
│   │   ├── user.service/
│   │   │   ├── user.service.ts
│   │   │   ├── user.service.interface.ts
│   │   │   └── index.ts
│   │   └── index.ts
│   ├── repositories/        # Data access with factory pattern
│   │   ├── repository.factory.ts
│   │   ├── dynamodb.repo/
│   │   │   ├── user.repo.ts
│   │   │   ├── user.repo.interface.ts
│   │   │   └── index.ts
│   │   └── index.ts
│   ├── validation/          # Validation rules with factory pattern
│   │   ├── validation.factory.ts
│   │   ├── user.validation.ts
│   │   └── index.ts
│   ├── handlers/            # Lambda handlers
│   │   ├── crud/
│   │   │   └── user.crud/
│   │   │       ├── index.ts
│   │   │       └── serverless.yml
│   │   ├── trigger/
│   │   │   └── user.trigger/
│   │   │       ├── index.ts
│   │   │       └── serverless.yml
│   │   ├── streamer/
│   │   │   └── user.streamer/
│   │   │       ├── index.ts
│   │   │       └── serverless.yml
│   │   └── schedule/
│   │       └── user.schedule/
│   │           ├── index.ts
│   │           └── serverless.yml
│   └── types/              # TypeScript types
│       └── user.model.ts
├── configs/                 # Table configurations
│   └── user.config.ts
├── serverless/             # Serverless resources
│   ├── dynamodb/
│   │   └── users.yml
│   ├── cognito.yml
│   ├── s3.yml
│   ├── sns.yml
│   ├── sqs.yml
│   ├── ses.yml
│   ├── kms.yml
│   ├── http-api-gateway.yml
│   └── ws-api-gateway.yml
├── package.json            # Project configuration
├── tsconfig.json           # TypeScript configuration
├── serverless.yml          # Serverless configuration
└── README.md               # Project documentation
```

### ➕ Add Table Configuration

Add new table with complete structure (controllers, services, repositories, validation, handlers, types):

```bash
# Add new table configuration
npx @june24/core-aws add --config ./configs/product.config.ts --name product

# Add with replace option (overwrites existing files)
npx @june24/core-aws add --config ./configs/product.config.ts --name product --replace

# Skip specific components
npx @june24/core-aws add --config ./configs/product.config.ts --name product --skip-validation --skip-handlers
```

**Generated Components:**

- ✅ **Types**: `src/types/product.model.ts`
- ✅ **Validation**: `src/validation/product.validation.ts`
- ✅ **Repository**: `src/repositories/dynamodb.repo/product.repo/`
- ✅ **Service**: `src/services/product.service/`
- ✅ **Controller**: `src/controllers/product.controller.ts`
- ✅ **Handlers**: `src/handlers/crud/product.crud/`
- ✅ **DynamoDB Config**: `serverless/dynamodb/product.yml`



## 🎯 Complete Usage Guide

### Step 1: Create New Project

```bash
# Create new project
npx @june24/core-aws create-project --name my-awesome-project

# Navigate to project
cd my-awesome-project

# Install dependencies
npm install
```

### Step 2: Create Table Configuration

Create a table configuration file in `configs/` folder:

```typescript
// configs/product.config.ts
import { TableConfig } from "@june24/core-aws";

const productTableConfig = new TableConfig();

// Define indexes
productTableConfig.set("By_Category", {
  partitionKeyField: "category",
  sourceFields: ["category"],
  sortKeyField: "createdDate",
});

productTableConfig.set("By_Status", {
  partitionKeyField: "status",
  sourceFields: ["status"],
  sortKeyField: "createdDate",
});

productTableConfig.set("By_Category_Status", {
  partitionKeyField: "category_status",
  sourceFields: ["category", "status"],
  compositeSeparator: "_",
  sortKeyField: "createdDate",
});

// Configure table
productTableConfig.setConfig({
  partitionKey: "id",
  tableName: `Products-${process.env.ENV || "dev"}`,
  deletionPolicy: "Retain",
  billingMode: "PAY_PER_REQUEST",
  streamSpecification: {
    streamViewType: "NEW_AND_OLD_IMAGES",
  },
  pointInTimeRecovery: true,
  tags: {
    Environment: process.env.ENV || "dev",
    Service: "my-service",
    TableType: "products",
  },
});

export default productTableConfig;
```

### Step 3: Add Table to Project

```bash
# Add product table with complete structure
npx @june24/core-aws add --config ./configs/product.config.ts --name product
```

### Step 4: Customize Generated Files

#### Update Type Definition

```typescript
// src/types/product.model.ts
import { BaseEntity } from "@june24/core-aws";

export interface IProduct extends BaseEntity {
  name: string;
  description?: string;
  price: number;
  category: string;
  status: "active" | "inactive" | "draft";
  stockQuantity: number;
  tags?: string[];
}
```

#### Update Validation Rules

```typescript
// src/validation/product.validation.ts
import { ValidationRule, commonValidations } from "@june24/core-aws";

export class ProductValidation {
  static getCreateValidationRules(): ValidationRule[] {
    return [
      commonValidations.required("id"),
      commonValidations.required("name"),
      commonValidations.required("price"),
      commonValidations.required("category"),
      commonValidations.required("status"),

      {
        field: "name",
        type: "string",
        minLength: 2,
        maxLength: 100,
        required: true,
      },
      {
        field: "price",
        type: "number",
        min: 0,
        required: true,
      },
      {
        field: "status",
        type: "string",
        custom: (value) => {
          const validStatuses = ["active", "inactive", "draft"];
          if (!validStatuses.includes(value)) {
            return `Status must be one of: ${validStatuses.join(", ")}`;
          }
          return true;
        },
      },
    ];
  }

  static getUpdateValidationRules(): ValidationRule[] {
    return [
      {
        field: "name",
        type: "string",
        minLength: 2,
        maxLength: 100,
      },
      {
        field: "price",
        type: "number",
        min: 0,
      },
    ];
  }

  static getSearchValidationRules(): ValidationRule[] {
    return [
      {
        field: "category",
        type: "string",
      },
      {
        field: "status",
        type: "string",
      },
    ];
  }
}
```

#### Update Controller Logic

```typescript
// src/controllers/product.controller.ts
import { BaseController } from "@june24/core-aws";
import { IProduct } from "@/types/product.model";
import { IProductService } from "@/services/product.service/product.service.interface";
import { ServiceFactory } from "@/services/service.factory";

export class ProductController extends BaseController<IProductService> {
  constructor() {
    super(ServiceFactory.createProductService());
  }

  protected processCrudRequest(): Promise<any> {
    if (this.endpoint === "POST /product") {
      // Add custom validation
      this.validateRequiredFields(["name", "price", "category"], this.request?.body);
      return this.service.create(this.userId, this.request?.body);
    }
    if (this.endpoint === "GET /products") {
      return this.service.listItemsDB(this.request.filter);
    }
    if (this.endpoint === "GET /product/{id}") {
      return this.service.get(this.request.pathParameters?.id);
    }
    if (this.endpoint === "PUT /product/{id}") {
      return this.service.update(this.userId, this.request.pathParameters?.id, this.request?.body);
    }
    if (this.endpoint === "DELETE /product/{id}") {
      return this.service.delete(this.request.pathParameters?.id);
    }
    throw new Error("Method not implemented.");
  }

  protected processTriggerEvent(): Promise<any> {
    // Handle Cognito trigger events
    const event = this.request as any;

    switch (event.triggerSource) {
      case "PreSignUp_AdminCreateUser":
        return this.service.handlePreSignUp(event);
      case "PostConfirmation_ConfirmSignUp":
        return this.service.handlePostConfirmation(event);
      default:
        throw new Error(`Unsupported trigger source: ${event.triggerSource}`);
    }
  }
}
```

### Step 5: Deploy

```bash
# Deploy to development
npm run deploy

# Deploy to production
npm run deploy:prod

# Run locally for development
npm run dev
```

## 🏭 Factory Pattern Usage

The framework uses factory patterns with caching for efficient instance management:

### Repository Factory

```typescript
import { RepositoryFactory } from "@/repositories/repository.factory";

// Get cached repository instance
const userRepo = RepositoryFactory.createUserRepo();
const productRepo = RepositoryFactory.createProductRepo();

// Check if repository exists in cache
if (RepositoryFactory.hasRepository("userRepo")) {
  console.log("User repository is cached");
}

// Clear cache
RepositoryFactory.clearCache();
```

### Service Factory

```typescript
import { ServiceFactory } from "@/services/service.factory";

// Get cached service instance
const userService = ServiceFactory.createUserService();
const productService = ServiceFactory.createProductService();

// Check if service exists in cache
if (ServiceFactory.hasService("userService")) {
  console.log("User service is cached");
}
```

### Validation Factory

```typescript
import { ValidationFactory } from "@/validation/validation.factory";

// Get validation for different operations
const createValidator = ValidationFactory.createUserCreateValidator();
const updateValidator = ValidationFactory.createUserUpdateValidator();
const searchValidator = ValidationFactory.createUserSearchValidator();

// Operation-based approach
const validator = ValidationFactory.getValidatorByOperation("create", "user");
```

### Controller Factory

```typescript
import { ControllerFactory } from "@/controllers/controller.factory";

// Get cached controller instance
const userController = ControllerFactory.createUserController();
const productController = ControllerFactory.createProductController();

// Entity-based approach
const controller = ControllerFactory.getControllerByEntity("user");
```

## 📋 TableConfig Configuration

### Basic Setup

```typescript
// configs/user.config.ts
import { TableConfig } from "@june24/core-aws";

const userTableConfig = new TableConfig();

// Configure table settings
userTableConfig.setConfig({
  partitionKey: "id",
  tableName: `Users-${process.env.ENV || "dev"}`,
  deletionPolicy: "Retain",
  billingMode: "PAY_PER_REQUEST",
  streamSpecification: {
    streamViewType: "NEW_AND_OLD_IMAGES",
  },
  pointInTimeRecovery: true,
  tags: {
    Environment: process.env.ENV || "dev",
    Service: "my-service",
    TableType: "users",
  },
});

// Add Global Secondary Indexes
userTableConfig.set("By_email", {
  partitionKeyField: "email",
  sourceFields: ["email"],
  sortKeyField: "createdAt",
});

userTableConfig.set("By_status", {
  partitionKeyField: "status",
  sourceFields: ["status"],
  sortKeyField: "updatedAt",
});

export default userTableConfig;
```

### Advanced Configuration

```typescript
// configs/product.config.ts
const productTableConfig = new TableConfig();

productTableConfig.setConfig({
  partitionKey: "id",
  tableName: `Products-${process.env.ENV || "dev"}`,
  deletionPolicy: "Retain",
  billingMode: "PROVISIONED", // For high-traffic tables
  streamSpecification: {
    streamViewType: "NEW_AND_OLD_IMAGES",
  },
  pointInTimeRecovery: true,
  tags: {
    Environment: process.env.ENV || "dev",
    Service: "my-service",
    TableType: "products",
  },
});

// Composite indexes
productTableConfig.set("By_Category_Status", {
  partitionKeyField: "category_status",
  sourceFields: ["category", "status"],
  compositeSeparator: "_",
  sortKeyField: "createdDate",
});

// Multiple sort keys
productTableConfig.set("By_Price_Range", {
  partitionKeyField: "priceRange",
  sourceFields: ["priceRange"],
  sortKeyField: "createdDate",
});

export default productTableConfig;
```

## 🔧 CLI Options

### Create Project Options

```bash
npx @june24/core-aws create-project [options]

Options:
  --name <name>                    Project name (required)
  --output-folder <path>           Output folder (default: ./)
  --skip-repositories              Skip repository generation
  --skip-services                  Skip service generation
  --skip-controllers               Skip controller generation
  --skip-validation                Skip validation generation
  --skip-handlers                  Skip handler generation
  --skip-types                     Skip type generation
  --help, -h                       Show help
```

### Add Table Options

```bash
npx @june24/core-aws add [options]

Options:
  --config <file>                  Table config file path (required)
  --name <name>                    Table name (required)
  --output-folder <path>           Output folder (default: ./)
  --replace                        Replace existing files
  --skip-repositories              Skip repository generation
  --skip-services                  Skip service generation
  --skip-controllers               Skip controller generation
  --skip-validation                Skip validation generation
  --skip-handlers                  Skip handler generation
  --skip-types                     Skip type generation
  --help, -h                       Show help
```

## 🚀 Examples

### Complete Project Setup

```bash
# 1. Create new project
npx @june24/core-aws create-project --name ecommerce-api

# 2. Navigate to project
cd ecommerce-api

# 3. Install dependencies
npm install

# 4. Create table configs
# Create configs/user.config.ts, configs/product.config.ts, etc.

# 5. Add tables to project
npx @june24/core-aws add --config ./configs/user.config.ts --name user
npx @june24/core-aws add --config ./configs/product.config.ts --name product
npx @june24/core-aws add --config ./configs/order.config.ts --name order

# 6. Customize generated files
# Edit types, validation, controllers as needed

# 7. Deploy
npm run deploy
```

### Custom Validation Example

```typescript
// src/validation/user.validation.ts
import { ValidationRule, commonValidations } from "@june24/core-aws";

export class UserValidation {
  static getCreateValidationRules(): ValidationRule[] {
    return [
      commonValidations.required("id"),
      commonValidations.required("email"),
      commonValidations.email("email"),

      {
        field: "password",
        type: "string",
        minLength: 8,
        maxLength: 128,
        required: true,
        pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/,
      },

      {
        field: "age",
        type: "number",
        min: 13,
        max: 120,
        custom: (value) => {
          if (value && value < 13) {
            return "User must be at least 13 years old";
          }
          return true;
        },
      },
    ];
  }

  static getUpdateValidationRules(): ValidationRule[] {
    return [
      {
        field: "email",
        type: "string",
        email: true,
      },
      {
        field: "age",
        type: "number",
        min: 13,
        max: 120,
      },
    ];
  }

  static getSearchValidationRules(): ValidationRule[] {
    return [
      {
        field: "email",
        type: "string",
      },
      {
        field: "status",
        type: "string",
      },
    ];
  }
}
```

### Custom Service Methods

```typescript
// src/services/user.service/user.service.ts
import { BaseServiceImpl } from "@june24/core-aws";
import { IUser } from "@/types/user.model";
import { IUserRepoDB } from "@/repositories/dynamodb.repo/user.repo/user.repo.interface";
import { IUserService } from "./user.service.interface";
import { RepositoryFactory } from "@/repositories/repository.factory";

export class UserServiceImpl extends BaseServiceImpl<IUser, IUserRepoDB> implements IUserService {
  constructor() {
    super(RepositoryFactory.createUserRepo());
  }

  // Custom method
  async findByEmail(email: string): Promise<IUser | null> {
    const filter = { indexName: "By_email", indexValue: email };
    const result = await this.listItemsDB(filter);
    return result.items.length > 0 ? result.items[0] : null;
  }

  // Custom business logic
  async createUser(userData: Partial<IUser>): Promise<IUser> {
    // Add custom validation
    if (userData.email) {
      const existingUser = await this.findByEmail(userData.email);
      if (existingUser) {
        throw new Error("User with this email already exists");
      }
    }

    return await this.create(userData.createdBy || "system", userData);
  }

  // Handle Cognito triggers
  async handlePreSignUp(event: any): Promise<any> {
    // Custom pre-signup logic
    return { allow: true };
  }

  async handlePostConfirmation(event: any): Promise<any> {
    // Custom post-confirmation logic
    const userData = {
      id: event.request.userAttributes.sub,
      email: event.request.userAttributes.email,
      status: "active",
      createdBy: "cognito",
    };

    return await this.create("cognito", userData);
  }
}
```

### Handler Examples

#### CRUD Handler

```typescript
// src/handlers/crud/user.crud/index.ts
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";
import { ControllerFactory } from "@/controllers/controller.factory";

export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
  const controller = ControllerFactory.createUserController();
  return await controller.handleRequest(event);
};
```

#### Trigger Handler

```typescript
// src/handlers/trigger/user.trigger/index.ts
import { PreSignUpTriggerEvent, PostConfirmationTriggerEvent } from "aws-lambda";
import { ControllerFactory } from "@/controllers/controller.factory";

export const handler = async (event: PreSignUpTriggerEvent | PostConfirmationTriggerEvent): Promise<any> => {
  const controller = ControllerFactory.createUserController();
  return await controller.handleTriggerEvent(event);
};
```

#### Stream Handler

```typescript
// src/handlers/streamer/user.streamer/index.ts
import { DynamoDBStreamEvent } from "aws-lambda";
import { ControllerFactory } from "@/controllers/controller.factory";

export const handler = async (event: DynamoDBStreamEvent): Promise<void> => {
  const controller = ControllerFactory.createUserController();
  return await controller.handleStreamEvent(event);
};
```

## 📚 API Reference

### Core Classes

- `BaseController<T, S>` - Base controller with common functionality
- `BaseServiceImpl<T, D, S>` - Base service with repository management
- `BaseRepoDBImpl<T>` - DynamoDB repository implementation
- `ValidationUtil` - Comprehensive validation system
- `TableConfig` - DynamoDB table configuration

### Factory Classes

- `RepositoryFactory` - Repository instance management with caching
- `ServiceFactory` - Service instance management with caching
- `ValidationFactory` - Validation instance management with caching
- `ControllerFactory` - Controller instance management with caching

### CLI Commands

- `create-project` - Create new project from examples
- `add` - Add table configuration with complete structure
- `init` - Initialize project from table configs (legacy)
- `generate` - Generate serverless configurations (legacy)

## 🤝 Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## 📄 License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## 🆘 Support

For support and questions:

- Create an issue on GitHub
- Check the [examples](./examples) folder for usage examples
- Review the [CLI documentation](./CLI_README.md)