https://github.com/expressive-tea/expresive-tea
A Simple, Clean, Flexible and Modulable web framework project, based on Express and Typescript
https://github.com/expressive-tea/expresive-tea
dependency-injection descriptive-decorators expressjs middlewares rest-api restful-api typescript
Last synced: about 1 month ago
JSON representation
A Simple, Clean, Flexible and Modulable web framework project, based on Express and Typescript
- Host: GitHub
- URL: https://github.com/expressive-tea/expresive-tea
- Owner: Expressive-Tea
- License: apache-2.0
- Created: 2019-02-27T01:23:21.000Z (about 7 years ago)
- Default Branch: develop
- Last Pushed: 2024-04-25T05:06:21.000Z (almost 2 years ago)
- Last Synced: 2024-04-26T04:32:04.344Z (almost 2 years ago)
- Topics: dependency-injection, descriptive-decorators, expressjs, middlewares, rest-api, restful-api, typescript
- Language: TypeScript
- Homepage: https://expressive-tea.io
- Size: 2.22 MB
- Stars: 94
- Watchers: 4
- Forks: 9
- Open Issues: 8
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
Awesome Lists containing this project
README
Expressive Tea
A modern, TypeScript-first framework for building scalable Node.js applications
Clean architecture β’ Dependency Injection β’ Decorator-driven β’ Express-powered
π Documentation
Β·
π Live Demo
Β·
π Report Bug
Β·
π‘ Request Feature
---
> [!IMPORTANT]
> ### π¦ Package Renamed: `@expressive-tea/core`
>
> **Expressive Tea has a new home on npm!** Starting with v2.0.0, install using:
>
> ```bash
> npm install @expressive-tea/core
> ```
>
> **Legacy package `@zerooneit/expressive-tea` will be maintained until April 30, 2026** for security patches only. Please migrate to `@expressive-tea/core` as soon as possible.
>
> **Why the change?**
> - β¨ Better namespace organization (`@expressive-tea/*`)
> - π Community-focused ownership
> - π Clearer project identity
>
> **Migration is simple:** Just update your `package.json` and imports remain the same!
> ```diff
> - "dependencies": { "@zerooneit/expressive-tea": "^1.2.0" }
> + "dependencies": { "@expressive-tea/core": "^2.0.0" }
> ```
---
> [!CAUTION]
> ### β οΈ CRITICAL: v1.x Security Notice
>
> **All versions 1.x are DEPRECATED and UNSUPPORTED** as of January 27, 2026.
>
> **v1.3.x Beta** - π΄ **CRITICAL SECURITY VULNERABILITY** - DO NOT USE
> Contains critical cryptography flaws in Teapot/Teacup gateway. If you're using this, **STOP IMMEDIATELY** and upgrade to v2.0.0.
>
> **v1.2.x Production** - π‘ No crypto issues, but **deprecated** (InversifyJS v6 EOL)
>
> **π Upgrade to v2.0.0 NOW** - See [Migration Guide](docs/MIGRATION_GUIDE_v2.md)
---
## β‘ Quick Start
```bash
# Install the new package
npm install @expressive-tea/core
# Or with yarn
yarn add @expressive-tea/core
```
```typescript
import { ServerSettings, Route, Get, Boot } from '@expressive-tea/core';
@ServerSettings({ port: 3000 })
class App extends Boot {}
@Route('/hello')
class HelloController {
@Get('/')
sayHello() {
return { message: 'Hello, World! π΅' };
}
}
new App().start();
// π Server running on http://localhost:3000
```
**[Try it live on CodeSandbox β](https://codesandbox.io/s/expressive-tea-2kmg7?fontsize=14&hidenavigation=1&theme=dark)**
---
## π― Why Expressive Tea?
### The Problem
Building Node.js applications is powerful, but messy. You get a blank canvas with Expressβno structure, no conventions, just middleware chaos. Sound familiar?
### The Solution
**Expressive Tea** brings the elegance of modern frameworks to Node.js, without the bloat. Think NestJS simplicity meets Express flexibility.
### π What Makes It Special
| Feature | What You Get |
|---------|-------------|
| π¨ **Clean Architecture** | Decorators organize your code beautifullyβno more spaghetti routes |
| π **Plugin Everything** | Share database configs, auth, websockets across projects |
| π **Smart DI** | Singleton, Transient, Scoped servicesβInversifyJS under the hood |
| π‘οΈ **Type-Safe** | Full TypeScript strict modeβcatch bugs before they ship |
| π **Secure by Default** | AES-256-GCM + HKDF crypto, built-in security best practices |
| β‘ **Production Ready** | 92%+ test coverage, battle-tested in real applications |
| π― **Express Compatible** | Use ANY Express middlewareβgradual migration friendly |
| π¦ **Zero Lock-in** | BYOA (Bring Your Own Architecture)βwe don't force opinions |
---
## π What's New in v2.0
**Major security and architecture improvements!**
```diff
+ β
Security: Fixed critical crypto vulnerabilities (AES-256-GCM + HKDF)
+ β
Type Safety: Full TypeScript strict mode support
+ β
DI: Scoped dependency injection (Singleton/Transient/Scoped)
+ β
Health Checks: Built-in health endpoints for Kubernetes/monitoring
+ β
Environment: .env file support with @Env decorator
+ β
Performance: Native utilities, removed lodash dependencies
+ β
ESLint: Migrated to ESLint v9 flat config
+ β
Quality: 95%+ coverage, all tests passing
```
**β οΈ Breaking Changes:**
- Cryptography format changed (must re-encrypt data)
- TypeScript strict mode enabled
- **Node.js 20+ required** (Node.js 18 reached EOL April 2025)
- Express 5.x required
- ESLint v9 (flat config)
**[π Full Changelog](CHANGELOG.md)** β’ **[π Migration Guide](docs/MIGRATION_GUIDE_v2.md)**
---
## π‘ Features That'll Make You Smile
### π¨ Decorator-Driven Development
```typescript
@Route('/api/users')
class UserController {
@Get('/:id')
async getUser(@Param('id') id: string) {
return this.userService.findById(id);
}
@Post('/')
async createUser(@Body() data: CreateUserDto) {
return this.userService.create(data);
}
}
```
### π Pluggable Architecture
```typescript
import { AuthPlugin } from '@my-org/auth-plugin';
import { DatabasePlugin } from '@my-org/db-plugin';
@ServerSettings({
port: 3000,
plugins: [AuthPlugin, DatabasePlugin]
})
class App extends Boot {}
```
### π Dependency Injection
```typescript
@injectable()
class UserService {
constructor(
@inject(TYPES.Database) private db: Database,
@inject(TYPES.Logger) private logger: Logger
) {}
}
```
### π― Type-Safe Everything
```typescript
// Generics everywhere
class ApiResponse {
constructor(
public data: T,
public status: number
) {}
}
@Get('/users')
getUsers(): ApiResponse {
return new ApiResponse(users, 200);
}
```
### π₯ Built-in Health Checks
```typescript
@HealthCheck({
checks: [
{
name: 'database',
check: async () => {
const isConnected = await db.ping();
return { status: isConnected ? 'pass' : 'fail' };
},
critical: true, // Blocks readiness probe if fails
timeout: 5000
}
]
})
class App extends Boot {}
// Endpoints:
// GET /health - Detailed health status
// GET /health/live - Liveness probe (K8s)
// GET /health/ready - Readiness probe (K8s)
```
### π Environment Variable Support
```typescript
// Load from .env files
@Env({ path: '.env', required: ['DATABASE_URL', 'API_KEY'] })
@Env({ path: '.env.local', override: true, silent: true })
class App extends Boot {}
// In your .env:
// DATABASE_URL=postgres://localhost:5432/mydb
// API_KEY="secret-key"
```
### π― Type-Safe Environment Variables (v2.0.1+)
```typescript
import { z } from 'zod';
const EnvSchema = z.object({
PORT: z.string().transform(Number),
DATABASE_URL: z.string().url(),
API_KEY: z.string().min(32)
});
type Env = z.infer;
@Env({
transform: (env) => EnvSchema.parse(env),
onTransformError: 'throw' // Fail fast on invalid env
})
class App extends Boot {
constructor() {
super();
const env = Settings.getInstance().getEnv();
console.log(env.PORT); // Type: number (validated!)
}
}
```
### π Configuration Files (v2.0.1+)
```yaml
# .expressive-tea.yaml (YAML support!)
port: 3000
securePort: 4443
database:
host: localhost
port: 5432
# Comments supported!
cache:
enabled: true
ttl: 3600
```
**File Priority**: `.expressive-tea.yaml` > `.expressive-tea.yml` > `.expressive-tea` (JSON)
---
## π¦ Installation & Setup
### Prerequisites
- **Node.js** β₯ 20.0.0
- **TypeScript** β₯ 5.0.0
- **Express** β₯ 5.0.0
> **Note:** Node.js 18 support was dropped in v2.0.0 as it reached End-of-Life in April 2025. We recommend using Node.js 20 LTS or Node.js 22 for the best experience and security updates.
### Configure TypeScript
```json
{
"compilerOptions": {
"target": "ES2017",
"module": "commonjs",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
// Recommended for maximum safety
"strict": true,
"strictNullChecks": true,
"noImplicitAny": true
}
}
```
### Install
```bash
# npm
npm install @expressive-tea/core reflect-metadata
# yarn
yarn add @expressive-tea/core reflect-metadata
```
---
## Local staging with Verdaccio
If you want to test publishing locally before pushing to the public registry, use a local Verdaccio instance as a staging registry.
Quick steps:
1. Start Verdaccio (Docker):
```bash
docker run -d --rm --name verdaccio-expressive-tea -p 4873:4873 verdaccio/verdaccio:latest
```
2. Point npm to local registry and publish:
```bash
# point npm to local registry
npm set registry http://localhost:4873
# publish (from package root)
npm publish --registry http://localhost:4873
# restore default registry
npm set registry https://registry.npmjs.org/
```
3. Optional: Use the repo-provided Verdaccio config for deterministic behavior:
```bash
docker run -d --rm --name verdaccio-expressive-tea -p 4873:4873 \
-v $(pwd)/.docs/verdaccio/config.yaml:/verdaccio/conf/config.yaml \
verdaccio/verdaccio:latest
```
Notes:
- Default URL: http://localhost:4873
- Container name: verdaccio-expressive-tea (the agent checks for this name before starting a new container)
- Anonymous publishing is enabled in the example config (local only). Do not expose to public networks.
- The config permits overwriting the same package version for easy iterative testing.
### Your First App
**1. Create your server:**
```typescript
// server.ts
import 'reflect-metadata';
import { ServerSettings, Boot } from '@expressive-tea/core';
@ServerSettings({
port: 3000,
controllers: [HelloController]
})
class MyApp extends Boot {}
export default MyApp;
```
**2. Add a controller:**
```typescript
// controllers/hello.controller.ts
import { Route, Get } from '@expressive-tea/core';
@Route('/hello')
export class HelloController {
@Get('/')
sayHello() {
return { message: 'Hello, Expressive Tea! π΅' };
}
}
```
**3. Start it up:**
```typescript
// main.ts
import MyApp from './server';
const app = new MyApp();
app.start().then(() => {
console.log('π Server is running!');
});
```
**[π Full Tutorial β](https://zero-oneit.github.io/expresive-tea/)**
---
## π Learn More
### π Documentation
- [Complete Guide](https://zero-oneit.github.io/expresive-tea/) - Full documentation
- [API Reference](https://zero-oneit.github.io/expresive-tea/api/) - Complete API docs
- [Examples](https://github.com/Expressive-Tea/expressive-tea-sandbox) - Sample projects
### π v2.0.1 Features
- [Configuration Files Guide](docs/configuration-files.md) - YAML/JSON config support
- [Environment Variables Guide](docs/env-decorator.md) - Type-safe env with Zod
### π Migration & Upgrading
- [Migration Guide v1 β v2](docs/MIGRATION_GUIDE_v2.md) - Step-by-step upgrade
- [Release Notes v2.0](docs/RELEASE_NOTES_v2.0.0.md) - What's new
- [Deprecation Notice](docs/DEPRECATION_NOTICE.md) - v1.x timeline
### π‘οΈ Security
- [Security Policy](SECURITY.md) - Vulnerability reporting
- [Changelog](CHANGELOG.md) - Version history
---
## π€ Contributing
We love contributions! Whether it's bug fixes, features, or docs.
**Quick links:**
- [Contributing Guide](CONTRIBUTING.md) - How to contribute
- [Code of Conduct](CODE_OF_CONDUCT.md) - Community guidelines
- [Issues](https://github.com/Expressive-Tea/expresive-tea/issues) - Report bugs or request features
```bash
# Get started
git clone https://github.com/Expressive-Tea/expresive-tea.git
cd expresive-tea
yarn install
yarn test
```
### π€ AI-Assisted Development & Vibe Coding
**We welcome AI-assisted contributions!** Whether you're using GitHub Copilot, Cursor, Claude, or other AI coding assistants, we embrace the future of collaborative development.
**β οΈ IMPORTANT: AI-Generated Code Requirements**
If you're using AI tools for code generation, you **MUST**:
1. **π Follow Repository Guidelines**
- β
Read and strictly adhere to [`AGENTS.md`](AGENTS.md) - Agent-specific coding rules
- β
Read and strictly adhere to [`CLAUDE.md`](CLAUDE.md) - Claude AI guidelines
- β
These files contain critical project conventions, style guides, and quality standards
2. **π¨βπ» Human Review is MANDATORY**
- β
**All AI-generated code MUST be reviewed by a human developer** before creating a pull request
- β
Understand the code completelyβdon't submit code you can't explain
- β
Test thoroughly (aim for 95%+ coverage)
- β
Verify the code follows our architectural patterns and best practices
3. **β
Quality Standards**
- β
All tests must pass (`yarn test`)
- β
Linting must pass (`yarn linter:ci`)
- β
TypeScript must compile without errors (`yarn build`)
- β
Code must match our existing patterns and conventions
- β
Documentation must be updated (JSDoc, README, CHANGELOG)
4. **π PR Transparency**
- β
Disclose AI assistance in your pull request description
- β
Example: "This PR was developed with assistance from Claude/Copilot/Cursor"
- β
Highlight any sections that were fully AI-generated for extra review
**Why These Rules?**
- π‘οΈ **Quality Assurance** - AI can make subtle mistakes humans catch
- π― **Consistency** - Ensures code matches our architectural vision
- π **Knowledge Transfer** - Reviewers understand your contribution
- π **Security** - Prevents AI from introducing vulnerabilities
- π€ **Collaboration** - Maintains clear communication in the codebase
**Vibe Coding Best Practices:**
```typescript
// β
GOOD: AI-generated, reviewed, and refined by human
@Route('/api/users')
class UserController {
@Get('/:id')
async getUser(@Param('id') id: string): Promise {
// Human: Added validation per AGENTS.md security guidelines
if (!id || !validator.isUUID(id)) {
throw new BadRequestException('Invalid user ID');
}
return this.userService.findById(id);
}
}
// β BAD: AI-generated, unreviewed, missing error handling
@Route('/api/users')
class UserController {
@Get('/:id')
async getUser(@Param('id') id: string) {
return this.userService.findById(id); // What if id is invalid?
}
}
```
**π Required Reading for AI-Assisted Development:**
- [`AGENTS.md`](AGENTS.md) - Repository-specific rules for AI agents
- [`CLAUDE.md`](CLAUDE.md) - Claude AI coding guidelines
- [`CONTRIBUTING.md`](CONTRIBUTING.md) - General contribution guide
- [`.prettierrc`](.prettierrc) - Code formatting rules
- [`eslint.config.js`](eslint.config.js) - Linting configuration
**Questions?** Ask in [GitHub Discussions](https://github.com/Expressive-Tea/expresive-tea/discussions) before submitting AI-generated code.
---
## π¬ Community & Support
### Get Help
- π [Documentation](https://zero-oneit.github.io/expresive-tea/)
- π¬ [Gitter Chat](https://gitter.im/Expressive-Tea/expresive-tea)
- π§ [Email Support](mailto:support@expressive-tea.io)
- π [GitHub Issues](https://github.com/Expressive-Tea/expresive-tea/issues)
- π [Stack Overflow](https://stackoverflow.com/questions/tagged/expressive-tea) - Use tag `expressive-tea`
### Stay Connected
- π¦ Twitter: [@expressive_tea](https://twitter.com/expressive_tea)
- π§ Email: [support@expressive-tea.io](mailto:support@expressive-tea.io)
- π¨βπ» Author: [Diego Resendez](https://twitter.com/diegoresendez)
---
## π Built With
| Technology | Purpose |
|------------|---------|
| [Express](https://expressjs.com/) | Fast, unopinionated web framework |
| [TypeScript](https://www.typescriptlang.org/) | Type-safe JavaScript |
| [InversifyJS](https://inversify.io/) | Powerful dependency injection |
| [Reflect Metadata](https://github.com/rbuckton/reflect-metadata) | Decorator metadata support |
---
## π Sponsors
Building Expressive Tea takes time and dedication. If this project helps you, consider sponsoring!
**Principal Sponsor:**
**Interested in sponsoring?** Contact [projects@zero-oneit.com](mailto:projects@zero-oneit.com)
---
## π License
Apache-2.0 License - see [LICENSE](LICENSE) file for details
---
## π Versioning
We use [Semantic Versioning](http://semver.org/) (SemVer). See [tags](https://github.com/Expressive-Tea/expresive-tea/tags) for available versions.
---
## π₯ Contributors
**Lead Developer:** [Diego Resendez](https://github.com/zerooneit)
See all [contributors](https://github.com/Expressive-Tea/expresive-tea/contributors) who've helped shape Expressive Tea.
---
## β€οΈ Credits
Logo and banner designed by [Freepik](http://www.freepik.com)
---
Made with β and π΅ by the Expressive Tea Team
Start brewing better Node.js apps today!