@june24/core-aws
v1.1.5
Published
A comprehensive AWS development toolkit for DynamoDB, S3, and serverless applications with TypeScript support.
Downloads
173
Readme
@june24/core-aws
A comprehensive AWS development toolkit for DynamoDB, S3, and serverless applications with TypeScript support.
🚀 Quick Start
Installation
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:
# 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 ./projectsGenerated 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):
# 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-handlersGenerated 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
# Create new project
npx @june24/core-aws create-project --name my-awesome-project
# Navigate to project
cd my-awesome-project
# Install dependencies
npm installStep 2: Create Table Configuration
Create a table configuration file in configs/ folder:
// 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
# Add product table with complete structure
npx @june24/core-aws add --config ./configs/product.config.ts --name productStep 4: Customize Generated Files
Update Type Definition
// 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
// 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
// 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
# 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
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
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
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
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
// 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
// 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
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 helpAdd Table Options
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
# 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 deployCustom Validation Example
// 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
// 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
// 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
// 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
// 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 functionalityBaseServiceImpl<T, D, S>- Base service with repository managementBaseRepoDBImpl<T>- DynamoDB repository implementationValidationUtil- Comprehensive validation systemTableConfig- DynamoDB table configuration
Factory Classes
RepositoryFactory- Repository instance management with cachingServiceFactory- Service instance management with cachingValidationFactory- Validation instance management with cachingControllerFactory- Controller instance management with caching
CLI Commands
create-project- Create new project from examplesadd- Add table configuration with complete structureinit- Initialize project from table configs (legacy)generate- Generate serverless configurations (legacy)
🤝 Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🆘 Support
For support and questions:
- Create an issue on GitHub
- Check the examples folder for usage examples
- Review the CLI documentation
