diff --git a/README.md b/README.md
index 86626a6..e6dbd80 100644
--- a/README.md
+++ b/README.md
@@ -1,99 +1,211 @@
-
-
-
-[![Version][version-shield]][version-url]
-[![MIT License][license-shield]][license-url]
-[![LinkedIn][linkedin-shield]][linkedin-url]
-
-
-
-
-
-
-
- Table of Contents
-
- - About The Project
- - Getting Started
- - Contributing
- - Support the project
- - License
-
-
-
-
-# About The Project
-
-ExpressoTS is a [Typescript](https://www.typescriptlang.org/) + [Node.js](https://nodejs.org/en/) lightweight framework for quick building scalable, easy to read and maintain, server-side applications ๐
-
-## Getting Started
-
-- Here is our [Site](https://expresso-ts.com/)
-- You can find our [Documentation here](https://doc.expresso-ts.com/)
-- Checkout our [First Steps documentation](https://doc.expresso-ts.com/docs/overview/first-steps)
-- Our [CLI Documentation](https://doc.expresso-ts.com/docs/cli/overview)
+# ExpressoTS Templates Repository
+
+Community-maintained templates and pricing data for the [ExpressoTS CLI](https://github.com/expressots/expressots-cli).
+
+## What's This?
-## Contributing
+This repository contains all the templates used by ExpressoTS CLI to generate:
+- **CI/CD Pipelines** (GitHub Actions, GitLab CI, CircleCI, Jenkins, etc.)
+- **Docker Configurations** (Dockerfiles, docker-compose)
+- **Kubernetes Manifests** (deployments, services, ingress)
+- **Migration Guides** (Heroku โ Railway/Render/Fly, Compose โ K8s)
+- **Cloud Provider Pricing** (for cost estimation)
+
+## Why a Separate Repository?
+
+**Fast Updates:** Templates can be updated without releasing a new CLI version. Users get updates within 24 hours.
+
+**Community Contributions:** Anyone can contribute templates or update pricing - no CLI expertise needed.
+
+**Offline Support:** CLI has embedded fallbacks, so it works without internet.
+
+**Version Control:** Templates are versioned independently from the CLI.
+
+## Repository Structure
+
+```
+cli-templates/
+โโโ manifest.json # Template registry with versions
+โโโ pricing.json # Cloud provider pricing data
+โโโ README.md # This file
+โโโ cicd/ # CI/CD pipeline templates
+โ โโโ github/
+โ โ โโโ basic.yml
+โ โ โโโ comprehensive.yml
+โ โ โโโ security-focused.yml
+โ โโโ gitlab/
+โ โโโ circleci/
+โ โโโ jenkins/
+โ โโโ bitbucket/
+โ โโโ azure/
+โโโ docker/ # Docker templates
+โ โโโ Dockerfile.production.tpl
+โ โโโ Dockerfile.development.tpl
+โ โโโ docker-compose.yml.tpl
+โ โโโ docker-compose.development.yml.tpl
+โโโ kubernetes/ # Kubernetes manifest templates
+โ โโโ deployment.yml.tpl
+โ โโโ service.yml.tpl
+โ โโโ configmap.yml.tpl
+โ โโโ ingress.yml.tpl
+โโโ migrations/ # Migration templates
+ โโโ heroku-to-railway/
+ โโโ heroku-to-render/
+ โโโ heroku-to-fly/
+ โโโ compose-to-kubernetes/
+```
+
+## How to Use
+
+### For Users
-Welcome to the ExpressoTS community, a place bustling with innovative minds just like yours. We're absolutely thrilled to have you here!
-ExpressoTS is more than just a TypeScript framework; it's a collective effort by developers who are passionate about creating a more efficient, secure, and robust web ecosystem. We firmly believe that the best ideas come from a diversity of perspectives, backgrounds, and skills.
+Users don't need to interact with this repository directly. The ExpressoTS CLI automatically fetches templates:
-Why Contribute to Documentation?
+```bash
+# List available templates
+expressots templates list
-- **Share Knowledge**: If you've figured out something cool, why keep it to yourself?
-- **Build Your Portfolio**: Contributing to an open-source project like ExpressoTS is a great way to showcase your skills.
-- **Join a Network**: Get to know a community of like-minded developers.
-- **Improve the Product**: Help us fill in the gaps, correct errors, or make complex topics easier to understand.
+# Update to latest versions
+expressots templates update
-Ready to contribute?
+# Generate CI/CD pipeline
+expressots cicd generate github --strategy comprehensive
+```
-- [Contributing Guidelines](https://github.com/expressots/expressots/blob/main/CONTRIBUTING.md)
-- [How to Contribute](https://github.com/expressots/expressots/blob/main/CONTRIBUTING_HOWTO.md)
-- [Coding Guidelines](https://github.com/rsaz/TypescriptCodingGuidelines)
+### For Contributors
-## Support the project
+Want to improve templates or update pricing? See [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed instructions.
-ExpressoTS is an independent open source project with ongoing development made possible thanks to your support. If you'd like to help, please consider:
+**Quick start:**
-- Become a **[sponsor on GitHub](https://github.com/sponsors/expressots)**
-- Follow the **[organization](https://github.com/expressots)** on GitHub and Star โญ the project
-- Subscribe to the Twitch channel: **[Richard Zampieri](https://www.twitch.tv/richardzampieri)**
-- Join our **[Discord](https://discord.com/invite/PyPJfGK)**
-- Contribute submitting **[issues and pull requests](https://github.com/expressots/expressots/issues)**
-- Share the project with your friends and colleagues
+1. Fork this repository
+2. Edit a template file (e.g., `cicd/github/basic.yml`)
+3. Update `manifest.json` with new version
+4. Test locally:
+ ```bash
+ expressots templates repo set YOUR_USERNAME/templates
+ expressots templates update
+ expressots cicd generate github
+ ```
+5. Submit a pull request
+
+### For Organizations
+
+Use custom templates for your organization:
+
+```bash
+# Fork this repo, customize, then:
+expressots templates repo set mycompany/expressots-templates
+
+# Team members automatically get company templates
+expressots cicd generate github
+```
+
+## Template Syntax
+
+Templates use Mustache-like syntax:
+
+```yaml
+name: {{projectName}}
+
+{{#includeSecurity}}
+security:
+ scan: enabled
+{{/includeSecurity}}
+
+{{^isProduction}}
+dev-tools:
+ - nodemon
+{{/isProduction}}
+```
+
+**Supported:**
+- Variables: `{{name}}`
+- Conditionals: `{{#cond}}...{{/cond}}`
+- Negative conditionals: `{{^cond}}...{{/cond}}`
+- Loops: `{{#each items}}...{{/each}}`
+
+## Contributing
+
+We welcome contributions! See [CONTRIBUTING.md](./CONTRIBUTING.md) for:
+- How to add new templates
+- How to update pricing data
+- Testing guidelines
+- Review process
+- Best practices
+
+**Common contributions:**
+- Add new CI/CD strategies
+- Update cloud provider pricing
+- Improve security scanning
+- Add new platform support
+- Fix bugs in templates
+
+## Pricing Data
+
+Cloud provider pricing is stored in `cli-templates/pricing.json` and used by the CLI's cost estimation features.
+
+**Updating pricing:**
+
+1. Visit official pricing pages (links in `pricing.json`)
+2. Update prices for a provider
+3. Update `lastVerified` date
+4. Submit PR with source URLs
+
+**Example:**
+```json
+{
+ "providers": {
+ "aws": {
+ "cpuPerHour": 0.04048,
+ "source": "https://aws.amazon.com/fargate/pricing/",
+ "lastVerified": "2026-01-15"
+ }
+ }
+}
+```
+
+## Versioning
+
+### Template Versions
+
+Each template has its own version:
+- **Patch (1.0.1):** Bug fixes, typos
+- **Minor (1.1.0):** New features, backward compatible
+- **Major (2.0.0):** Breaking changes
+
+### Manifest Version
+
+The manifest version tracks overall structure changes:
+```json
+{
+ "version": "1.0.0",
+ "updated": "2026-01-07T00:00:00Z"
+}
+```
+
+## Release Process
+
+1. PRs merged to `main` branch
+2. CI validates manifest and templates
+3. Changes immediately available to CLI users
+4. Users' local cache updates within 24 hours
+5. Or manually: `expressots templates update`
+
+## Support
+
+- **Documentation:** https://expresso-ts.com/docs/cli/templates
+- **Issues:** https://github.com/expressots/expressots-cli/issues
+- **Discord:** https://discord.gg/expressots
## License
-Distributed under the MIT License. See [`LICENSE.txt`](https://github.com/expressots/expressots/blob/main/LICENSE) for more information.
+MIT License - see [LICENSE](./LICENSE) for details.
+
+## Acknowledgments
-(back to top)
+This repository is maintained by the ExpressoTS community. Special thanks to all contributors who help keep templates and pricing data up-to-date!
-
-
+---
-[version-shield]: https://img.shields.io/github/v/tag/expressots/templates?style=for-the-badge&logo=github
-[version-url]: https://img.shields.io/github/v/tag/expressots/templates?style=for-the-badge&logo=github
-[license-shield]: https://img.shields.io/github/license/expressots/expressots-project-template?style=for-the-badge
-[license-url]: https://github.com/expressots/expressots-project-template/blob/main/LICENSE
-[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555
-[linkedin-url]: https://www.linkedin.com/company/expresso-ts/
-[product-screenshot]: images/screenshot.png
+**Built with โค๏ธ by the ExpressoTS community**
diff --git a/application/.gitignore b/application/.gitignore
new file mode 100644
index 0000000..d6b5299
--- /dev/null
+++ b/application/.gitignore
@@ -0,0 +1,30 @@
+# Dependencies
+node_modules/
+
+# Build output
+dist/
+*.tsbuildinfo
+
+# Environment files (except examples)
+.env
+.env.local
+.env.staging
+.env.prod
+!.env.example
+
+# IDE
+.idea/
+.vscode/
+*.swp
+*.swo
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Testing
+coverage/
+
+# Logs
+*.log
+npm-debug.log*
\ No newline at end of file
diff --git a/application/README.md b/application/README.md
new file mode 100644
index 0000000..7d7625e
--- /dev/null
+++ b/application/README.md
@@ -0,0 +1,116 @@
+# ExpressoTS Application
+
+A modern, type-safe Node.js backend powered by ExpressoTS v4.0.
+
+## Features
+
+- ๐ง **Type-Safe Configuration** - Full TypeScript inference for config values
+- ๐ **Zero-Config Bootstrap** - Just run and go
+- ๐ฆ **Build-Time Path Resolution** - No runtime overhead
+- ๐งช **Testing Ready** - Jest configured out of the box
+
+## Quick Start
+
+```bash
+# Install dependencies
+npm install
+
+# Start development server
+npm run dev
+
+# Build for production
+npm run build
+
+# Run in production
+npm run prod
+```
+
+## Project Structure
+
+```
+src/
+โโโ main.ts # Application entry point
+โโโ app.ts # Application class (middleware, lifecycle)
+โโโ config.ts # Type-safe configuration
+โโโ app.controller.ts # Example controller
+```
+
+## Configuration
+
+Configuration is managed through `src/config.ts` using the `defineConfig` helper:
+
+```typescript
+export const appConfig = defineConfig({
+ app: {
+ name: Env.string("APP_NAME").default("My App"),
+ version: Env.string("APP_VERSION").default("1.0.0"),
+ },
+ server: {
+ port: Env.number("PORT").default(3000),
+ },
+});
+```
+
+### Environment Files
+
+- `.env.local` - Development environment (default)
+- `.env.staging` - Staging environment
+- `.env.prod` - Production environment
+
+## Scaffolding
+
+Use the CLI to generate new resources:
+
+```bash
+# Generate a controller
+npx expressots generate controller user
+
+# Generate a use case
+npx expressots generate usecase user/create-user
+
+# Generate a module with controller and use case
+npx expressots generate module user
+```
+
+### Scaffold Configuration
+
+Customize scaffolding in `expressots.config.ts`:
+
+```typescript
+const config: ExpressoConfig = {
+ opinionated: true, // Enable structured folders
+ scaffoldPattern: Pattern.KEBAB_CASE,
+ scaffoldSchematics: {
+ controller: "controllers",
+ usecase: "useCases",
+ entity: "entities",
+ },
+};
+```
+
+## Testing
+
+```bash
+# Run tests
+npm test
+
+# Run tests with coverage
+npm run test:cov
+
+# Watch mode
+npm run test:watch
+```
+
+## API Endpoints
+
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | /api/ | Application info |
+| GET | /api/health | Health check |
+
+## Learn More
+
+- [ExpressoTS Documentation](https://expresso-ts.com)
+- [GitHub Repository](https://github.com/expressots)
+- [Discord Community](https://discord.gg/PyPJfGK)
+
diff --git a/application/eslint.config.mjs b/application/eslint.config.mjs
new file mode 100644
index 0000000..33c6935
--- /dev/null
+++ b/application/eslint.config.mjs
@@ -0,0 +1,43 @@
+import js from "@eslint/js";
+import tseslint from "typescript-eslint";
+import { fileURLToPath } from "node:url";
+
+const __dirname = fileURLToPath(new URL(".", import.meta.url));
+
+export default tseslint.config(
+ js.configs.recommended,
+ ...tseslint.configs.recommended,
+ {
+ files: ["src/**/*.ts", "test/**/*.ts"],
+ languageOptions: {
+ parserOptions: {
+ project: true,
+ tsconfigRootDir: __dirname,
+ },
+ },
+ rules: {
+ // TypeScript-specific rules
+ "@typescript-eslint/no-unused-vars": [
+ "error",
+ {
+ argsIgnorePattern: "^_",
+ varsIgnorePattern: "^_",
+ },
+ ],
+ "@typescript-eslint/explicit-function-return-type": "off",
+ "@typescript-eslint/no-explicit-any": "off",
+ "@typescript-eslint/no-unused-vars": "off",
+ "@typescript-eslint/no-non-null-assertion": "warn",
+ },
+ },
+ {
+ ignores: [
+ "node_modules/**",
+ "dist/**",
+ "coverage/**",
+ "*.config.ts",
+ "*.config.js",
+ "*.config.mjs",
+ ],
+ }
+);
diff --git a/opinionated/expressots.config.ts b/application/expressots.config.ts
similarity index 100%
rename from opinionated/expressots.config.ts
rename to application/expressots.config.ts
diff --git a/application/jest.config.ts b/application/jest.config.ts
new file mode 100644
index 0000000..251492b
--- /dev/null
+++ b/application/jest.config.ts
@@ -0,0 +1,17 @@
+import type { Config } from "jest";
+
+const config: Config = {
+ preset: "ts-jest",
+ testEnvironment: "node",
+ rootDir: ".",
+ testMatch: ["/test/**/*.spec.ts"],
+ moduleNameMapper: {
+ "^@app/(.*)$": "/src/$1",
+ },
+ modulePathIgnorePatterns: ["/dist"],
+ collectCoverageFrom: ["src/**/*.ts", "!src/**/*.d.ts", "!src/main.ts"],
+ coverageDirectory: "coverage",
+ coverageReporters: ["text", "lcov"],
+};
+
+export default config;
diff --git a/application/package.json b/application/package.json
new file mode 100644
index 0000000..1df5f32
--- /dev/null
+++ b/application/package.json
@@ -0,0 +1,43 @@
+{
+ "name": "expressots-app",
+ "version": "1.0.0",
+ "description": "ExpressoTS Application",
+ "author": "",
+ "license": "MIT",
+ "main": "dist/src/main.js",
+ "scripts": {
+ "dev": "expressots dev",
+ "build": "expressots build",
+ "prod": "expressots prod",
+ "test": "jest --runInBand",
+ "test:watch": "jest --watchAll",
+ "coverage": "jest --coverage",
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
+ "lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\" --fix"
+ },
+ "dependencies": {
+ "@expressots/adapter-express": "^4.0.0",
+ "@expressots/core": "^4.0.0",
+ "@expressots/shared": "^4.0.0",
+ "express": "5.2.1",
+ "reflect-metadata": "^0.2.2"
+ },
+ "devDependencies": {
+ "@eslint/js": "9.39.2",
+ "@expressots/cli": "^4.0.0",
+ "@types/express": "5.0.6",
+ "@types/jest": "30.0.0",
+ "@types/node": "25.0.3",
+ "@typescript-eslint/eslint-plugin": "8.51.0",
+ "@typescript-eslint/parser": "8.51.0",
+ "eslint": "9.39.2",
+ "jest": "30.0.0",
+ "nodemon": "3.1.11",
+ "prettier": "3.7.4",
+ "ts-jest": "29.4.6",
+ "tsconfig-paths": "4.2.0",
+ "tsx": "4.21.0",
+ "typescript": "5.9.3",
+ "typescript-eslint": "8.51.0"
+ }
+}
diff --git a/non_opinionated/src/app.controller.ts b/application/src/app.controller.ts
similarity index 100%
rename from non_opinionated/src/app.controller.ts
rename to application/src/app.controller.ts
diff --git a/non_opinionated/src/app.ts b/application/src/app.ts
similarity index 61%
rename from non_opinionated/src/app.ts
rename to application/src/app.ts
index cff71a4..cb2d114 100644
--- a/non_opinionated/src/app.ts
+++ b/application/src/app.ts
@@ -3,18 +3,21 @@ import { AppContainer, CreateModule } from "@expressots/core";
import { AppController } from "./app.controller";
export class App extends AppExpress {
- private config: AppContainer = this.configContainer([
+ private container: AppContainer = this.configContainer([
CreateModule([AppController]),
]);
- async globalConfiguration(): Promise {}
+ globalConfiguration(): void {}
async configureServices(): Promise {
- this.Middleware.addBodyParser();
- this.Middleware.setErrorHandler({ showStackTrace: true });
+ // __MIDDLEWARE_PRESET_PLACEHOLDER__
+
+ this.Middleware.setErrorHandler({
+ showStackTrace: await this.isDevelopment(),
+ });
}
-
+
async postServerInitialization(): Promise {}
async serverShutdown(): Promise {}
-}
\ No newline at end of file
+}
diff --git a/application/src/main.ts b/application/src/main.ts
new file mode 100644
index 0000000..8236042
--- /dev/null
+++ b/application/src/main.ts
@@ -0,0 +1,4 @@
+import { bootstrap } from "@expressots/core";
+import { App } from "./app";
+
+bootstrap(App);
diff --git a/application/test/app.controller.spec.ts b/application/test/app.controller.spec.ts
new file mode 100644
index 0000000..dcd7894
--- /dev/null
+++ b/application/test/app.controller.spec.ts
@@ -0,0 +1,37 @@
+import {
+ createTestApp,
+ setupExpressoTSMatchers,
+ TestAppResult,
+} from "@expressots/core";
+import { afterAll, beforeAll, describe, it } from "@jest/globals";
+import { App } from "../src/app";
+
+// Setup ExpressoTS custom matchers
+setupExpressoTSMatchers();
+
+describe("AppController", () => {
+ let testApp: TestAppResult;
+
+ beforeAll(async () => {
+ testApp = await createTestApp(App, {
+ env: {
+ NODE_ENV: "test",
+ },
+ autoCleanup: false,
+ });
+ });
+
+ afterAll(async () => {
+ await testApp.cleanup();
+ });
+
+ describe("GET /", () => {
+ it("should return welcome message", async () => {
+ await testApp.request
+ .get("/")
+ .expectStatus(200)
+ .expectBody("Hello from ExpressoTS!")
+ .execute();
+ });
+ });
+});
diff --git a/application/tsconfig.build.json b/application/tsconfig.build.json
new file mode 100644
index 0000000..4864d83
--- /dev/null
+++ b/application/tsconfig.build.json
@@ -0,0 +1,22 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./dist",
+ "rootDir": "./",
+ "declaration": false,
+ "declarationMap": false,
+ "sourceMap": false,
+ "removeComments": true,
+ "incremental": true,
+ "tsBuildInfoFile": "./dist/.tsbuildinfo",
+ "isolatedModules": true,
+ "types": ["node"],
+ "baseUrl": ".",
+ "paths": {
+ "@useCases/*": ["./src/useCases/*"],
+ "@controllers/*": ["./src/controllers/*"]
+ }
+ },
+ "include": ["src/**/*.ts"],
+ "exclude": ["node_modules", "dist", "test"]
+}
diff --git a/application/tsconfig.json b/application/tsconfig.json
new file mode 100644
index 0000000..a921762
--- /dev/null
+++ b/application/tsconfig.json
@@ -0,0 +1,50 @@
+{
+ "compilerOptions": {
+ // Language and Environment
+ "target": "ES2021",
+ "lib": ["ES2021"],
+
+ // Modules
+ "module": "commonjs",
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+
+ // Emit
+ "outDir": "./dist",
+ "rootDir": "./",
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "removeComments": true,
+
+ // ExpressoTS Required: Decorators and Metadata
+ "experimentalDecorators": true,
+ "emitDecoratorMetadata": true,
+
+ // Path Mapping
+ "baseUrl": "./src",
+ "paths": {
+ "@useCases/*": ["./useCases/*"],
+ "@controllers/*": ["./controllers/*"]
+ },
+
+ // Type Checking
+ "strict": true,
+ "noImplicitAny": false,
+ "strictPropertyInitialization": false,
+ "skipLibCheck": true,
+
+ // Performance
+ "incremental": true,
+ "tsBuildInfoFile": "./dist/.tsbuildinfo",
+
+ // Interop Constraints
+ "forceConsistentCasingInFileNames": true,
+
+ // Type Definitions
+ "types": ["node", "jest"]
+ },
+ "include": ["src/**/*.ts", "test/**/*.ts", "expressots.config.ts"],
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/cli-templates/README.md b/cli-templates/README.md
new file mode 100644
index 0000000..d360cc9
--- /dev/null
+++ b/cli-templates/README.md
@@ -0,0 +1,70 @@
+# ExpressoTS CLI Templates
+
+This directory contains templates used by the ExpressoTS CLI for generating CI/CD pipelines, Docker configurations, Kubernetes manifests, and migration guides.
+
+## Structure
+
+```
+cli-templates/
+โโโ manifest.json # Template registry with versions
+โโโ cicd/ # CI/CD pipeline templates
+โ โโโ github/
+โ โ โโโ basic.yml
+โ โ โโโ comprehensive.yml
+โ โ โโโ security-focused.yml
+โ โโโ gitlab/
+โ โ โโโ basic.yml
+โ โ โโโ comprehensive.yml
+โ โ โโโ security-focused.yml
+โ โโโ circleci/
+โ โโโ jenkins/
+โ โโโ bitbucket/
+โ โโโ azure/
+โโโ docker/ # Docker templates
+โ โโโ Dockerfile.production.tpl
+โ โโโ Dockerfile.development.tpl
+โ โโโ docker-compose.yml.tpl
+โ โโโ docker-compose.development.yml.tpl
+โโโ kubernetes/ # Kubernetes manifest templates
+โ โโโ deployment.yml.tpl
+โ โโโ service.yml.tpl
+โ โโโ configmap.yml.tpl
+โ โโโ ingress.yml.tpl
+โโโ migrations/ # Migration templates
+ โโโ heroku-to-railway/
+ โโโ heroku-to-render/
+ โโโ heroku-to-fly/
+ โโโ compose-to-kubernetes/
+```
+
+## Template Syntax
+
+Templates use Mustache-like syntax:
+
+- `{{variable}}` - Variable substitution
+- `{{#condition}}...{{/condition}}` - Conditional blocks
+- `{{^condition}}...{{/condition}}` - Negative conditionals
+
+## Usage
+
+```bash
+# List available templates
+expressots templates list
+
+# Update cache
+expressots templates update
+
+# Show status
+expressots templates status
+```
+
+## Contributing
+
+1. Fork this repository
+2. Add or modify templates
+3. Update manifest.json
+4. Submit a pull request
+
+## License
+
+MIT License
diff --git a/cli-templates/cicd/azure/basic.yml b/cli-templates/cicd/azure/basic.yml
new file mode 100644
index 0000000..df2acd8
--- /dev/null
+++ b/cli-templates/cicd/azure/basic.yml
@@ -0,0 +1,43 @@
+# Azure DevOps Pipeline
+# Generated by ExpressoTS CLI
+# Strategy: basic
+# Template Version: 1.0.0
+
+trigger:
+ - {{branch}}
+
+pool:
+ vmImage: 'ubuntu-latest'
+
+variables:
+ nodeVersion: '{{nodeVersion}}'
+
+stages:
+ - stage: Build
+ displayName: 'Build Stage'
+ jobs:
+ - job: BuildJob
+ displayName: 'Build, Lint, and Test'
+ steps:
+ - task: NodeTool@0
+ inputs:
+ versionSpec: '$(nodeVersion)'
+ displayName: 'Install Node.js'
+
+ - script: {{installCmd}}
+ displayName: 'Install dependencies'
+
+ - script: {{lintCmd}}
+ displayName: 'Run linter'
+
+ - script: {{testCmd}}
+ displayName: 'Run tests'
+
+ - script: {{buildCmd}}
+ displayName: 'Build application'
+
+ - task: PublishBuildArtifacts@1
+ inputs:
+ pathToPublish: 'dist'
+ artifactName: 'dist'
+ displayName: 'Publish build artifacts'
diff --git a/cli-templates/cicd/bitbucket/basic.yml b/cli-templates/cicd/bitbucket/basic.yml
new file mode 100644
index 0000000..290f932
--- /dev/null
+++ b/cli-templates/cicd/bitbucket/basic.yml
@@ -0,0 +1,72 @@
+# Bitbucket Pipelines
+# Generated by ExpressoTS CLI
+# Strategy: basic
+# Template Version: 1.0.0
+
+image: node:{{nodeVersion}}-alpine
+
+definitions:
+ caches:
+ npm: $HOME/.npm
+
+pipelines:
+ default:
+ - step:
+ name: Lint
+ caches:
+ - npm
+ - node
+ script:
+ - {{installCmd}}
+ - {{lintCmd}}
+
+ - step:
+ name: Test
+ caches:
+ - npm
+ - node
+ script:
+ - {{installCmd}}
+ - {{testCmd}}
+
+ - step:
+ name: Build
+ caches:
+ - npm
+ - node
+ script:
+ - {{installCmd}}
+ - {{buildCmd}}
+ artifacts:
+ - dist/**
+
+ branches:
+ {{branch}}:
+ - step:
+ name: Lint
+ caches:
+ - npm
+ - node
+ script:
+ - {{installCmd}}
+ - {{lintCmd}}
+
+ - step:
+ name: Test
+ caches:
+ - npm
+ - node
+ script:
+ - {{installCmd}}
+ - {{testCmd}}
+
+ - step:
+ name: Build
+ caches:
+ - npm
+ - node
+ script:
+ - {{installCmd}}
+ - {{buildCmd}}
+ artifacts:
+ - dist/**
diff --git a/cli-templates/cicd/circleci/basic.yml b/cli-templates/cicd/circleci/basic.yml
new file mode 100644
index 0000000..bcaa6e2
--- /dev/null
+++ b/cli-templates/cicd/circleci/basic.yml
@@ -0,0 +1,59 @@
+# CircleCI Configuration
+# Generated by ExpressoTS CLI
+# Strategy: basic
+# Template Version: 1.0.0
+
+version: 2.1
+
+orbs:
+ node: circleci/node@5.1.0
+
+jobs:
+ lint:
+ executor:
+ name: node/default
+ tag: '{{nodeVersion}}'
+ steps:
+ - checkout
+ - node/install-packages
+ - run:
+ name: Run linter
+ command: {{lintCmd}}
+
+ test:
+ executor:
+ name: node/default
+ tag: '{{nodeVersion}}'
+ steps:
+ - checkout
+ - node/install-packages
+ - run:
+ name: Run tests
+ command: {{testCmd}}
+
+ build:
+ executor:
+ name: node/default
+ tag: '{{nodeVersion}}'
+ steps:
+ - checkout
+ - node/install-packages
+ - run:
+ name: Build application
+ command: {{buildCmd}}
+ - persist_to_workspace:
+ root: .
+ paths:
+ - dist
+
+workflows:
+ version: 2
+ build-and-test:
+ jobs:
+ - lint
+ - test:
+ requires:
+ - lint
+ - build:
+ requires:
+ - test
diff --git a/cli-templates/cicd/circleci/comprehensive.yml b/cli-templates/cicd/circleci/comprehensive.yml
new file mode 100644
index 0000000..db07cd0
--- /dev/null
+++ b/cli-templates/cicd/circleci/comprehensive.yml
@@ -0,0 +1,99 @@
+# CircleCI Configuration
+# Generated by ExpressoTS CLI
+# Strategy: comprehensive
+# Template Version: 1.0.0
+
+version: 2.1
+
+orbs:
+ node: circleci/node@5.1.0
+ docker: circleci/docker@2.4.0
+
+jobs:
+ lint:
+ executor:
+ name: node/default
+ tag: '{{nodeVersion}}'
+ steps:
+ - checkout
+ - node/install-packages
+ - run:
+ name: Run linter
+ command: {{lintCmd}}
+
+ test:
+ executor:
+ name: node/default
+ tag: '{{nodeVersion}}'
+ steps:
+ - checkout
+ - node/install-packages
+ - run:
+ name: Run tests
+ command: {{testCmd}}
+{{#includeCoverage}}
+ - run:
+ name: Run tests with coverage
+ command: {{testCmd}} -- --coverage
+ - store_artifacts:
+ path: coverage
+{{/includeCoverage}}
+
+ security:
+ docker:
+ - image: aquasec/trivy:latest
+ steps:
+ - checkout
+ - run:
+ name: Run security scan
+ command: trivy fs --severity HIGH,CRITICAL .
+
+ build:
+ executor:
+ name: node/default
+ tag: '{{nodeVersion}}'
+ steps:
+ - checkout
+ - node/install-packages
+ - run:
+ name: Build application
+ command: {{buildCmd}}
+ - persist_to_workspace:
+ root: .
+ paths:
+ - dist
+
+ docker-build:
+ executor: docker/docker
+ steps:
+ - checkout
+ - setup_remote_docker
+ - docker/check
+ - docker/build:
+ image: {{dockerRegistry}}/$CIRCLE_PROJECT_REPONAME
+ tag: $CIRCLE_SHA1
+ - docker/push:
+ image: {{dockerRegistry}}/$CIRCLE_PROJECT_REPONAME
+ tag: $CIRCLE_SHA1
+
+workflows:
+ version: 2
+ build-test-deploy:
+ jobs:
+ - lint
+ - test:
+ requires:
+ - lint
+ - security:
+ requires:
+ - lint
+ - build:
+ requires:
+ - test
+ - security
+ - docker-build:
+ requires:
+ - build
+ filters:
+ branches:
+ only: {{branch}}
diff --git a/cli-templates/cicd/github/basic.yml b/cli-templates/cicd/github/basic.yml
new file mode 100644
index 0000000..c83ded0
--- /dev/null
+++ b/cli-templates/cicd/github/basic.yml
@@ -0,0 +1,79 @@
+# GitHub Actions CI/CD Pipeline
+# Generated by ExpressoTS CLI
+# Strategy: {{strategy}}
+# Template Version: 1.0.0
+
+name: CI/CD Pipeline
+
+on:
+ push:
+ branches: [{{branch}}]
+ pull_request:
+ branches: [{{branch}}]
+
+env:
+ NODE_VERSION: '{{nodeVersion}}'
+
+jobs:
+ lint:
+ name: Lint
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: '{{packageManager}}'
+
+ - name: Install dependencies
+ run: {{installCmd}}
+
+ - name: Run linter
+ run: {{lintCmd}}
+
+ test:
+ name: Test
+ runs-on: ubuntu-latest
+ needs: lint
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: '{{packageManager}}'
+
+ - name: Install dependencies
+ run: {{installCmd}}
+
+ - name: Run tests
+ run: {{testCmd}}
+
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ needs: test
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: '{{packageManager}}'
+
+ - name: Install dependencies
+ run: {{installCmd}}
+
+ - name: Build application
+ run: {{buildCmd}}
+
+ - name: Upload build artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: dist
+ path: dist/
+ retention-days: 7
diff --git a/cli-templates/cicd/github/comprehensive.yml b/cli-templates/cicd/github/comprehensive.yml
new file mode 100644
index 0000000..80bef76
--- /dev/null
+++ b/cli-templates/cicd/github/comprehensive.yml
@@ -0,0 +1,183 @@
+# GitHub Actions CI/CD Pipeline
+# Generated by ExpressoTS CLI
+# Strategy: comprehensive
+# Template Version: 1.0.0
+
+name: CI/CD Pipeline
+
+on:
+ push:
+ branches: [{{branch}}]
+ pull_request:
+ branches: [{{branch}}]
+
+env:
+ NODE_VERSION: '{{nodeVersion}}'
+ REGISTRY: {{dockerRegistry}}
+ IMAGE_NAME: ${{ github.repository }}
+
+jobs:
+ lint:
+ name: Lint
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: '{{packageManager}}'
+
+ - name: Install dependencies
+ run: {{installCmd}}
+
+ - name: Run linter
+ run: {{lintCmd}}
+
+ test:
+ name: Test
+ runs-on: ubuntu-latest
+ needs: lint
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: '{{packageManager}}'
+
+ - name: Install dependencies
+ run: {{installCmd}}
+
+ - name: Run tests
+ run: {{testCmd}}
+{{#includeCoverage}}
+
+ - name: Run tests with coverage
+ run: {{testCmd}} -- --coverage
+
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v4
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ fail_ci_if_error: false
+{{/includeCoverage}}
+
+ security:
+ name: Security Scan
+ runs-on: ubuntu-latest
+ needs: lint
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Run Trivy vulnerability scanner
+ uses: aquasecurity/trivy-action@master
+ with:
+ scan-type: 'fs'
+ scan-ref: '.'
+ format: 'sarif'
+ output: 'trivy-results.sarif'
+
+ - name: Upload Trivy scan results
+ uses: github/codeql-action/upload-sarif@v3
+ if: always()
+ with:
+ sarif_file: 'trivy-results.sarif'
+
+{{#includeE2E}}
+ e2e:
+ name: E2E Tests
+ runs-on: ubuntu-latest
+ needs: test
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: '{{packageManager}}'
+
+ - name: Install dependencies
+ run: {{installCmd}}
+
+ - name: Build application
+ run: {{buildCmd}}
+
+ - name: Start application
+ run: |
+ npm start &
+ sleep 10
+
+ - name: Run E2E tests
+ run: npm run test:e2e
+{{/includeE2E}}
+
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ needs: [test, security{{#includeE2E}}, e2e{{/includeE2E}}]
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: '{{packageManager}}'
+
+ - name: Install dependencies
+ run: {{installCmd}}
+
+ - name: Build application
+ run: {{buildCmd}}
+
+ - name: Upload build artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: dist
+ path: dist/
+ retention-days: 7
+
+ docker:
+ name: Docker Build
+ runs-on: ubuntu-latest
+ needs: build
+ if: github.event_name == 'push' && github.ref == 'refs/heads/{{branch}}'
+ permissions:
+ contents: read
+ packages: write
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Log in to Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ${{ env.REGISTRY }}
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Extract metadata
+ id: meta
+ uses: docker/metadata-action@v5
+ with:
+ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
+ tags: |
+ type=ref,event=branch
+ type=sha,prefix=
+ type=raw,value=latest,enable={{is_default_branch}}
+
+ - name: Build and push
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ push: true
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
diff --git a/cli-templates/cicd/github/security-focused.yml b/cli-templates/cicd/github/security-focused.yml
new file mode 100644
index 0000000..d8791e8
--- /dev/null
+++ b/cli-templates/cicd/github/security-focused.yml
@@ -0,0 +1,209 @@
+# GitHub Actions CI/CD Pipeline
+# Generated by ExpressoTS CLI
+# Strategy: security-focused
+# Template Version: 1.0.0
+
+name: Security-Focused CI/CD Pipeline
+
+on:
+ push:
+ branches: [{{branch}}]
+ pull_request:
+ branches: [{{branch}}]
+ schedule:
+ - cron: '0 0 * * 0' # Weekly security scan
+
+env:
+ NODE_VERSION: '{{nodeVersion}}'
+ REGISTRY: {{dockerRegistry}}
+ IMAGE_NAME: ${{ github.repository }}
+
+jobs:
+ lint:
+ name: Lint
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: '{{packageManager}}'
+
+ - name: Install dependencies
+ run: {{installCmd}}
+
+ - name: Run linter
+ run: {{lintCmd}}
+
+ test:
+ name: Test
+ runs-on: ubuntu-latest
+ needs: lint
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: '{{packageManager}}'
+
+ - name: Install dependencies
+ run: {{installCmd}}
+
+ - name: Run tests
+ run: {{testCmd}}
+
+ security-trivy:
+ name: Trivy Security Scan
+ runs-on: ubuntu-latest
+ needs: lint
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Run Trivy vulnerability scanner
+ uses: aquasecurity/trivy-action@master
+ with:
+ scan-type: 'fs'
+ scan-ref: '.'
+ format: 'sarif'
+ output: 'trivy-results.sarif'
+ severity: 'CRITICAL,HIGH'
+
+ - name: Upload Trivy scan results
+ uses: github/codeql-action/upload-sarif@v3
+ if: always()
+ with:
+ sarif_file: 'trivy-results.sarif'
+
+ security-snyk:
+ name: Snyk Security Scan
+ runs-on: ubuntu-latest
+ needs: lint
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Run Snyk security scan
+ uses: snyk/actions/node@master
+ continue-on-error: true
+ env:
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
+ with:
+ args: --severity-threshold=high
+
+ security-npm-audit:
+ name: NPM Audit
+ runs-on: ubuntu-latest
+ needs: lint
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+
+ - name: Run npm audit
+ run: npm audit --audit-level=high
+
+ security-owasp:
+ name: OWASP Dependency Check
+ runs-on: ubuntu-latest
+ needs: lint
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: OWASP Dependency Check
+ uses: dependency-check/Dependency-Check_Action@main
+ with:
+ project: '{{projectName}}'
+ path: '.'
+ format: 'HTML'
+
+ - name: Upload OWASP report
+ uses: actions/upload-artifact@v4
+ with:
+ name: owasp-report
+ path: reports/
+
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ needs: [test, security-trivy, security-snyk, security-npm-audit]
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: '{{packageManager}}'
+
+ - name: Install dependencies
+ run: {{installCmd}}
+
+ - name: Build application
+ run: {{buildCmd}}
+
+ - name: Upload build artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: dist
+ path: dist/
+ retention-days: 7
+
+ docker:
+ name: Docker Build & Scan
+ runs-on: ubuntu-latest
+ needs: build
+ if: github.event_name == 'push' && github.ref == 'refs/heads/{{branch}}'
+ permissions:
+ contents: read
+ packages: write
+ security-events: write
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Log in to Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ${{ env.REGISTRY }}
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Build image
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ load: true
+ tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
+
+ - name: Scan container for vulnerabilities
+ uses: aquasecurity/trivy-action@master
+ with:
+ image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
+ format: 'sarif'
+ output: 'container-scan.sarif'
+ severity: 'CRITICAL,HIGH'
+
+ - name: Upload container scan results
+ uses: github/codeql-action/upload-sarif@v3
+ if: always()
+ with:
+ sarif_file: 'container-scan.sarif'
+
+ - name: Push image
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ push: true
+ tags: |
+ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
+ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
diff --git a/cli-templates/cicd/gitlab/basic.yml b/cli-templates/cicd/gitlab/basic.yml
new file mode 100644
index 0000000..e6c5afd
--- /dev/null
+++ b/cli-templates/cicd/gitlab/basic.yml
@@ -0,0 +1,50 @@
+# GitLab CI/CD Pipeline
+# Generated by ExpressoTS CLI
+# Strategy: basic
+# Template Version: 1.0.0
+
+image: node:{{nodeVersion}}-alpine
+
+stages:
+ - lint
+ - test
+ - build
+
+variables:
+ npm_config_cache: "$CI_PROJECT_DIR/.npm"
+
+cache:
+ key: ${CI_COMMIT_REF_SLUG}
+ paths:
+ - .npm/
+ - node_modules/
+
+lint:
+ stage: lint
+ script:
+ - {{installCmd}}
+ - {{lintCmd}}
+ only:
+ - {{branch}}
+ - merge_requests
+
+test:
+ stage: test
+ script:
+ - {{installCmd}}
+ - {{testCmd}}
+ only:
+ - {{branch}}
+ - merge_requests
+
+build:
+ stage: build
+ script:
+ - {{installCmd}}
+ - {{buildCmd}}
+ artifacts:
+ paths:
+ - dist/
+ expire_in: 1 week
+ only:
+ - {{branch}}
diff --git a/cli-templates/cicd/gitlab/comprehensive.yml b/cli-templates/cicd/gitlab/comprehensive.yml
new file mode 100644
index 0000000..63ccf8c
--- /dev/null
+++ b/cli-templates/cicd/gitlab/comprehensive.yml
@@ -0,0 +1,86 @@
+# GitLab CI/CD Pipeline
+# Generated by ExpressoTS CLI
+# Strategy: comprehensive
+# Template Version: 1.0.0
+
+image: node:{{nodeVersion}}-alpine
+
+stages:
+ - lint
+ - test
+ - security
+ - build
+ - docker
+ - deploy
+
+variables:
+ npm_config_cache: "$CI_PROJECT_DIR/.npm"
+ DOCKER_IMAGE: $CI_REGISTRY_IMAGE
+
+cache:
+ key: ${CI_COMMIT_REF_SLUG}
+ paths:
+ - .npm/
+ - node_modules/
+
+lint:
+ stage: lint
+ script:
+ - {{installCmd}}
+ - {{lintCmd}}
+ only:
+ - {{branch}}
+ - merge_requests
+
+test:
+ stage: test
+ script:
+ - {{installCmd}}
+ - {{testCmd}}{{#includeCoverage}} --coverage{{/includeCoverage}}
+{{#includeCoverage}}
+ coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
+ artifacts:
+ reports:
+ coverage_report:
+ coverage_format: cobertura
+ path: coverage/cobertura-coverage.xml
+{{/includeCoverage}}
+ only:
+ - {{branch}}
+ - merge_requests
+
+security:
+ stage: security
+ image: aquasec/trivy:latest
+ script:
+ - trivy fs --severity HIGH,CRITICAL --exit-code 1 .
+ allow_failure: true
+ only:
+ - {{branch}}
+ - merge_requests
+
+build:
+ stage: build
+ script:
+ - {{installCmd}}
+ - {{buildCmd}}
+ artifacts:
+ paths:
+ - dist/
+ expire_in: 1 week
+ only:
+ - {{branch}}
+
+docker:
+ stage: docker
+ image: docker:latest
+ services:
+ - docker:dind
+ before_script:
+ - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+ script:
+ - docker build -t $DOCKER_IMAGE:$CI_COMMIT_SHA -t $DOCKER_IMAGE:latest .
+ - docker push $DOCKER_IMAGE:$CI_COMMIT_SHA
+ - docker push $DOCKER_IMAGE:latest
+ only:
+ - {{branch}}
diff --git a/cli-templates/cicd/gitlab/security-focused.yml b/cli-templates/cicd/gitlab/security-focused.yml
new file mode 100644
index 0000000..90f8946
--- /dev/null
+++ b/cli-templates/cicd/gitlab/security-focused.yml
@@ -0,0 +1,97 @@
+# GitLab CI/CD Pipeline
+# Generated by ExpressoTS CLI
+# Strategy: security-focused
+# Template Version: 1.0.0
+
+image: node:{{nodeVersion}}-alpine
+
+stages:
+ - lint
+ - test
+ - security
+ - sast
+ - build
+ - container-scanning
+ - deploy
+
+include:
+ - template: Security/SAST.gitlab-ci.yml
+ - template: Security/Dependency-Scanning.gitlab-ci.yml
+ - template: Security/Secret-Detection.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml
+
+variables:
+ npm_config_cache: "$CI_PROJECT_DIR/.npm"
+ DOCKER_IMAGE: $CI_REGISTRY_IMAGE
+ SAST_EXCLUDED_PATHS: "node_modules, dist, coverage"
+
+cache:
+ key: ${CI_COMMIT_REF_SLUG}
+ paths:
+ - .npm/
+ - node_modules/
+
+lint:
+ stage: lint
+ script:
+ - {{installCmd}}
+ - {{lintCmd}}
+ only:
+ - {{branch}}
+ - merge_requests
+
+test:
+ stage: test
+ script:
+ - {{installCmd}}
+ - {{testCmd}}
+ only:
+ - {{branch}}
+ - merge_requests
+
+npm-audit:
+ stage: security
+ script:
+ - npm audit --audit-level=high
+ allow_failure: true
+ only:
+ - {{branch}}
+ - merge_requests
+
+trivy-scan:
+ stage: security
+ image: aquasec/trivy:latest
+ script:
+ - trivy fs --severity CRITICAL,HIGH --exit-code 1 --format sarif -o trivy-results.sarif .
+ artifacts:
+ reports:
+ sast: trivy-results.sarif
+ allow_failure: false
+ only:
+ - {{branch}}
+ - merge_requests
+
+build:
+ stage: build
+ script:
+ - {{installCmd}}
+ - {{buildCmd}}
+ artifacts:
+ paths:
+ - dist/
+ expire_in: 1 week
+ only:
+ - {{branch}}
+
+docker:
+ stage: container-scanning
+ image: docker:latest
+ services:
+ - docker:dind
+ before_script:
+ - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+ script:
+ - docker build -t $DOCKER_IMAGE:$CI_COMMIT_SHA .
+ - docker push $DOCKER_IMAGE:$CI_COMMIT_SHA
+ only:
+ - {{branch}}
diff --git a/cli-templates/cicd/jenkins/basic.groovy b/cli-templates/cicd/jenkins/basic.groovy
new file mode 100644
index 0000000..357d9c8
--- /dev/null
+++ b/cli-templates/cicd/jenkins/basic.groovy
@@ -0,0 +1,51 @@
+// Jenkinsfile
+// Generated by ExpressoTS CLI
+// Strategy: basic
+// Template Version: 1.0.0
+
+pipeline {
+ agent {
+ docker {
+ image 'node:{{nodeVersion}}-alpine'
+ }
+ }
+
+ environment {
+ npm_config_cache = "${WORKSPACE}/.npm"
+ }
+
+ stages {
+ stage('Install') {
+ steps {
+ sh '{{installCmd}}'
+ }
+ }
+
+ stage('Lint') {
+ steps {
+ sh '{{lintCmd}}'
+ }
+ }
+
+ stage('Test') {
+ steps {
+ sh '{{testCmd}}'
+ }
+ }
+
+ stage('Build') {
+ steps {
+ sh '{{buildCmd}}'
+ }
+ }
+ }
+
+ post {
+ always {
+ cleanWs()
+ }
+ success {
+ archiveArtifacts artifacts: 'dist/**/*', fingerprint: true
+ }
+ }
+}
diff --git a/cli-templates/docker/Dockerfile.development.tpl b/cli-templates/docker/Dockerfile.development.tpl
new file mode 100644
index 0000000..614b04e
--- /dev/null
+++ b/cli-templates/docker/Dockerfile.development.tpl
@@ -0,0 +1,35 @@
+# Development Dockerfile
+# Generated by ExpressoTS CLI
+# Template Version: 1.0.0
+
+FROM node:{{nodeVersion}}-alpine
+
+WORKDIR /app
+
+# Install development tools
+RUN apk add --no-cache git
+
+# Copy package files
+{{#hasLocalDeps}}
+COPY package.docker.json ./package.json
+COPY .docker-deps/ ./.docker-deps/
+{{/hasLocalDeps}}
+{{^hasLocalDeps}}
+COPY package*.json ./
+{{/hasLocalDeps}}
+
+# Install all dependencies (including dev)
+RUN {{installCommand}}
+
+# Copy source code
+COPY . .
+
+# Set environment variables
+ENV NODE_ENV=development
+ENV PORT={{port}}
+
+# Expose port
+EXPOSE {{port}}
+
+# Start with hot reload
+CMD ["npm", "run", "dev"]
diff --git a/cli-templates/docker/Dockerfile.production.tpl b/cli-templates/docker/Dockerfile.production.tpl
new file mode 100644
index 0000000..c58eb75
--- /dev/null
+++ b/cli-templates/docker/Dockerfile.production.tpl
@@ -0,0 +1,59 @@
+# Production Dockerfile
+# Generated by ExpressoTS CLI
+# Template Version: 1.0.0
+
+# Build stage
+FROM node:{{nodeVersion}}-alpine AS builder
+
+WORKDIR /app
+
+# Copy package files
+{{#hasLocalDeps}}
+COPY package.docker.json ./package.json
+{{/hasLocalDeps}}
+{{^hasLocalDeps}}
+COPY package*.json ./
+{{/hasLocalDeps}}
+
+# Install dependencies
+RUN {{installCommand}}
+
+# Copy source code
+COPY . .
+
+# Build the application
+RUN {{buildCommand}}
+
+# Prune dev dependencies
+RUN npm prune --production
+
+# Production stage
+FROM node:{{nodeVersion}}-alpine AS production
+
+WORKDIR /app
+
+# Create non-root user
+RUN addgroup -g 1001 -S nodejs && \
+ adduser -S expressots -u 1001 -G nodejs
+
+# Copy built files from builder
+COPY --from=builder --chown=expressots:nodejs /app/node_modules ./node_modules
+COPY --from=builder --chown=expressots:nodejs /app/dist ./dist
+COPY --from=builder --chown=expressots:nodejs /app/package.json ./
+
+# Set environment variables
+ENV NODE_ENV=production
+ENV PORT={{port}}
+
+# Switch to non-root user
+USER expressots
+
+# Expose port
+EXPOSE {{port}}
+
+# Health check
+HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
+ CMD wget --no-verbose --tries=1 --spider http://localhost:{{port}}{{healthCheckEndpoint}} || exit 1
+
+# Start the application
+CMD ["node", "{{entryPoint}}"]
diff --git a/cli-templates/docker/docker-compose.development.yml.tpl b/cli-templates/docker/docker-compose.development.yml.tpl
new file mode 100644
index 0000000..d71a398
--- /dev/null
+++ b/cli-templates/docker/docker-compose.development.yml.tpl
@@ -0,0 +1,28 @@
+# Docker Compose - Development
+# Generated by ExpressoTS CLI
+# Template Version: 1.0.0
+
+version: '3.8'
+
+services:
+ app:
+ build:
+ context: .
+ dockerfile: Dockerfile.development
+ container_name: {{projectName}}-dev
+ ports:
+ - "{{port}}:{{port}}"
+ environment:
+ - NODE_ENV=development
+ - PORT={{port}}
+ volumes:
+ - ./src:/app/src:ro
+ - ./package.json:/app/package.json:ro
+ - ./tsconfig.json:/app/tsconfig.json:ro
+ - ./expressots.config.ts:/app/expressots.config.ts:ro
+ networks:
+ - dev-network
+
+networks:
+ dev-network:
+ driver: bridge
diff --git a/cli-templates/docker/docker-compose.yml.tpl b/cli-templates/docker/docker-compose.yml.tpl
new file mode 100644
index 0000000..579585b
--- /dev/null
+++ b/cli-templates/docker/docker-compose.yml.tpl
@@ -0,0 +1,30 @@
+# Docker Compose - Production
+# Generated by ExpressoTS CLI
+# Template Version: 1.0.0
+
+version: '3.8'
+
+services:
+ app:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ container_name: {{projectName}}
+ restart: unless-stopped
+ ports:
+ - "{{port}}:{{port}}"
+ environment:
+ - NODE_ENV=production
+ - PORT={{port}}
+ healthcheck:
+ test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:{{port}}{{healthCheckEndpoint}}"]
+ interval: 30s
+ timeout: 3s
+ retries: 3
+ start_period: 10s
+ networks:
+ - app-network
+
+networks:
+ app-network:
+ driver: bridge
diff --git a/cli-templates/kubernetes/configmap.yml.tpl b/cli-templates/kubernetes/configmap.yml.tpl
new file mode 100644
index 0000000..5d5fea7
--- /dev/null
+++ b/cli-templates/kubernetes/configmap.yml.tpl
@@ -0,0 +1,17 @@
+# Kubernetes ConfigMap
+# Generated by ExpressoTS CLI
+# Template Version: 1.0.0
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{appName}}-config
+ namespace: {{namespace}}
+ labels:
+ app: {{appName}}
+data:
+ NODE_ENV: "production"
+ PORT: "{{port}}"
+ # Add your application configuration here
+ # LOG_LEVEL: "info"
+ # API_VERSION: "v1"
diff --git a/cli-templates/kubernetes/deployment.yml.tpl b/cli-templates/kubernetes/deployment.yml.tpl
new file mode 100644
index 0000000..9ad5f69
--- /dev/null
+++ b/cli-templates/kubernetes/deployment.yml.tpl
@@ -0,0 +1,54 @@
+# Kubernetes Deployment
+# Generated by ExpressoTS CLI
+# Template Version: 1.0.0
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{appName}}
+ namespace: {{namespace}}
+ labels:
+ app: {{appName}}
+spec:
+ replicas: {{replicas}}
+ selector:
+ matchLabels:
+ app: {{appName}}
+ template:
+ metadata:
+ labels:
+ app: {{appName}}
+ spec:
+ containers:
+ - name: app
+ image: your-registry/{{appName}}:latest
+ ports:
+ - containerPort: {{port}}
+ name: http
+ env:
+ - name: NODE_ENV
+ value: "production"
+ - name: PORT
+ value: "{{port}}"
+ envFrom:
+ - configMapRef:
+ name: {{appName}}-config
+ resources:
+ requests:
+ memory: "{{memory}}"
+ cpu: "{{cpu}}"
+ limits:
+ memory: "512Mi"
+ cpu: "500m"
+ livenessProbe:
+ httpGet:
+ path: {{healthCheckPath}}
+ port: {{port}}
+ initialDelaySeconds: 30
+ periodSeconds: 10
+ readinessProbe:
+ httpGet:
+ path: {{healthCheckPath}}
+ port: {{port}}
+ initialDelaySeconds: 5
+ periodSeconds: 5
diff --git a/cli-templates/kubernetes/ingress.yml.tpl b/cli-templates/kubernetes/ingress.yml.tpl
new file mode 100644
index 0000000..8792083
--- /dev/null
+++ b/cli-templates/kubernetes/ingress.yml.tpl
@@ -0,0 +1,30 @@
+# Kubernetes Ingress
+# Generated by ExpressoTS CLI
+# Template Version: 1.0.0
+
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: {{appName}}-ingress
+ namespace: {{namespace}}
+ labels:
+ app: {{appName}}
+ annotations:
+ kubernetes.io/ingress.class: nginx
+ cert-manager.io/cluster-issuer: letsencrypt-prod
+spec:
+ tls:
+ - hosts:
+ - {{appName}}.example.com
+ secretName: {{appName}}-tls
+ rules:
+ - host: {{appName}}.example.com
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: {{appName}}
+ port:
+ number: 80
diff --git a/cli-templates/kubernetes/service.yml.tpl b/cli-templates/kubernetes/service.yml.tpl
new file mode 100644
index 0000000..fc51f9e
--- /dev/null
+++ b/cli-templates/kubernetes/service.yml.tpl
@@ -0,0 +1,20 @@
+# Kubernetes Service
+# Generated by ExpressoTS CLI
+# Template Version: 1.0.0
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{appName}}
+ namespace: {{namespace}}
+ labels:
+ app: {{appName}}
+spec:
+ type: ClusterIP
+ ports:
+ - port: 80
+ targetPort: {{port}}
+ protocol: TCP
+ name: http
+ selector:
+ app: {{appName}}
diff --git a/cli-templates/manifest.json b/cli-templates/manifest.json
new file mode 100644
index 0000000..edb3ac8
--- /dev/null
+++ b/cli-templates/manifest.json
@@ -0,0 +1,147 @@
+{
+ "$schema": "https://raw.githubusercontent.com/expressots/templates/main/manifest.schema.json",
+ "version": "1.0.0",
+ "updated": "2026-01-07T00:00:00Z",
+ "description": "ExpressoTS CLI Templates Repository",
+ "templates": {
+ "cicd": {
+ "github": {
+ "basic": {
+ "path": "cicd/github/basic.yml",
+ "version": "1.0.0",
+ "description": "Basic GitHub Actions CI/CD pipeline with lint, test, and build"
+ },
+ "comprehensive": {
+ "path": "cicd/github/comprehensive.yml",
+ "version": "1.0.0",
+ "description": "Full CI/CD pipeline with security scanning, E2E tests, and Docker"
+ },
+ "security-focused": {
+ "path": "cicd/github/security-focused.yml",
+ "version": "1.0.0",
+ "description": "Security-focused pipeline with Trivy, Snyk, and OWASP checks"
+ }
+ },
+ "gitlab": {
+ "basic": {
+ "path": "cicd/gitlab/basic.yml",
+ "version": "1.0.0",
+ "description": "Basic GitLab CI pipeline"
+ },
+ "comprehensive": {
+ "path": "cicd/gitlab/comprehensive.yml",
+ "version": "1.0.0",
+ "description": "Comprehensive GitLab CI pipeline"
+ },
+ "security-focused": {
+ "path": "cicd/gitlab/security-focused.yml",
+ "version": "1.0.0",
+ "description": "Security-focused GitLab CI pipeline"
+ }
+ },
+ "circleci": {
+ "basic": {
+ "path": "cicd/circleci/basic.yml",
+ "version": "1.0.0",
+ "description": "Basic CircleCI pipeline"
+ },
+ "comprehensive": {
+ "path": "cicd/circleci/comprehensive.yml",
+ "version": "1.0.0",
+ "description": "Comprehensive CircleCI pipeline"
+ }
+ },
+ "jenkins": {
+ "basic": {
+ "path": "cicd/jenkins/basic.groovy",
+ "version": "1.0.0",
+ "description": "Basic Jenkinsfile"
+ }
+ },
+ "bitbucket": {
+ "basic": {
+ "path": "cicd/bitbucket/basic.yml",
+ "version": "1.0.0",
+ "description": "Basic Bitbucket Pipelines"
+ }
+ },
+ "azure": {
+ "basic": {
+ "path": "cicd/azure/basic.yml",
+ "version": "1.0.0",
+ "description": "Basic Azure DevOps pipeline"
+ }
+ }
+ },
+ "docker": {
+ "production": {
+ "path": "docker/Dockerfile.production.tpl",
+ "version": "1.0.0",
+ "description": "Production-optimized multi-stage Dockerfile"
+ },
+ "development": {
+ "path": "docker/Dockerfile.development.tpl",
+ "version": "1.0.0",
+ "description": "Development Dockerfile with hot reload"
+ },
+ "compose": {
+ "path": "docker/docker-compose.yml.tpl",
+ "version": "1.0.0",
+ "description": "Production Docker Compose configuration"
+ },
+ "compose-development": {
+ "path": "docker/docker-compose.development.yml.tpl",
+ "version": "1.0.0",
+ "description": "Development Docker Compose with volume mounts"
+ }
+ },
+ "kubernetes": {
+ "deployment": {
+ "path": "kubernetes/deployment.yml.tpl",
+ "version": "1.0.0",
+ "description": "Kubernetes Deployment manifest"
+ },
+ "service": {
+ "path": "kubernetes/service.yml.tpl",
+ "version": "1.0.0",
+ "description": "Kubernetes Service manifest"
+ },
+ "configmap": {
+ "path": "kubernetes/configmap.yml.tpl",
+ "version": "1.0.0",
+ "description": "Kubernetes ConfigMap manifest"
+ },
+ "ingress": {
+ "path": "kubernetes/ingress.yml.tpl",
+ "version": "1.0.0",
+ "description": "Kubernetes Ingress manifest"
+ }
+ },
+ "migrations": {
+ "heroku-to-railway": {
+ "checklist": {
+ "path": "migrations/heroku-to-railway/checklist.md.tpl",
+ "version": "1.0.0"
+ }
+ },
+ "heroku-to-render": {
+ "checklist": {
+ "path": "migrations/heroku-to-render/checklist.md.tpl",
+ "version": "1.0.0"
+ }
+ },
+ "heroku-to-fly": {
+ "checklist": {
+ "path": "migrations/heroku-to-fly/checklist.md.tpl",
+ "version": "1.0.0"
+ }
+ },
+ "compose-to-kubernetes": {
+ "checklist": {
+ "path": "migrations/compose-to-kubernetes/checklist.md.tpl",
+ "version": "1.0.0"
+ }
+ }
+ }
+ }
+}
diff --git a/cli-templates/migrations/compose-to-kubernetes/checklist.md.tpl b/cli-templates/migrations/compose-to-kubernetes/checklist.md.tpl
new file mode 100644
index 0000000..68b01fb
--- /dev/null
+++ b/cli-templates/migrations/compose-to-kubernetes/checklist.md.tpl
@@ -0,0 +1,48 @@
+# Docker Compose to Kubernetes Migration Checklist
+
+Generated by ExpressoTS CLI
+
+## Pre-Migration
+
+- [ ] Review existing docker-compose.yml
+- [ ] Identify all services and dependencies
+- [ ] Set up Kubernetes cluster (local or cloud)
+- [ ] Install kubectl and configure context
+- [ ] Create container registry access
+
+## Migration Steps
+
+### 1. Create Kubernetes Manifests
+- [ ] Create namespace
+- [ ] Create ConfigMaps for configuration
+- [ ] Create Secrets for sensitive data
+- [ ] Create Deployments for each service
+- [ ] Create Services for networking
+- [ ] Create Ingress for external access
+
+### 2. Container Images
+- [ ] Push images to container registry
+- [ ] Update image references in manifests
+- [ ] Configure image pull secrets if needed
+
+### 3. Persistent Storage
+- [ ] Create PersistentVolumeClaims
+- [ ] Migrate data volumes
+- [ ] Update pod specs with volume mounts
+
+### 4. Networking
+- [ ] Configure service discovery
+- [ ] Set up internal DNS
+- [ ] Configure load balancing
+
+### 5. Deploy
+- [ ] Apply manifests: `kubectl apply -f k8s/`
+- [ ] Verify pods are running
+- [ ] Check logs for errors
+
+## Post-Migration
+
+- [ ] Set up monitoring (Prometheus/Grafana)
+- [ ] Configure alerting
+- [ ] Set up CI/CD for Kubernetes
+- [ ] Document runbooks
diff --git a/cli-templates/migrations/heroku-to-fly/checklist.md.tpl b/cli-templates/migrations/heroku-to-fly/checklist.md.tpl
new file mode 100644
index 0000000..b6e759a
--- /dev/null
+++ b/cli-templates/migrations/heroku-to-fly/checklist.md.tpl
@@ -0,0 +1,41 @@
+# Heroku to Fly.io Migration Checklist
+
+Generated by ExpressoTS CLI
+
+## Pre-Migration
+
+- [ ] Export Heroku environment variables
+- [ ] Install Fly CLI: `brew install flyctl` or `curl -L https://fly.io/install.sh | sh`
+- [ ] Login to Fly: `flyctl auth login`
+- [ ] Backup database if applicable
+
+## Migration Steps
+
+### 1. Initialize Fly App
+- [ ] Run `flyctl launch` in project directory
+- [ ] Review generated `fly.toml`
+- [ ] Configure regions
+
+### 2. Environment Variables
+- [ ] Set secrets: `flyctl secrets set KEY=value`
+- [ ] Review `[env]` section in fly.toml
+
+### 3. Database Migration (if applicable)
+- [ ] Create Fly Postgres: `flyctl postgres create`
+- [ ] Attach to app: `flyctl postgres attach`
+- [ ] Migrate data
+
+### 4. Deploy
+- [ ] Deploy: `flyctl deploy`
+- [ ] Check status: `flyctl status`
+- [ ] View logs: `flyctl logs`
+
+### 5. DNS & Scaling
+- [ ] Configure custom domain
+- [ ] Scale as needed: `flyctl scale count 2`
+
+## Post-Migration
+
+- [ ] Verify all features
+- [ ] Update CI/CD to use Fly
+- [ ] Delete Heroku app
diff --git a/cli-templates/migrations/heroku-to-railway/checklist.md.tpl b/cli-templates/migrations/heroku-to-railway/checklist.md.tpl
new file mode 100644
index 0000000..3b71578
--- /dev/null
+++ b/cli-templates/migrations/heroku-to-railway/checklist.md.tpl
@@ -0,0 +1,54 @@
+# Heroku to Railway Migration Checklist
+
+Generated by ExpressoTS CLI
+
+## Pre-Migration
+
+- [ ] Export Heroku environment variables: `heroku config -a `
+- [ ] Export Heroku add-ons list: `heroku addons -a `
+- [ ] Backup database if applicable
+- [ ] Review current Heroku dyno configuration
+- [ ] Create Railway account at https://railway.app
+
+## Migration Steps
+
+### 1. Environment Setup
+- [ ] Create new Railway project
+- [ ] Link GitHub repository
+- [ ] Configure environment variables in Railway dashboard
+
+### 2. Database Migration (if applicable)
+- [ ] Provision Railway database
+- [ ] Update DATABASE_URL in Railway
+- [ ] Migrate data from Heroku database
+
+### 3. Deploy Configuration
+- [ ] Review `railway.json` configuration
+- [ ] Configure build settings
+- [ ] Set start command
+
+### 4. Testing
+- [ ] Deploy to Railway staging
+- [ ] Verify application starts correctly
+- [ ] Test all endpoints
+- [ ] Check logs for errors
+
+### 5. DNS & Cutover
+- [ ] Configure custom domain in Railway
+- [ ] Update DNS records
+- [ ] Monitor application health
+
+## Post-Migration
+
+- [ ] Verify all features work correctly
+- [ ] Update CI/CD pipelines
+- [ ] Update documentation
+- [ ] Scale down/delete Heroku app
+
+## Environment Variable Mapping
+
+| Heroku | Railway |
+|--------|---------|
+| PORT | PORT (auto-configured) |
+| DATABASE_URL | DATABASE_URL |
+| NODE_ENV | NODE_ENV |
diff --git a/cli-templates/migrations/heroku-to-render/checklist.md.tpl b/cli-templates/migrations/heroku-to-render/checklist.md.tpl
new file mode 100644
index 0000000..13d6b28
--- /dev/null
+++ b/cli-templates/migrations/heroku-to-render/checklist.md.tpl
@@ -0,0 +1,42 @@
+# Heroku to Render Migration Checklist
+
+Generated by ExpressoTS CLI
+
+## Pre-Migration
+
+- [ ] Export Heroku environment variables
+- [ ] Export Heroku add-ons list
+- [ ] Backup database if applicable
+- [ ] Create Render account at https://render.com
+
+## Migration Steps
+
+### 1. Create Render Service
+- [ ] Create new Web Service in Render
+- [ ] Connect GitHub/GitLab repository
+- [ ] Configure build command
+- [ ] Configure start command
+
+### 2. Environment Variables
+- [ ] Add all environment variables
+- [ ] Configure any secret groups
+
+### 3. Database Migration (if applicable)
+- [ ] Create PostgreSQL database in Render
+- [ ] Update DATABASE_URL
+- [ ] Migrate data
+
+### 4. Testing
+- [ ] Deploy to Render
+- [ ] Verify application health
+- [ ] Test all endpoints
+
+### 5. DNS Cutover
+- [ ] Configure custom domain
+- [ ] Update DNS records
+
+## Post-Migration
+
+- [ ] Verify all features
+- [ ] Update CI/CD pipelines
+- [ ] Delete Heroku app
diff --git a/cli-templates/pricing.json b/cli-templates/pricing.json
new file mode 100644
index 0000000..3c7a1dc
--- /dev/null
+++ b/cli-templates/pricing.json
@@ -0,0 +1,121 @@
+{
+ "$schema": "https://raw.githubusercontent.com/expressots/pricing/main/pricing.schema.json",
+ "version": "1.0.0",
+ "updated": "2026-01-07T00:00:00Z",
+ "description": "ExpressoTS CLI Cloud Provider Pricing Data",
+ "disclaimer": "Prices are estimates and may vary by region. Check provider websites for current pricing.",
+ "providers": {
+ "aws": {
+ "serviceName": "ECS Fargate",
+ "model": "per-hour",
+ "basePrice": 0,
+ "cpuPerHour": 0.04048,
+ "memoryPerGbHour": 0.004445,
+ "storagePerGb": 0.10,
+ "bandwidthPerGb": 0.09,
+ "freeBandwidth": 100,
+ "freeCredits": 0,
+ "notes": "Prices for us-east-1 region",
+ "source": "https://aws.amazon.com/fargate/pricing/",
+ "lastVerified": "2026-01-05"
+ },
+ "gcp": {
+ "serviceName": "Cloud Run",
+ "model": "per-hour",
+ "basePrice": 0,
+ "cpuPerHour": 0.024,
+ "memoryPerGbHour": 0.0025,
+ "storagePerGb": 0.10,
+ "bandwidthPerGb": 0.12,
+ "freeBandwidth": 200,
+ "freeCredits": 300,
+ "notes": "Pay only for what you use, scales to zero",
+ "source": "https://cloud.google.com/run/pricing",
+ "lastVerified": "2026-01-05"
+ },
+ "azure": {
+ "serviceName": "Container Apps",
+ "model": "per-hour",
+ "basePrice": 0,
+ "cpuPerHour": 0.024,
+ "memoryPerGbHour": 0.003,
+ "storagePerGb": 0.10,
+ "bandwidthPerGb": 0.087,
+ "freeBandwidth": 100,
+ "freeCredits": 200,
+ "notes": "First 180,000 vCPU-seconds free per month",
+ "source": "https://azure.microsoft.com/pricing/details/container-apps/",
+ "lastVerified": "2026-01-05"
+ },
+ "railway": {
+ "serviceName": "Web Service",
+ "model": "usage",
+ "basePrice": 5,
+ "cpuPerHour": 0.000463,
+ "memoryPerGbHour": 0.000231,
+ "storagePerGb": 0.25,
+ "bandwidthPerGb": 0,
+ "freeBandwidth": 1000,
+ "freeCredits": 5,
+ "notes": "Usage-based pricing, great DX",
+ "source": "https://railway.app/pricing",
+ "lastVerified": "2026-01-05"
+ },
+ "render": {
+ "serviceName": "Web Service",
+ "model": "per-month",
+ "basePrice": 7,
+ "cpuPerHour": 0,
+ "memoryPerGbHour": 0,
+ "storagePerGb": 0.25,
+ "bandwidthPerGb": 0.10,
+ "freeBandwidth": 100,
+ "freeCredits": 0,
+ "notes": "Simple pricing, auto-scaling available",
+ "source": "https://render.com/pricing",
+ "lastVerified": "2026-01-05"
+ },
+ "fly": {
+ "serviceName": "Machines",
+ "model": "per-hour",
+ "basePrice": 0,
+ "cpuPerHour": 0.0000158,
+ "memoryPerGbHour": 0.0000047,
+ "storagePerGb": 0.15,
+ "bandwidthPerGb": 0.02,
+ "freeBandwidth": 100,
+ "freeCredits": 0,
+ "notes": "Pay for resources while running, scales to zero",
+ "source": "https://fly.io/docs/about/pricing/",
+ "lastVerified": "2026-01-05"
+ },
+ "digitalocean": {
+ "serviceName": "App Platform",
+ "model": "per-month",
+ "basePrice": 5,
+ "cpuPerHour": 0,
+ "memoryPerGbHour": 0,
+ "storagePerGb": 0.10,
+ "bandwidthPerGb": 0.01,
+ "freeBandwidth": 500,
+ "freeCredits": 0,
+ "notes": "Simple pricing, good for small projects",
+ "source": "https://www.digitalocean.com/pricing/app-platform",
+ "lastVerified": "2026-01-05"
+ },
+ "heroku": {
+ "serviceName": "Eco Dyno",
+ "model": "per-month",
+ "basePrice": 5,
+ "cpuPerHour": 0,
+ "memoryPerGbHour": 0,
+ "storagePerGb": 0,
+ "bandwidthPerGb": 0,
+ "freeBandwidth": 2000,
+ "freeCredits": 0,
+ "notes": "Basic: $7/mo, Standard: $25/mo, Performance: $250+/mo",
+ "source": "https://www.heroku.com/pricing",
+ "lastVerified": "2026-01-05"
+ }
+ }
+}
diff --git a/commitlint.config.ts b/commitlint.config.ts
index 149bce3..3cbf29f 100644
--- a/commitlint.config.ts
+++ b/commitlint.config.ts
@@ -1,7 +1,12 @@
-import type { UserConfig } from '@commitlint/types'
+import type { UserConfig } from "@commitlint/types";
const Configuration: UserConfig = {
- extends: ['@commitlint/config-conventional']
-}
+ extends: ["@commitlint/config-conventional"],
+ rules: {
+ "subject-max-length": [0],
+ "body-max-line-length": [0],
+ "header-max-length": [0],
+ },
+};
-export default Configuration
\ No newline at end of file
+export default Configuration;
diff --git a/micro/README.md b/micro/README.md
index c09d790..b36e0af 100644
--- a/micro/README.md
+++ b/micro/README.md
@@ -1,74 +1,234 @@
-# Expresso TS
+# ExpressoTS Micro
-A Typescript + [Node.js]("https://nodejs.org/en/") lightweight framework for quick building scalable, easy to read and maintain, server-side applications ๐
+A lightweight, minimal ExpressoTS microservice template with powerful enterprise features.
-## Philosophy
+## Quick Start
-ExpressoTS is a TypeScript lightweight framework for building scalable, readable and maintainable server-side applications. The framework provides a level of abstraction on top of common HTTP server framework Expressjs exposing their API's directly to the developer. This provides freedom and brings to the developer a tool that is well known and easy to use.
+```bash
+# Install dependencies
+npm install
-## How to use
+# Start development server
+npm run dev
-### Executing in development mode
+# Build for production
+npm run build
-```bash
-npm run dev
+# Run in production
+npm run prod
```
-### Generating production build
+## Project Structure
-```bash
-npm run build
+```
+src/
+โโโ api.ts # Single file API
+
+examples/ # Advanced feature examples
+โโโ circuit-breaker.example.ts
+โโโ service-discovery.example.ts
+โโโ service-client.example.ts
+โโโ serverless-lambda.example.ts
+โโโ full-di-api.example.ts
```
-### Executing in production mode
+## Adding Routes
-```bash
-npm run prod
+```typescript
+import { micro } from "@expressots/adapter-express";
+
+const app = micro();
+
+// Simple GET route - return value is auto-sent as JSON
+app.get("/users", () => {
+ return { users: [] };
+});
+
+// POST route with request body
+app.post("/users", (req) => {
+ const user = req.body;
+ return user;
+});
+
+// Route with parameters
+app.get("/users/:id", (req) => {
+ return { id: req.params.id };
+});
+
+// Route with query parameters
+app.get("/search", (req) => {
+ return { query: req.query.q };
+});
+
+// Use res directly for custom responses
+app.post("/custom", (req, res) => {
+ res.status(201).json({ created: true });
+});
+
+app.listen(3000);
+```
+
+## Middleware Support
+
+```typescript
+// Global middleware
+app.use((req, res, next) => {
+ console.log(`${req.method} ${req.path}`);
+ next();
+});
+
+// Path-specific middleware
+app.use("/api", authMiddleware);
+
+// Route-specific middleware (before handler)
+const validate = (req, res, next) => {
+ if (!req.body.name) {
+ return res.status(400).json({ error: "Name required" });
+ }
+ next();
+};
+
+app.post("/users", validate, (req) => {
+ return { created: true };
+});
```
-## Test
+## Error Handling
-How to run test scripts
+```typescript
+app.setErrorHandler((err, req, res, next) => {
+ console.error(err);
+ res.status(500).json({ error: err.message });
+});
+```
-### Unit tests
+## Configuration
-```bash
-npm run test
+```typescript
+const app = micro({
+ autoParseJson: true, // Enable JSON body parsing (default: true)
+ globalPrefix: "/api", // Add prefix to all routes
+ showBanner: true, // Show startup banner (default: true)
+});
```
-### Test coverage
+## Advanced Features
-```bash
-npm run test:cov
+ExpressoTS Micro includes powerful enterprise features for building production-ready microservices:
+
+### Circuit Breaker
+
+Protect your services from cascading failures:
+
+```typescript
+import { CircuitBreaker } from "@expressots/adapter-express";
+
+const breaker = new CircuitBreaker({
+ failureThreshold: 5,
+ successThreshold: 2,
+ timeout: 60000,
+});
+
+app.get("/external-api", async () => {
+ return await breaker.execute(async () => {
+ const response = await fetch("https://api.example.com/data");
+ return response.json();
+ });
+});
+```
+
+### Service Discovery
+
+Register and discover service instances with load balancing:
+
+```typescript
+import { ServiceDiscovery } from "@expressots/adapter-express";
+
+const discovery = new ServiceDiscovery({ type: "static" });
+
+discovery.registerService({
+ id: "user-service-1",
+ name: "user-service",
+ host: "localhost",
+ port: 3001,
+ health: "healthy",
+ lastCheck: new Date(),
+});
+
+// Get a healthy instance (round-robin load balancing)
+const instance = discovery.getService("user-service");
+```
+
+### Service Client
+
+HTTP client with retry logic and circuit breaker integration:
+
+```typescript
+import { ServiceClient } from "@expressots/adapter-express";
+
+const client = new ServiceClient({
+ name: "user-service",
+ baseUrl: "http://localhost:3001",
+ timeout: 5000,
+ retries: 3,
+ circuitBreaker: {
+ failureThreshold: 5,
+ timeout: 60000,
+ },
+});
+
+app.get("/users", async () => {
+ return await client.get("/api/users");
+});
```
-## Documentation
+### Serverless Deployment
+
+Deploy to AWS Lambda, Vercel, or Cloudflare Workers. See `examples/serverless-lambda.example.ts`.
+
+## Upgrading to Full DI
-- Here is our [Official Documentation](https://expresso-ts.com/)
-- Checkout our [First Steps documentation](https://expresso-ts.com/docs/overview/first-steps)
-- Our [CLI Documentation](https://expresso-ts.com/docs/category/cli)
+When you need dependency injection and more advanced features, upgrade to `createMicroAPI()`:
-## Questions
+```typescript
+import { createMicroAPI } from "@expressots/adapter-express";
-For questions and support please use the Official [Discord Channel](https://discord.com/invite/PyPJfGK). We have a very active community there, that will be happy to help you. Post your questions in the channel called **HELP EXPRESSO TS** and forum called **help**.
+const microAPI = createMicroAPI();
+microAPI.setGlobalRoutePrefix("/api/v1");
-## Issues
+const app = microAPI.build();
+app.Middleware.parse();
-The [Issue Reporting Channel](https://github.com/expressots/expressots/issues) is for bug report and feature request **only**.
+app.Route.get("/users", async (req, res) => {
+ res.json([]);
+});
-Before you create an issue, please make sure you read the [Contribution Guidelines](CONTRIBUTING.md).
+await app.listen(3000);
+```
+
+See `examples/full-di-api.example.ts` for a complete example.
+
+## Examples
-## Support the project
+Check the `examples/` folder for complete working examples of:
-Expresso TS is an MIT-licensed open source project. It's an independent project with ongoing development made possible thanks to your support. If you'd like to help, please consider:
+- **Circuit Breaker** - Fault tolerance pattern
+- **Service Discovery** - Service registration and load balancing
+- **Service Client** - HTTP client with retries
+- **Serverless** - AWS Lambda deployment
+- **Full DI API** - Upgrade path with dependency injection
-- Become a sponsor on **[Sponsor no GitHub](https://github.com/sponsors/expressots)**
-- Follow the **[organization](https://github.com/expressots)** on GitHub and Star โญ the project
-- Subscribe to the Twitch channel: **[Richard Zampieri](https://www.twitch.tv/richardzampieri)**
-- Join our **[Discord](https://discord.com/invite/PyPJfGK)**
-- Contribute submitting **[issues and pull requests](https://github.com/expressots/expressots/issues/new/choose)**
-- Share the project with your friends and colleagues
+Run examples with:
+
+```bash
+npm run example:circuit-breaker
+npm run example:service-discovery
+```
-## License
+## Learn More
-ExpressoTS is **[MIT licensed](LICENSE.md)**
\ No newline at end of file
+- [ExpressoTS Documentation](https://expresso-ts.com)
+- [GitHub Repository](https://github.com/expressots)
+- [Discord Community](https://discord.gg/PyPJfGK)
+- [Advanced Features Guide](./ADVANCED.md)
+- [Upgrading Guide](./UPGRADING.md)
diff --git a/micro/eslint.config.mjs b/micro/eslint.config.mjs
new file mode 100644
index 0000000..f480369
--- /dev/null
+++ b/micro/eslint.config.mjs
@@ -0,0 +1,43 @@
+import js from "@eslint/js";
+import tseslint from "typescript-eslint";
+import { fileURLToPath } from "node:url";
+
+const __dirname = fileURLToPath(new URL(".", import.meta.url));
+
+export default tseslint.config(
+ js.configs.recommended,
+ ...tseslint.configs.recommended,
+ {
+ files: ["src/**/*.ts", "test/**/*.ts"],
+ languageOptions: {
+ parserOptions: {
+ project: true,
+ tsconfigRootDir: __dirname,
+ },
+ },
+ rules: {
+ // TypeScript-specific rules
+ "@typescript-eslint/no-unused-vars": [
+ "error",
+ {
+ argsIgnorePattern: "^_",
+ varsIgnorePattern: "^_",
+ },
+ ],
+ "@typescript-eslint/explicit-function-return-type": "off",
+ "@typescript-eslint/no-explicit-any": "off",
+ "@typescript-eslint/no-unused-vars": "off",
+ "@typescript-eslint/no-non-null-assertion": "warn",
+ },
+ },
+ {
+ ignores: [
+ "node_modules/**",
+ "dist/**",
+ "coverage/**",
+ "*.config.ts",
+ "*.config.js",
+ "*.config.mjs",
+ ],
+ },
+);
diff --git a/micro/examples/README.md b/micro/examples/README.md
new file mode 100644
index 0000000..0b486fd
--- /dev/null
+++ b/micro/examples/README.md
@@ -0,0 +1,133 @@
+# ExpressoTS Micro Examples
+
+This folder contains examples demonstrating the advanced features available in ExpressoTS Micro.
+
+## Running Examples
+
+Each example can be run independently using the provided npm scripts:
+
+```bash
+# Circuit Breaker - Fault tolerance pattern
+npm run example:circuit-breaker
+
+# Service Discovery - Service registration and load balancing
+npm run example:service-discovery
+
+# Service Client - HTTP client with retries
+npm run example:service-client
+
+# Full DI API - Upgrade path with dependency injection
+npm run example:full-di-api
+```
+
+For the serverless example, see the deployment instructions in the file.
+
+## Examples Overview
+
+### 1. Circuit Breaker (`circuit-breaker.example.ts`)
+
+Demonstrates the Circuit Breaker pattern for protecting your service from cascading failures:
+
+- **CLOSED**: Normal operation, requests pass through
+- **OPEN**: Requests fail immediately (service unavailable)
+- **HALF_OPEN**: Testing if service has recovered
+
+Key features:
+- Configurable failure and success thresholds
+- Automatic recovery after timeout
+- Manual reset and open controls
+- Statistics and monitoring
+
+### 2. Service Discovery (`service-discovery.example.ts`)
+
+Shows how to implement service discovery for microservices:
+
+- Static service registration
+- Round-robin load balancing
+- Health status tracking
+- Dynamic service registration/deregistration
+
+Use cases:
+- Microservice architecture
+- Multiple service instances
+- Blue/green deployments
+
+### 3. Service Client (`service-client.example.ts`)
+
+Demonstrates HTTP client for service-to-service communication:
+
+- Automatic retries with exponential backoff
+- Request timeouts
+- Circuit breaker integration
+- Custom headers per request
+- Query parameter handling
+
+Use cases:
+- API Gateway pattern
+- Service composition
+- External API calls
+
+### 4. Serverless Lambda (`serverless-lambda.example.ts`)
+
+Shows how to deploy to AWS Lambda:
+
+- Same code works locally and on Lambda
+- AWS SAM template example
+- Environment-aware configuration
+- Binary content handling
+
+Deployment steps included in the file.
+
+### 5. Full DI API (`full-di-api.example.ts`)
+
+Upgrade path from simple `micro()` to full `createMicroAPI()`:
+
+- Dependency injection container
+- Provider registration (singleton, transient)
+- Middleware pipeline
+- Route management
+
+## Feature Comparison
+
+| Feature | micro() | createMicroAPI() |
+|---------|---------|------------------|
+| Simple routing | โ
| โ
|
+| Auto-response | โ
| โ |
+| Middleware | โ
basic | โ
pipeline |
+| DI Container | โ | โ
|
+| Provider registration | โ | โ
|
+
+## When to Use What
+
+### Use `micro()` when:
+- Building simple APIs or serverless functions
+- Prototyping quickly
+- Don't need dependency injection
+- Want minimal boilerplate
+
+### Use `createMicroAPI()` when:
+- Building larger microservices
+- Need dependency injection
+- Need advanced middleware pipeline
+- Building with provider pattern
+
+### Use Circuit Breaker when:
+- Calling external/unreliable services
+- Need fault tolerance
+- Want to prevent cascading failures
+
+### Use Service Discovery when:
+- Running multiple service instances
+- Need load balancing
+- Building microservice mesh
+
+### Use Service Client when:
+- Service-to-service communication
+- Need automatic retries
+- Want circuit breaker on HTTP calls
+
+## Learn More
+
+- [ExpressoTS Documentation](https://expresso-ts.com)
+- [Advanced Features Guide](../ADVANCED.md)
+- [Upgrading Guide](../UPGRADING.md)
diff --git a/micro/examples/circuit-breaker.example.ts b/micro/examples/circuit-breaker.example.ts
new file mode 100644
index 0000000..171a51d
--- /dev/null
+++ b/micro/examples/circuit-breaker.example.ts
@@ -0,0 +1,86 @@
+/**
+ * Circuit Breaker Example
+ *
+ * Demonstrates how to use the CircuitBreaker pattern to protect your
+ * microservice from cascading failures when calling external services.
+ *
+ * Run with: npm run example:circuit-breaker
+ */
+
+import { micro, CircuitBreaker } from "@expressots/adapter-express";
+
+const app = micro();
+
+// Create a circuit breaker for external API calls
+const externalApiBreaker = new CircuitBreaker({
+ // Open circuit after 5 failures
+ failureThreshold: 5,
+ // Try to close circuit after 2 successes in half-open state
+ successThreshold: 2,
+ // Wait 30 seconds before trying to close an open circuit
+ timeout: 30000,
+ // Count failures within 10 second window
+ monitoringPeriod: 10000,
+});
+
+// Simulated external API call (replace with real API)
+async function callExternalApi(): Promise<{ data: string }> {
+ // Simulate random failures for demo
+ if (Math.random() < 0.3) {
+ throw new Error("External API unavailable");
+ }
+ return { data: "Success from external API" };
+}
+
+// Protected endpoint using circuit breaker
+app.get("/api/external", async () => {
+ try {
+ const result = await externalApiBreaker.execute(async () => {
+ return await callExternalApi();
+ });
+ return result;
+ } catch (error) {
+ if (error instanceof Error && error.message === "Circuit breaker is OPEN") {
+ // Service is temporarily unavailable
+ return {
+ error: "Service temporarily unavailable",
+ message: "Please try again later",
+ retryAfter: 30,
+ };
+ }
+ return { error: (error as Error).message };
+ }
+});
+
+// Health check with circuit breaker status
+app.get("/health", () => {
+ const stats = externalApiBreaker.getStats();
+ return {
+ status: "healthy",
+ circuitBreaker: {
+ state: stats.state,
+ failures: stats.failures,
+ successes: stats.successes,
+ totalCalls: stats.totalCalls,
+ lastFailure: stats.lastFailure,
+ lastSuccess: stats.lastSuccess,
+ },
+ };
+});
+
+// Endpoint to manually reset the circuit breaker (for testing)
+app.post("/admin/reset-circuit", () => {
+ externalApiBreaker.reset();
+ return { message: "Circuit breaker reset" };
+});
+
+// Endpoint to manually open the circuit (for maintenance)
+app.post("/admin/open-circuit", () => {
+ externalApiBreaker.open();
+ return { message: "Circuit breaker opened" };
+});
+
+app.listen(3000, {
+ appName: "Circuit Breaker Example",
+ appVersion: "1.0.0",
+});
diff --git a/micro/examples/full-di-api.example.ts b/micro/examples/full-di-api.example.ts
new file mode 100644
index 0000000..34aca85
--- /dev/null
+++ b/micro/examples/full-di-api.example.ts
@@ -0,0 +1,139 @@
+/**
+ * Full DI API Example
+ *
+ * Demonstrates how to upgrade from the simple micro() API to the full
+ * createMicroAPI() with dependency injection container.
+ *
+ * Use this when you need:
+ * - Dependency injection
+ * - Middleware pipeline
+ * - Route management with prefixes
+ * - Provider registration
+ *
+ * Run with: npm run example:full-di-api
+ */
+
+import { createMicroAPI } from "@expressots/adapter-express";
+
+// Create a micro API with DI container
+const microAPI = createMicroAPI();
+
+// Set global route prefix (all routes will be prefixed with /api/v1)
+microAPI.setGlobalRoutePrefix("/api/v1");
+
+// Access the container for dependency injection
+const container = microAPI.Container;
+
+// Register services in the container
+// Example: Register a singleton service
+class UserRepository {
+ private users = [
+ { id: "1", name: "Alice", email: "alice@example.com" },
+ { id: "2", name: "Bob", email: "bob@example.com" },
+ ];
+
+ findAll() {
+ return this.users;
+ }
+
+ findById(id: string) {
+ return this.users.find((u) => u.id === id);
+ }
+
+ create(user: { name: string; email: string }) {
+ const newUser = { id: String(Date.now()), ...user };
+ this.users.push(newUser);
+ return newUser;
+ }
+}
+
+// Register as singleton (same instance throughout app lifecycle)
+container.addSingleton(UserRepository);
+
+// Build the web server
+const app = microAPI.build();
+
+// Configure middleware
+app.Middleware.parse(); // Enable JSON body parsing
+
+// Add custom middleware
+app.Middleware.addMiddleware((req, _res, next) => {
+ console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
+ next();
+});
+
+// Define routes using the Route interface
+// Note: Routes are prefixed with /api/v1
+
+app.Route.get("/", (req, res) => {
+ res.json({
+ message: "Welcome to ExpressoTS Micro API with DI",
+ version: "1.0.0",
+ });
+});
+
+app.Route.get("/users", (req, res) => {
+ // Get the repository from the container
+ const userRepo = container.get(UserRepository);
+ res.json(userRepo.findAll());
+});
+
+app.Route.get("/users/:id", (req, res) => {
+ const userRepo = container.get(UserRepository);
+ const user = userRepo.findById(req.params.id);
+
+ if (!user) {
+ res.status(404).json({ error: "User not found" });
+ return;
+ }
+
+ res.json(user);
+});
+
+app.Route.post("/users", (req, res) => {
+ const userRepo = container.get(UserRepository);
+ const user = userRepo.create(req.body);
+ res.status(201).json(user);
+});
+
+app.Route.get("/health", (req, res) => {
+ res.json({
+ status: "healthy",
+ timestamp: new Date().toISOString(),
+ });
+});
+
+// Set custom error handler
+app.Middleware.setErrorHandler((err, req, res, next) => {
+ console.error("Error:", err);
+ res.status(500).json({
+ error: err.message,
+ path: req.path,
+ });
+});
+
+// Start the server
+app.listen(3000, {
+ appName: "Full DI API Example",
+ appVersion: "1.0.0",
+});
+
+/**
+ * Feature Comparison: micro() vs createMicroAPI()
+ *
+ * | Feature | micro() | createMicroAPI() |
+ * |------------------------|-----------------|------------------|
+ * | Simple routing | โ
| โ
|
+ * | Auto-response | โ
| โ |
+ * | Middleware | โ
(basic) | โ
(pipeline) |
+ * | DI Container | โ | โ
|
+ * | Route prefix | โ
(config) | โ
|
+ * | Provider registration | โ | โ
|
+ * | Middleware presets | โ | โ
|
+ *
+ * When to upgrade:
+ * - Need dependency injection
+ * - Need advanced middleware pipeline
+ * - Need provider registration (singletons, etc.)
+ * - Building a larger microservice
+ */
diff --git a/micro/examples/serverless-lambda.example.ts b/micro/examples/serverless-lambda.example.ts
new file mode 100644
index 0000000..3caeb27
--- /dev/null
+++ b/micro/examples/serverless-lambda.example.ts
@@ -0,0 +1,115 @@
+/**
+ * Serverless Lambda Example
+ *
+ * Demonstrates how to deploy an ExpressoTS Micro API to AWS Lambda.
+ * The same code works locally for development and on Lambda for production.
+ *
+ * Deployment:
+ * 1. Build: npm run build
+ * 2. Package: zip -r function.zip dist/ node_modules/
+ * 3. Deploy to AWS Lambda with API Gateway
+ *
+ * For local development: npm run dev
+ */
+
+import { micro, awsLambdaAdapter } from "@expressots/adapter-express";
+
+// Create the micro API
+const app = micro({
+ showBanner: process.env.AWS_LAMBDA_FUNCTION_NAME ? false : true,
+});
+
+// Define your routes
+app.get("/", () => {
+ return {
+ message: "Hello from ExpressoTS Micro on Lambda!",
+ environment: process.env.AWS_LAMBDA_FUNCTION_NAME ? "lambda" : "local",
+ };
+});
+
+app.get("/users", () => {
+ return {
+ users: [
+ { id: 1, name: "Alice" },
+ { id: 2, name: "Bob" },
+ ],
+ };
+});
+
+app.get("/users/:id", (req) => {
+ return {
+ id: req.params.id,
+ name: `User ${req.params.id}`,
+ requestedAt: new Date().toISOString(),
+ };
+});
+
+app.post("/users", (req) => {
+ return {
+ id: Date.now(),
+ ...req.body,
+ createdAt: new Date().toISOString(),
+ };
+});
+
+app.get("/health", () => {
+ return {
+ status: "healthy",
+ timestamp: new Date().toISOString(),
+ memoryUsage: process.memoryUsage(),
+ lambdaContext: process.env.AWS_LAMBDA_FUNCTION_NAME
+ ? {
+ functionName: process.env.AWS_LAMBDA_FUNCTION_NAME,
+ memoryLimit: process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE,
+ region: process.env.AWS_REGION,
+ }
+ : null,
+ };
+});
+
+// Error handling
+app.setErrorHandler((err, _req, res) => {
+ console.error("Error:", err);
+ res.status(500).json({
+ error: err.message,
+ stack: process.env.NODE_ENV === "development" ? err.stack : undefined,
+ });
+});
+
+// Export for Lambda
+// AWS Lambda will call this handler
+export const handler = awsLambdaAdapter(app.getApp(), {
+ debug: process.env.DEBUG === "true",
+ binaryContentTypes: ["application/octet-stream", "image/*"],
+});
+
+// Local development
+// Only starts the server when running locally (not on Lambda)
+if (!process.env.AWS_LAMBDA_FUNCTION_NAME) {
+ app.listen(3000, {
+ appName: "Lambda Example",
+ appVersion: "1.0.0",
+ });
+}
+
+/**
+ * AWS SAM Template Example (template.yaml):
+ *
+ * AWSTemplateFormatVersion: '2010-09-09'
+ * Transform: AWS::Serverless-2016-10-31
+ *
+ * Resources:
+ * ExpressoTSFunction:
+ * Type: AWS::Serverless::Function
+ * Properties:
+ * Handler: dist/examples/serverless-lambda.example.handler
+ * Runtime: nodejs20.x
+ * MemorySize: 256
+ * Timeout: 30
+ * Events:
+ * Api:
+ * Type: HttpApi
+ * Properties:
+ * Path: /{proxy+}
+ * Method: ANY
+ */
diff --git a/micro/examples/service-client.example.ts b/micro/examples/service-client.example.ts
new file mode 100644
index 0000000..f791af7
--- /dev/null
+++ b/micro/examples/service-client.example.ts
@@ -0,0 +1,175 @@
+/**
+ * Service Client Example
+ *
+ * Demonstrates how to use ServiceClient for service-to-service communication
+ * with automatic retries, timeouts, and circuit breaker integration.
+ *
+ * Run with: npm run example:service-client
+ */
+
+import { micro, ServiceClient } from "@expressots/adapter-express";
+
+const app = micro();
+
+// Create service clients for different microservices
+const userService = new ServiceClient({
+ name: "user-service",
+ baseUrl: "http://localhost:3001",
+ timeout: 5000, // 5 second timeout
+ retries: 3, // Retry failed requests up to 3 times
+ circuitBreaker: {
+ failureThreshold: 5,
+ timeout: 30000,
+ },
+ headers: {
+ "X-Service-Name": "api-gateway",
+ },
+});
+
+const orderService = new ServiceClient({
+ name: "order-service",
+ baseUrl: "http://localhost:4001",
+ timeout: 10000, // Longer timeout for order processing
+ retries: 2,
+ circuitBreaker: true, // Use default circuit breaker config
+});
+
+// Disable circuit breaker for analytics (non-critical)
+const analyticsService = new ServiceClient({
+ name: "analytics-service",
+ baseUrl: "http://localhost:5001",
+ timeout: 3000,
+ retries: 1,
+ circuitBreaker: false,
+});
+
+// Get user by ID
+app.get("/users/:id", async (req) => {
+ try {
+ interface User {
+ id: string;
+ name: string;
+ email: string;
+ }
+ const user = await userService.get(`/api/users/${req.params.id}`);
+ return user;
+ } catch (error) {
+ if ((error as Error).message.includes("Circuit breaker is OPEN")) {
+ return { error: "User service temporarily unavailable" };
+ }
+ return { error: (error as Error).message };
+ }
+});
+
+// Create a new user
+app.post("/users", async (req) => {
+ try {
+ interface User {
+ id: string;
+ name: string;
+ email: string;
+ }
+ const user = await userService.post("/api/users", req.body);
+ return user;
+ } catch (error) {
+ return { error: (error as Error).message };
+ }
+});
+
+// Create an order (calls user and order services)
+app.post("/orders", async (req) => {
+ const { userId, items } = req.body;
+
+ try {
+ // First verify user exists
+ interface User {
+ id: string;
+ name: string;
+ }
+ const user = await userService.get(`/api/users/${userId}`);
+
+ // Then create the order
+ interface Order {
+ id: string;
+ userId: string;
+ items: unknown[];
+ total: number;
+ }
+ const order = await orderService.post("/api/orders", {
+ userId,
+ items,
+ });
+
+ // Fire-and-forget analytics (don't wait, don't fail if it errors)
+ analyticsService
+ .post("/events", {
+ event: "order.created",
+ orderId: order.id,
+ userId,
+ timestamp: new Date().toISOString(),
+ })
+ .catch(() => {
+ // Ignore analytics errors
+ });
+
+ return { order, user };
+ } catch (error) {
+ return { error: (error as Error).message };
+ }
+});
+
+// Get service health and statistics
+app.get("/health", () => {
+ return {
+ status: "healthy",
+ services: {
+ user: userService.getStats(),
+ order: orderService.getStats(),
+ analytics: analyticsService.getStats(),
+ },
+ };
+});
+
+// Demonstrate custom headers per request
+app.get("/users/:id/with-auth", async (req) => {
+ try {
+ interface User {
+ id: string;
+ name: string;
+ }
+ const user = await userService.get(`/api/users/${req.params.id}`, {
+ headers: {
+ Authorization: `Bearer ${req.headers.authorization}`,
+ "X-Request-ID": `req-${Date.now()}`,
+ },
+ });
+ return user;
+ } catch (error) {
+ return { error: (error as Error).message };
+ }
+});
+
+// Demonstrate query parameters
+app.get("/users", async (req) => {
+ try {
+ interface UserList {
+ users: unknown[];
+ total: number;
+ }
+ const result = await userService.call("/api/users", {
+ params: {
+ page: (req.query.page as string) || "1",
+ limit: (req.query.limit as string) || "10",
+ sort: (req.query.sort as string) || "createdAt",
+ },
+ });
+ return result;
+ } catch (error) {
+ return { error: (error as Error).message };
+ }
+});
+
+app.listen(3000, {
+ appName: "Service Client Example",
+ appVersion: "1.0.0",
+});
diff --git a/micro/examples/service-discovery.example.ts b/micro/examples/service-discovery.example.ts
new file mode 100644
index 0000000..7f3e843
--- /dev/null
+++ b/micro/examples/service-discovery.example.ts
@@ -0,0 +1,140 @@
+/**
+ * Service Discovery Example
+ *
+ * Demonstrates how to use ServiceDiscovery for registering and discovering
+ * microservices with round-robin load balancing.
+ *
+ * Run with: npm run example:service-discovery
+ */
+
+import { micro, ServiceDiscovery, ServiceClient } from "@expressots/adapter-express";
+
+const app = micro();
+
+// Create a service discovery instance (static mode for this example)
+const discovery = new ServiceDiscovery({
+ type: "static",
+ debug: true, // Enable logging for demo
+});
+
+// Register some service instances
+// In production, services would self-register on startup
+discovery.registerService({
+ id: "user-service-1",
+ name: "user-service",
+ host: "localhost",
+ port: 3001,
+ health: "healthy",
+ lastCheck: new Date(),
+ metadata: { version: "1.0.0", region: "us-east-1" },
+});
+
+discovery.registerService({
+ id: "user-service-2",
+ name: "user-service",
+ host: "localhost",
+ port: 3002,
+ health: "healthy",
+ lastCheck: new Date(),
+ metadata: { version: "1.0.0", region: "us-west-1" },
+});
+
+discovery.registerService({
+ id: "order-service-1",
+ name: "order-service",
+ host: "localhost",
+ port: 4001,
+ health: "healthy",
+ lastCheck: new Date(),
+});
+
+// Get users - demonstrates round-robin load balancing
+app.get("/users", async () => {
+ const instance = discovery.getService("user-service");
+
+ if (!instance) {
+ return { error: "No healthy user-service instances available" };
+ }
+
+ // Create client for this instance
+ const client = new ServiceClient({
+ name: "user-service",
+ baseUrl: `http://${instance.host}:${instance.port}`,
+ timeout: 5000,
+ });
+
+ try {
+ // In real scenario, make the actual call
+ // const users = await client.get("/api/users");
+ return {
+ message: `Would call user-service at ${instance.host}:${instance.port}`,
+ instance: {
+ id: instance.id,
+ host: instance.host,
+ port: instance.port,
+ },
+ };
+ } catch (error) {
+ // Mark instance as unhealthy on failure
+ discovery.updateHealth(instance.name, instance.id, "unhealthy");
+ return { error: (error as Error).message };
+ }
+});
+
+// List all registered services
+app.get("/services", () => {
+ const serviceNames = discovery.listServices();
+ const services: Record = {};
+
+ for (const name of serviceNames) {
+ services[name] = discovery.getServiceInstances(name, false);
+ }
+
+ return { services };
+});
+
+// Get service statistics
+app.get("/services/stats", () => {
+ return { stats: discovery.getStats() };
+});
+
+// Register a new service instance (for self-registration)
+app.post("/services/register", (req) => {
+ const { id, name, host, port, metadata } = req.body;
+
+ discovery.registerService({
+ id,
+ name,
+ host,
+ port,
+ health: "healthy",
+ lastCheck: new Date(),
+ metadata,
+ });
+
+ return { message: `Registered ${name} (${id})` };
+});
+
+// Deregister a service instance
+app.delete("/services/:name/:id", (req) => {
+ const { name, id } = req.params;
+ discovery.deregisterService(name, id);
+ return { message: `Deregistered ${name} (${id})` };
+});
+
+// Update service health
+app.put("/services/:name/:id/health", (req) => {
+ const { name, id } = req.params;
+ const { health } = req.body;
+
+ const updated = discovery.updateHealth(name, id, health);
+ if (updated) {
+ return { message: `Updated ${name} (${id}) health to ${health}` };
+ }
+ return { error: "Service instance not found" };
+});
+
+app.listen(3000, {
+ appName: "Service Discovery Example",
+ appVersion: "1.0.0",
+});
diff --git a/micro/expressots.config.ts b/micro/expressots.config.ts
index 3dc3853..90360e7 100644
--- a/micro/expressots.config.ts
+++ b/micro/expressots.config.ts
@@ -1,7 +1,7 @@
import { ExpressoConfig, Pattern } from "@expressots/shared";
const config: ExpressoConfig = {
- entryPoint: "api",
+ entryPoint: "src/api",
sourceRoot: "src",
scaffoldPattern: Pattern.KEBAB_CASE,
opinionated: false,
diff --git a/micro/jest.config.ts b/micro/jest.config.ts
index 1910514..251492b 100644
--- a/micro/jest.config.ts
+++ b/micro/jest.config.ts
@@ -1,15 +1,17 @@
-import type { JestConfigWithTsJest } from "ts-jest";
+import type { Config } from "jest";
-const jestConfig: JestConfigWithTsJest = {
+const config: Config = {
preset: "ts-jest",
- rootDir: "./",
testEnvironment: "node",
- verbose: true,
- automock: false,
- testMatch: ["**/*.test.ts", "**/*.spec.ts"],
- coverageDirectory: "./coverage",
- coverageReporters: ["text", "html", "json"],
- modulePathIgnorePatterns: ["/dist/"],
+ rootDir: ".",
+ testMatch: ["/test/**/*.spec.ts"],
+ moduleNameMapper: {
+ "^@app/(.*)$": "/src/$1",
+ },
+ modulePathIgnorePatterns: ["/dist"],
+ collectCoverageFrom: ["src/**/*.ts", "!src/**/*.d.ts", "!src/main.ts"],
+ coverageDirectory: "coverage",
+ coverageReporters: ["text", "lcov"],
};
-export default jestConfig;
+export default config;
diff --git a/micro/package.json b/micro/package.json
index 87b907e..4d8c437 100644
--- a/micro/package.json
+++ b/micro/package.json
@@ -1,41 +1,45 @@
{
- "name": "micro",
+ "name": "expressots-micro",
"version": "1.0.0",
- "description": "",
+ "description": "ExpressoTS Microservice - Lightweight API with Circuit Breaker, Service Discovery, and Serverless support",
"author": "",
- "private": true,
- "license": "UNLICENSED",
+ "license": "MIT",
+ "main": "dist/src/api.js",
"scripts": {
"build": "expressots build",
"dev": "expressots dev",
"prod": "expressots prod",
+ "format": "prettier --write \"src/**/*.ts\"",
+ "lint": "eslint \"src/**/*.ts\" --fix",
"test": "jest",
- "test:watch": "jest --watchAll",
- "test:cov": "jest --coverage",
- "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
- "lint": "eslint \"src/**/*.ts\" --fix"
+ "test:watch": "jest --watch",
+ "test:coverage": "jest --coverage",
+ "example:circuit-breaker": "tsx examples/circuit-breaker.example.ts",
+ "example:service-discovery": "tsx examples/service-discovery.example.ts",
+ "example:service-client": "tsx examples/service-client.example.ts",
+ "example:full-di-api": "tsx examples/full-di-api.example.ts"
},
- "keywords": [],
"dependencies": {
- "@expressots/adapter-express": "3.0.0",
- "@expressots/core": "3.0.0",
- "@expressots/shared": "3.0.0"
+ "@expressots/adapter-express": "file:../adapter-express/expressots-adapter-express-4.0.0-beta.1.tgz",
+ "@expressots/core": "file:../expressots/expressots-core-4.0.0-beta.1.tgz",
+ "@expressots/shared": "file:../shared/expressots-shared-4.0.0-beta.1.tgz",
+ "express": "5.2.1"
},
"devDependencies": {
- "@expressots/cli": "3.0.0",
- "@types/express": "5.0.0",
- "@types/jest": "29.5.14",
- "@types/node": "20.12.7",
- "@typescript-eslint/eslint-plugin": "8.0.0",
- "@typescript-eslint/parser": "8.0.0",
- "eslint": "8.57.0",
- "eslint-config-prettier": "9.0.0",
- "eslint-plugin-prettier": "5.0.0",
- "jest": "29.7.0",
- "prettier": "3.2.5",
- "supertest": "^7.0.0",
- "ts-jest": "29.1.2",
- "tsx": "4.19.2",
- "typescript": "5.1.3"
+ "@eslint/js": "9.39.2",
+ "@expressots/cli": "file:../expressots-cli/expressots-cli-4.0.0-beta.1.tgz",
+ "@types/express": "5.0.6",
+ "@types/jest": "30.0.0",
+ "@types/node": "25.0.3",
+ "@typescript-eslint/eslint-plugin": "8.51.0",
+ "@typescript-eslint/parser": "8.51.0",
+ "eslint": "9.39.2",
+ "jest": "30.2.0",
+ "nodemon": "3.1.11",
+ "prettier": "3.7.4",
+ "ts-jest": "29.4.6",
+ "tsx": "4.21.0",
+ "typescript": "5.9.3",
+ "typescript-eslint": "^8.53.0"
}
}
diff --git a/micro/src/api.ts b/micro/src/api.ts
index 57f6655..5f492ca 100644
--- a/micro/src/api.ts
+++ b/micro/src/api.ts
@@ -1,12 +1,9 @@
-import { createMicroAPI } from "@expressots/adapter-express";
-import { Request, Response } from "express";
+import { micro } from "@expressots/adapter-express";
-const microAPI = createMicroAPI();
+const app = micro();
-const app = microAPI.build();
-
-app.Route.get("/", (req: Request, res: Response) => {
- res.send("Hello from ExpressoTS Micro API!");
+app.get("/", () => {
+ return "Hello from ExpressoTS Micro API!";
});
app.listen(3000);
diff --git a/micro/test/api.spec.ts b/micro/test/api.spec.ts
index 81e938e..9c77e11 100644
--- a/micro/test/api.spec.ts
+++ b/micro/test/api.spec.ts
@@ -1,26 +1,29 @@
-import { createMicroAPI } from "@expressots/adapter-express";
-import { Server } from "http";
-import request from "supertest";
+import { micro, MicroApp } from "@expressots/adapter-express";
+import { AddressInfo } from "net";
-describe("MicroAPI Root Route", () => {
- let httpServer: Server;
+describe("Micro API", () => {
+ let api: MicroApp;
+ let baseUrl: string;
- beforeAll(() => {
- const microAPI = createMicroAPI();
- const app = microAPI.build();
- app.listen(0);
+ beforeAll(async () => {
+ api = micro({ showBanner: false });
+ api.get("/", () => "Hello from ExpressoTS Micro API!");
+ await api.listen(0);
- httpServer = microAPI.getHttpServer();
+ const { port } = api.getHttpServer().address() as AddressInfo;
+ baseUrl = `http://localhost:${port}`;
});
- afterAll(() => {
- httpServer.close();
+ afterAll(async () => {
+ await new Promise((resolve) =>
+ api.getHttpServer().close(() => resolve()),
+ );
});
- it("should return Hello from ExpressoTS!", () => {
- request(httpServer)
- .get("/")
- .expect(200)
- .expect("Hello from ExpressoTS!");
+ it("should return hello message on GET /", async () => {
+ const response = await fetch(`${baseUrl}/`);
+
+ expect(response.status).toBe(200);
+ expect(await response.text()).toBe("Hello from ExpressoTS Micro API!");
});
});
diff --git a/micro/tsconfig.build.json b/micro/tsconfig.build.json
index 4764b76..3579133 100644
--- a/micro/tsconfig.build.json
+++ b/micro/tsconfig.build.json
@@ -1,22 +1,18 @@
{
+ "extends": "./tsconfig.json",
"compilerOptions": {
- "target": "ES2021",
- "module": "commonjs",
"outDir": "./dist",
- "rootDir": "./src",
- "strict": true,
- "esModuleInterop": true,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true,
- "moduleResolution": "node",
- "resolveJsonModule": true,
+ "rootDir": "./",
+ "declaration": false,
+ "declarationMap": false,
+ "sourceMap": false,
"removeComments": true,
- "noImplicitAny": false,
- "strictPropertyInitialization": false,
- "types": ["reflect-metadata", "node", "jest"],
- "experimentalDecorators": true,
- "emitDecoratorMetadata": true
+ "incremental": true,
+ "tsBuildInfoFile": "./dist/.tsbuildinfo",
+ "isolatedModules": true,
+ "types": ["node"],
+ "baseUrl": "."
},
"include": ["src/**/*.ts"],
- "exclude": ["node_modules", "dist", "test/**/*"]
+ "exclude": ["node_modules", "dist", "test"]
}
diff --git a/micro/tsconfig.json b/micro/tsconfig.json
index 6ba3401..99d10f7 100644
--- a/micro/tsconfig.json
+++ b/micro/tsconfig.json
@@ -1,23 +1,46 @@
{
"compilerOptions": {
+ // Language and Environment
+ "target": "ES2021",
+ "lib": ["ES2021"],
+
+ // Modules
"module": "commonjs",
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+
+ // Emit
+ "outDir": "./dist",
+ "rootDir": "./",
"declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
"removeComments": true,
+
+ // ExpressoTS Required: Decorators and Metadata
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
- "allowSyntheticDefaultImports": true,
- "resolveJsonModule": true,
- "target": "ES2021",
- "sourceMap": true,
- "rootDir": "./src",
- "esModuleInterop": true,
- "forceConsistentCasingInFileNames": true,
+
+ // Path Mapping
+ "baseUrl": "./src",
+
+ // Type Checking
"strict": true,
"noImplicitAny": false,
"strictPropertyInitialization": false,
"skipLibCheck": true,
- "types": ["reflect-metadata", "node", "jest"]
+
+ // Performance
+ "incremental": true,
+ "tsBuildInfoFile": "./dist/.tsbuildinfo",
+
+ // Interop Constraints
+ "forceConsistentCasingInFileNames": true,
+
+ // Type Definitions
+ "types": ["node", "jest"]
},
- "include": ["src/**/*.ts"],
- "exclude": ["node_modules", "dist", "test/**/*"]
+ "include": ["src/**/*.ts", "test/**/*.ts", "expressots.config.ts"],
+ "exclude": ["node_modules", "dist"]
}
diff --git a/non_opinionated/.eslintrc.js b/non_opinionated/.eslintrc.js
deleted file mode 100644
index 9340aff..0000000
--- a/non_opinionated/.eslintrc.js
+++ /dev/null
@@ -1,29 +0,0 @@
-module.exports = {
- parser: "@typescript-eslint/parser",
- plugins: ["@typescript-eslint/eslint-plugin"],
- extends: [
- "plugin:@typescript-eslint/recommended",
- "plugin:prettier/recommended",
- ],
- root: true,
- env: {
- node: true,
- jest: true,
- },
- ignorePatterns: [".eslintrc.js"],
- rules: {
- "@typescript-eslint/interface-name-prefix": "off",
- "@typescript-eslint/explicit-function-return-type": "off",
- "@typescript-eslint/explicit-module-boundary-types": "off",
- "@typescript-eslint/no-inferrable-types": "off",
- "@typescript-eslint/no-explicit-any": "off",
- "@typescript-eslint/no-empty-function": "off",
- "@typescript-eslint/no-empty-interface": "off",
- "@typescript-eslint/no-unused-vars": "off",
- "no-trailing-spaces": ["error", { skipBlankLines: true }],
- "no-multi-spaces": ["error", { ignoreEOLComments: true }],
- "no-multi-spaces": "off",
- "prettier/prettier": ["error", { endOfLine: "auto" }, { tabWidth: 4 }],
- "prettier/prettier": "off",
- },
-};
diff --git a/non_opinionated/.gitignore b/non_opinionated/.gitignore
deleted file mode 100644
index 94709eb..0000000
--- a/non_opinionated/.gitignore
+++ /dev/null
@@ -1,36 +0,0 @@
-# compiled output
-/dist
-/node_modules
-.env
-
-# Logs
-logs
-*.log
-npm-debug.log*
-pnpm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-lerna-debug.log*
-
-# OS
-.DS_Store
-
-# Tests
-/coverage
-/.nyc_output
-
-# IDEs and editors
-/.idea
-.project
-.classpath
-.c9/
-*.launch
-.settings/
-*.sublime-workspace
-
-# IDE - VSCode
-.vscode/*
-!.vscode/settings.json
-!.vscode/tasks.json
-!.vscode/launch.json
-!.vscode/extensions.json
\ No newline at end of file
diff --git a/non_opinionated/.prettierrc b/non_opinionated/.prettierrc
deleted file mode 100644
index d7708b4..0000000
--- a/non_opinionated/.prettierrc
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "singleQuote": false,
- "trailingComma": "all",
- "endOfLine": "auto",
- "tabWidth": 4
-}
\ No newline at end of file
diff --git a/non_opinionated/README.md b/non_opinionated/README.md
deleted file mode 100644
index c09d790..0000000
--- a/non_opinionated/README.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# Expresso TS
-
-A Typescript + [Node.js]("https://nodejs.org/en/") lightweight framework for quick building scalable, easy to read and maintain, server-side applications ๐
-
-## Philosophy
-
-ExpressoTS is a TypeScript lightweight framework for building scalable, readable and maintainable server-side applications. The framework provides a level of abstraction on top of common HTTP server framework Expressjs exposing their API's directly to the developer. This provides freedom and brings to the developer a tool that is well known and easy to use.
-
-## How to use
-
-### Executing in development mode
-
-```bash
-npm run dev
-```
-
-### Generating production build
-
-```bash
-npm run build
-```
-
-### Executing in production mode
-
-```bash
-npm run prod
-```
-
-## Test
-
-How to run test scripts
-
-### Unit tests
-
-```bash
-npm run test
-```
-
-### Test coverage
-
-```bash
-npm run test:cov
-```
-
-## Documentation
-
-- Here is our [Official Documentation](https://expresso-ts.com/)
-- Checkout our [First Steps documentation](https://expresso-ts.com/docs/overview/first-steps)
-- Our [CLI Documentation](https://expresso-ts.com/docs/category/cli)
-
-## Questions
-
-For questions and support please use the Official [Discord Channel](https://discord.com/invite/PyPJfGK). We have a very active community there, that will be happy to help you. Post your questions in the channel called **HELP EXPRESSO TS** and forum called **help**.
-
-## Issues
-
-The [Issue Reporting Channel](https://github.com/expressots/expressots/issues) is for bug report and feature request **only**.
-
-Before you create an issue, please make sure you read the [Contribution Guidelines](CONTRIBUTING.md).
-
-## Support the project
-
-Expresso TS is an MIT-licensed open source project. It's an independent project with ongoing development made possible thanks to your support. If you'd like to help, please consider:
-
-- Become a sponsor on **[Sponsor no GitHub](https://github.com/sponsors/expressots)**
-- Follow the **[organization](https://github.com/expressots)** on GitHub and Star โญ the project
-- Subscribe to the Twitch channel: **[Richard Zampieri](https://www.twitch.tv/richardzampieri)**
-- Join our **[Discord](https://discord.com/invite/PyPJfGK)**
-- Contribute submitting **[issues and pull requests](https://github.com/expressots/expressots/issues/new/choose)**
-- Share the project with your friends and colleagues
-
-## License
-
-ExpressoTS is **[MIT licensed](LICENSE.md)**
\ No newline at end of file
diff --git a/non_opinionated/expressots.config.ts b/non_opinionated/expressots.config.ts
deleted file mode 100644
index cc58e55..0000000
--- a/non_opinionated/expressots.config.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { ExpressoConfig, Pattern } from "@expressots/shared";
-
-const config: ExpressoConfig = {
- entryPoint: "main",
- sourceRoot: "src",
- scaffoldPattern: Pattern.KEBAB_CASE,
- opinionated: false
-};
-
-export default config;
\ No newline at end of file
diff --git a/non_opinionated/jest.config.ts b/non_opinionated/jest.config.ts
deleted file mode 100644
index cebb7e5..0000000
--- a/non_opinionated/jest.config.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import type { JestConfigWithTsJest } from "ts-jest";
-
-const jestConfig: JestConfigWithTsJest = {
- preset: "ts-jest",
- rootDir: "./",
- testEnvironment: "node",
- verbose: true,
- automock: false,
- testMatch: ["**/*.test.ts", "**/*.spec.ts"],
- coverageDirectory: "./coverage",
- coverageReporters: ["text", "html", "json"],
-};
-
-export default jestConfig;
diff --git a/non_opinionated/package.json b/non_opinionated/package.json
deleted file mode 100644
index c9eedda..0000000
--- a/non_opinionated/package.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "name": "nopinionated",
- "version": "1.0.0",
- "description": "",
- "author": "",
- "private": true,
- "license": "UNLICENSED",
- "scripts": {
- "build": "expressots build",
- "dev": "expressots dev",
- "prod": "expressots prod",
- "test": "jest",
- "test:watch": "jest --watchAll",
- "test:cov": "jest --coverage",
- "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
- "lint": "eslint \"src/**/*.ts\" --fix"
- },
- "keywords": [],
- "dependencies": {
- "@expressots/adapter-express": "3.0.0",
- "@expressots/core": "3.0.0",
- "@expressots/shared": "3.0.0"
- },
- "devDependencies": {
- "@expressots/cli": "3.0.0",
- "@types/express": "5.0.0",
- "@types/jest": "29.5.14",
- "@types/node": "20.12.7",
- "@typescript-eslint/eslint-plugin": "8.0.0",
- "@typescript-eslint/parser": "8.0.0",
- "eslint": "8.57.0",
- "eslint-config-prettier": "9.0.0",
- "eslint-plugin-prettier": "5.0.0",
- "jest": "29.7.0",
- "prettier": "3.2.5",
- "supertest": "^7.0.0",
- "ts-jest": "29.1.2",
- "tsx": "4.19.2",
- "typescript": "5.1.3"
- }
-}
diff --git a/non_opinionated/src/main.ts b/non_opinionated/src/main.ts
deleted file mode 100644
index 11413b3..0000000
--- a/non_opinionated/src/main.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { AppFactory } from "@expressots/core";
-import { App } from "./app";
-
-AppFactory.create(App).then((app) => app.listen(3000));
\ No newline at end of file
diff --git a/non_opinionated/test/app.controller.spec.ts b/non_opinionated/test/app.controller.spec.ts
deleted file mode 100644
index 3c43fc3..0000000
--- a/non_opinionated/test/app.controller.spec.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import request from "supertest";
-import { Server } from "http";
-
-import { AppFactory, StatusCode } from '@expressots/core';
-import { IWebServerBuilder } from '@expressots/shared';
-import { App } from "../src/app";
-
-
-describe("AppController", () => {
- let server: Server;
- let webServerBuilder: IWebServerBuilder
-
- beforeAll(async () => {
- webServerBuilder = await AppFactory.create(App);
- const app = await webServerBuilder.listen(3000);
- server = await app.getHttpServer();
- });
-
- afterAll(async () => {
- await server.close();
- });
-
- it("returns Hello Expresso TS!", async () => {
- return request(server)
- .get("/")
- .expect(StatusCode.OK)
- .expect("Hello from ExpressoTS!");
- });
-});
diff --git a/non_opinionated/tsconfig.build.json b/non_opinionated/tsconfig.build.json
deleted file mode 100644
index 6f440dc..0000000
--- a/non_opinionated/tsconfig.build.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES2021",
- "module": "commonjs",
- "outDir": "./dist",
- "rootDir": "./src",
- "strict": true,
- "esModuleInterop": true,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true,
- "moduleResolution": "node",
- "resolveJsonModule": true,
- "removeComments": true,
- "noImplicitAny": false,
- "strictPropertyInitialization": false,
- "types": ["node", "jest"],
- "experimentalDecorators": true,
- "emitDecoratorMetadata": true
- },
- "include": ["src/**/*.ts"],
- "exclude": ["node_modules", "dist", "test/**/*"]
-}
diff --git a/non_opinionated/tsconfig.json b/non_opinionated/tsconfig.json
deleted file mode 100644
index 981d0b7..0000000
--- a/non_opinionated/tsconfig.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "compilerOptions": {
- "module": "commonjs",
- "target": "ES2021",
- "declaration": true,
- "removeComments": true,
- "experimentalDecorators": true,
- "emitDecoratorMetadata": true,
- "resolveJsonModule": true,
- "sourceMap": true,
- "rootDir": "./src",
- "esModuleInterop": true,
- "forceConsistentCasingInFileNames": true,
- "strict": true,
- "noImplicitAny": false,
- "strictPropertyInitialization": false,
- "skipLibCheck": true,
- "types": ["node", "jest"]
- },
- "include": ["src/**/*.ts"],
- "exclude": ["node_modules", "dist", "test/**/*"]
-}
diff --git a/opinionated/.env.development b/opinionated/.env.development
deleted file mode 100644
index ea93d3e..0000000
--- a/opinionated/.env.development
+++ /dev/null
@@ -1,2 +0,0 @@
-# This file is used to set environment variables for development environment
-PORT=3000
\ No newline at end of file
diff --git a/opinionated/.env.production b/opinionated/.env.production
deleted file mode 100644
index 71733c8..0000000
--- a/opinionated/.env.production
+++ /dev/null
@@ -1,2 +0,0 @@
-# This file is used to set environment variables for production environment
-PORT=4000
\ No newline at end of file
diff --git a/opinionated/.eslintrc.js b/opinionated/.eslintrc.js
deleted file mode 100644
index f335b8d..0000000
--- a/opinionated/.eslintrc.js
+++ /dev/null
@@ -1,28 +0,0 @@
-module.exports = {
- parser: "@typescript-eslint/parser",
- plugins: ["@typescript-eslint/eslint-plugin"],
- extends: [
- "plugin:@typescript-eslint/recommended",
- "plugin:prettier/recommended",
- ],
- root: true,
- env: {
- node: true,
- jest: true,
- },
- ignorePatterns: [".eslintrc.js"],
- rules: {
- "@typescript-eslint/interface-name-prefix": "off",
- "@typescript-eslint/explicit-function-return-type": "off",
- "@typescript-eslint/explicit-module-boundary-types": "off",
- "@typescript-eslint/no-inferrable-types": "off",
- "@typescript-eslint/no-explicit-any": "off",
- "@typescript-eslint/no-empty-function": "off",
- "@typescript-eslint/no-empty-interface": "off",
- "@typescript-eslint/no-unused-vars": "off",
- "no-trailing-spaces": ["error", { skipBlankLines: true }],
- "no-multi-spaces": ["error", { ignoreEOLComments: true }],
- "no-multi-spaces": "off",
- "prettier/prettier": "off",
- },
-};
diff --git a/opinionated/.gitignore b/opinionated/.gitignore
deleted file mode 100644
index 94709eb..0000000
--- a/opinionated/.gitignore
+++ /dev/null
@@ -1,36 +0,0 @@
-# compiled output
-/dist
-/node_modules
-.env
-
-# Logs
-logs
-*.log
-npm-debug.log*
-pnpm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-lerna-debug.log*
-
-# OS
-.DS_Store
-
-# Tests
-/coverage
-/.nyc_output
-
-# IDEs and editors
-/.idea
-.project
-.classpath
-.c9/
-*.launch
-.settings/
-*.sublime-workspace
-
-# IDE - VSCode
-.vscode/*
-!.vscode/settings.json
-!.vscode/tasks.json
-!.vscode/launch.json
-!.vscode/extensions.json
\ No newline at end of file
diff --git a/opinionated/.prettierrc b/opinionated/.prettierrc
deleted file mode 100644
index d7708b4..0000000
--- a/opinionated/.prettierrc
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "singleQuote": false,
- "trailingComma": "all",
- "endOfLine": "auto",
- "tabWidth": 4
-}
\ No newline at end of file
diff --git a/opinionated/README.md b/opinionated/README.md
deleted file mode 100644
index c09d790..0000000
--- a/opinionated/README.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# Expresso TS
-
-A Typescript + [Node.js]("https://nodejs.org/en/") lightweight framework for quick building scalable, easy to read and maintain, server-side applications ๐
-
-## Philosophy
-
-ExpressoTS is a TypeScript lightweight framework for building scalable, readable and maintainable server-side applications. The framework provides a level of abstraction on top of common HTTP server framework Expressjs exposing their API's directly to the developer. This provides freedom and brings to the developer a tool that is well known and easy to use.
-
-## How to use
-
-### Executing in development mode
-
-```bash
-npm run dev
-```
-
-### Generating production build
-
-```bash
-npm run build
-```
-
-### Executing in production mode
-
-```bash
-npm run prod
-```
-
-## Test
-
-How to run test scripts
-
-### Unit tests
-
-```bash
-npm run test
-```
-
-### Test coverage
-
-```bash
-npm run test:cov
-```
-
-## Documentation
-
-- Here is our [Official Documentation](https://expresso-ts.com/)
-- Checkout our [First Steps documentation](https://expresso-ts.com/docs/overview/first-steps)
-- Our [CLI Documentation](https://expresso-ts.com/docs/category/cli)
-
-## Questions
-
-For questions and support please use the Official [Discord Channel](https://discord.com/invite/PyPJfGK). We have a very active community there, that will be happy to help you. Post your questions in the channel called **HELP EXPRESSO TS** and forum called **help**.
-
-## Issues
-
-The [Issue Reporting Channel](https://github.com/expressots/expressots/issues) is for bug report and feature request **only**.
-
-Before you create an issue, please make sure you read the [Contribution Guidelines](CONTRIBUTING.md).
-
-## Support the project
-
-Expresso TS is an MIT-licensed open source project. It's an independent project with ongoing development made possible thanks to your support. If you'd like to help, please consider:
-
-- Become a sponsor on **[Sponsor no GitHub](https://github.com/sponsors/expressots)**
-- Follow the **[organization](https://github.com/expressots)** on GitHub and Star โญ the project
-- Subscribe to the Twitch channel: **[Richard Zampieri](https://www.twitch.tv/richardzampieri)**
-- Join our **[Discord](https://discord.com/invite/PyPJfGK)**
-- Contribute submitting **[issues and pull requests](https://github.com/expressots/expressots/issues/new/choose)**
-- Share the project with your friends and colleagues
-
-## License
-
-ExpressoTS is **[MIT licensed](LICENSE.md)**
\ No newline at end of file
diff --git a/opinionated/jest.config.ts b/opinionated/jest.config.ts
deleted file mode 100644
index bac9448..0000000
--- a/opinionated/jest.config.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import type { JestConfigWithTsJest } from "ts-jest";
-
-const jestConfig: JestConfigWithTsJest = {
- preset: "ts-jest",
- rootDir: "./",
- testEnvironment: "node",
- verbose: true,
- automock: false,
- testMatch: ["**/*.test.ts", "**/*.spec.ts"],
- coverageDirectory: "./coverage",
- coverageReporters: ["text", "html", "json"],
- moduleNameMapper: {
- "^@entities/(.*)$": "/src/entities/$1",
- "^@providers/(.*)$": "/src/providers/$1",
- "^@repositories/(.*)$": "/src/repositories/$1",
- "^@useCases/(.*)$": "/src/useCases/$1",
- },
- modulePathIgnorePatterns: ["/dist/"],
-};
-
-export default jestConfig;
diff --git a/opinionated/package.json b/opinionated/package.json
deleted file mode 100644
index e21afa9..0000000
--- a/opinionated/package.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "name": "opinionated",
- "version": "1.0.0",
- "description": "",
- "author": "",
- "private": true,
- "license": "UNLICENSED",
- "scripts": {
- "build": "expressots build",
- "dev": "expressots dev",
- "prod": "expressots prod",
- "test": "jest",
- "test:watch": "jest --watchAll",
- "test:cov": "jest --coverage",
- "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
- "lint": "eslint \"src/**/*.ts\" --fix"
- },
- "keywords": [],
- "dependencies": {
- "@expressots/adapter-express": "3.0.0",
- "@expressots/core": "3.0.0",
- "@expressots/shared": "3.0.0"
- },
- "devDependencies": {
- "@expressots/cli": "3.0.0",
- "@types/express": "5.0.0",
- "@types/jest": "29.5.14",
- "@types/node": "20.12.7",
- "@typescript-eslint/eslint-plugin": "8.0.0",
- "@typescript-eslint/parser": "8.0.0",
- "eslint": "8.57.0",
- "eslint-config-prettier": "9.0.0",
- "eslint-plugin-prettier": "5.0.0",
- "jest": "29.7.0",
- "prettier": "3.2.5",
- "supertest": "^7.0.0",
- "ts-jest": "29.1.2",
- "tsconfig-paths": "4.2.0",
- "tsx": "4.19.2",
- "typescript": "5.1.3"
- }
-}
diff --git a/opinionated/register-path.js b/opinionated/register-path.js
deleted file mode 100644
index 116ebb7..0000000
--- a/opinionated/register-path.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/* eslint-disable @typescript-eslint/no-var-requires */
-
-const path = require("path");
-const tsconfigPaths = require("tsconfig-paths");
-const tsconfig = require("./tsconfig.build.json");
-
-const baseUrl = tsconfig.compilerOptions.baseUrl || ".";
-const outDir = tsconfig.compilerOptions.outDir || ".";
-
-let baseUrlPath = path.resolve(outDir, baseUrl);
-
-const explicitPaths = {
- baseUrl: baseUrlPath,
- paths: tsconfig.compilerOptions.paths,
-};
-
-tsconfigPaths.register(explicitPaths);
diff --git a/opinionated/src/app.ts b/opinionated/src/app.ts
deleted file mode 100644
index 343b6e8..0000000
--- a/opinionated/src/app.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { AppExpress } from "@expressots/adapter-express";
-import { AppContainer, Env } from "@expressots/core";
-import { AppModule } from "@useCases/app/app.module";
-
-export class App extends AppExpress {
- private config: AppContainer = this.configContainer([AppModule]);
-
- async globalConfiguration(): Promise {
- this.setGlobalRoutePrefix("/v1");
-
- this.initEnvironment("development", {
- env: {
- development: ".env.development",
- production: ".env.production",
- },
- });
- }
-
- async configureServices(): Promise {
- this.Provider.register(Env);
-
- this.Middleware.addBodyParser();
- this.Middleware.setErrorHandler({ showStackTrace: true });
- }
-
- async postServerInitialization(): Promise {
- if (await this.isDevelopment()) {
- this.Provider.get(Env).checkFile(".env.development");
- }
- }
-
- async serverShutdown(): Promise {}
-}
diff --git a/opinionated/src/env.ts b/opinionated/src/env.ts
deleted file mode 100644
index a2d2d25..0000000
--- a/opinionated/src/env.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import pkg from "../package.json";
-
-export const env = {
- App: {
- appName: pkg.name,
- appVersion: pkg.version,
- get Port() {
- return process.env.PORT || 3000;
- }
- },
-};
\ No newline at end of file
diff --git a/opinionated/src/main.ts b/opinionated/src/main.ts
deleted file mode 100644
index 693468f..0000000
--- a/opinionated/src/main.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { AppFactory } from "@expressots/core";
-import { App } from "app";
-import { env } from "env";
-
-AppFactory.create(App).then((app) =>
- app.listen(env.App.Port, {
- appName: env.App.appName,
- appVersion: env.App.appVersion,
- }),
-);
diff --git a/opinionated/src/useCases/app/app.controller.ts b/opinionated/src/useCases/app/app.controller.ts
deleted file mode 100644
index dab0c36..0000000
--- a/opinionated/src/useCases/app/app.controller.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { controller, Get } from "@expressots/adapter-express";
-import { inject } from "@expressots/core";
-import { AppUseCase } from "./app.usecase";
-
-@controller("/")
-export class AppController {
- @inject(AppUseCase) private appUseCase: AppUseCase;
-
- @Get("/")
- execute() {
- return this.appUseCase.execute();
- }
-}
diff --git a/opinionated/src/useCases/app/app.module.ts b/opinionated/src/useCases/app/app.module.ts
deleted file mode 100644
index e148a06..0000000
--- a/opinionated/src/useCases/app/app.module.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { ContainerModule, CreateModule } from "@expressots/core";
-import { AppController } from "./app.controller";
-
-export const AppModule: ContainerModule = CreateModule([AppController]);
\ No newline at end of file
diff --git a/opinionated/src/useCases/app/app.usecase.ts b/opinionated/src/useCases/app/app.usecase.ts
deleted file mode 100644
index c491abb..0000000
--- a/opinionated/src/useCases/app/app.usecase.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { provide } from "@expressots/core";
-
-@provide(AppUseCase)
-export class AppUseCase {
- execute() {
- return "Hello from ExpressoTS!";
- }
-}
diff --git a/opinionated/test/app.controller.spec.ts b/opinionated/test/app.controller.spec.ts
deleted file mode 100644
index 41f829e..0000000
--- a/opinionated/test/app.controller.spec.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import request from "supertest";
-
-import { AppFactory, StatusCode } from "@expressots/core";
-import { IWebServerBuilder } from "@expressots/shared";
-
-import { Server } from "http";
-import { App } from "../src/app";
-
-describe("AppController", () => {
- let server: Server;
- let webServerBuilder: IWebServerBuilder;
-
- beforeAll(async () => {
- webServerBuilder = await AppFactory.create(App);
- const app = await webServerBuilder.listen(3000);
- server = await app.getHttpServer();
- });
-
- afterAll(async () => {
- await server.close();
- });
-
- it("returns a valid AppResponse", async () => {
- return request(server)
- .get("/v1")
- .expect(StatusCode.OK)
- .expect("Hello from ExpressoTS!");
- });
-});
diff --git a/opinionated/tsconfig.build.json b/opinionated/tsconfig.build.json
deleted file mode 100644
index bed4d89..0000000
--- a/opinionated/tsconfig.build.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES2021",
- "module": "commonjs",
- "declaration": false,
- "sourceMap": false,
- "removeComments": true,
- "experimentalDecorators": true,
- "emitDecoratorMetadata": true,
- "resolveJsonModule": true,
- "outDir": "./dist",
- "rootDir": "./",
- "baseUrl": "./src",
- "paths": {
- "@entities/*": ["entities/*"],
- "@providers/*": ["providers/*"],
- "@repositories/*": ["repositories/*"],
- "@useCases/*": ["useCases/*"]
- },
- "esModuleInterop": true,
- "forceConsistentCasingInFileNames": true,
- "strict": true,
- "allowJs": true,
- "noImplicitAny": false,
- "strictPropertyInitialization": false,
- "skipLibCheck": true,
- "types": ["node", "jest"]
- },
- "include": ["src/**/*.ts"],
- "exclude": ["node_modules", "dist", "test"]
-}
diff --git a/opinionated/tsconfig.json b/opinionated/tsconfig.json
deleted file mode 100644
index 6e94d5e..0000000
--- a/opinionated/tsconfig.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES2021",
- "module": "commonjs",
- "lib": ["es2021"],
- "declaration": false,
- "removeComments": true,
- "experimentalDecorators": true,
- "emitDecoratorMetadata": true,
- "resolveJsonModule": true,
- "sourceMap": false,
- "outDir": "./dist",
- "rootDir": "./",
- "baseUrl": "./src",
- "paths": {
- "@entities/*": ["entities/*"],
- "@providers/*": ["providers/*"],
- "@repositories/*": ["repositories/*"],
- "@useCases/*": ["useCases/*"]
- },
- "esModuleInterop": true,
- "forceConsistentCasingInFileNames": true,
- "strict": true,
- "allowJs": true,
- "noImplicitAny": false,
- "strictPropertyInitialization": false,
- "skipLibCheck": true,
- "types": ["node", "jest"]
- },
- "include": ["src/**/*.ts"],
- "exclude": ["node_modules", "dist", "test/**/*.ts"]
-}
diff --git a/package.json b/package.json
index 1f03d1d..f07964b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@expressots/templates",
- "version": "3.0.0",
+ "version": "4.0.0-beta.1",
"description": "Expressots templates",
"author": "Richard Zampieri",
"license": "MIT",
diff --git a/provider/package.json b/provider/package.json
index 14f8b22..d59cf0d 100644
--- a/provider/package.json
+++ b/provider/package.json
@@ -64,7 +64,7 @@
"lint:fix": "eslint \"src/**/*.ts\" --fix"
},
"dependencies": {
- "@expressots/core": "3.0.0"
+ "@expressots/core": "^4.0.0"
},
"devDependencies": {
"@commitlint/cli": "19.5.0",