Skip to content

Latest commit

History

293 Commits

Folders and files

NameName
Last commit message
Last commit date

npm versiondownloadsvulnerabilitiescoveragebuildstarslicense


Expressive Tea is in maintenance. Its successor is green-tea.

green-tea keeps the ideas from this project — decorators, dependency injection, structure — and drops the foundation: no Express, no InversifyJS, and a dependency graph as the core instead of a middleware chain. It runs on Node, Deno, Bun and Cloudflare Workers from one codebase.

This was a ceiling, not an abandonment. Issues #266, #267, #268 and #269 in this repo are the list that made it obvious: type-safe DI, module-scoped providers, a boot-stage redesign and a type-safety overhaul — four breaking XL changes filed on the same day. That is not a v3. Building on someone else's chain means inheriting their model, and every one of those items ended in "…but Express won't let me."

Expressive Tea still works, is still published as @expressive-tea/core, and still receives security fixes. For new projects, start with green-tea.


Logo

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:

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!

- "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


⚡ Quick Start

# Install the new package
npm install @expressive-tea/core
# Or with yarn
yarn add @expressive-tea/core
import{ServerSettings,Route,Get,Boot}from'@expressive-tea/core';
@ServerSettings({port: 3000})classAppextendsBoot{}
@Route('/hello')classHelloController{
@Get('/')sayHello(){return{message: 'Hello, World! 🍵'};}}newApp().start();// 🎉 Server running on http://localhost:3000

Try it live on CodeSandbox →


🎯 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

FeatureWhat You Get
🎨 Clean ArchitectureDecorators organize your code beautifully—no more spaghetti routes
🔌 Plugin EverythingShare database configs, auth, websockets across projects
💉 Smart DISingleton, Transient, Scoped services—InversifyJS under the hood
🛡️ Type-SafeFull TypeScript strict mode—catch bugs before they ship
🔒 Secure by DefaultAES-256-GCM + HKDF crypto, built-in security best practices
Production Ready92%+ test coverage, battle-tested in real applications
🎯 Express CompatibleUse ANY Express middleware—gradual migration friendly
📦 Zero Lock-inBYOA (Bring Your Own Architecture)—we don't force opinions

🚀 What's New in v2.0

Major security and architecture improvements!

+ ✅ 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🔄 Migration Guide


💡 Features That'll Make You Smile

🎨 Decorator-Driven Development

@Route('/api/users')classUserController{
@Get('/:id')asyncgetUser(@Param('id')id: string){returnthis.userService.findById(id);}
@Post('/')asynccreateUser(@Body()data: CreateUserDto){returnthis.userService.create(data);}}

🔌 Pluggable Architecture

import{AuthPlugin}from'@my-org/auth-plugin';import{DatabasePlugin}from'@my-org/db-plugin';
@ServerSettings({port: 3000,plugins: [AuthPlugin,DatabasePlugin]})classAppextendsBoot{}

💉 Dependency Injection

@injectable()classUserService{constructor(
@inject(TYPES.Database)privatedb: Database,
@inject(TYPES.Logger)privatelogger: Logger){}}

🎯 Type-Safe Everything

// Generics everywhereclassApiResponse<T>{constructor(publicdata: T,publicstatus: number){}}
@Get('/users')getUsers(): ApiResponse<User[]>{returnnewApiResponse(users,200);}

🏥 Built-in Health Checks

@HealthCheck({checks: [{name: 'database',check: async()=>{constisConnected=awaitdb.ping();return{status: isConnected ? 'pass' : 'fail'};},critical: true,// Blocks readiness probe if failstimeout: 5000}]})classAppextendsBoot{}// Endpoints:// GET /health - Detailed health status// GET /health/live - Liveness probe (K8s)// GET /health/ready - Readiness probe (K8s)

🌍 Environment Variable Support

// Load from .env files
@Env({path: '.env',required: ['DATABASE_URL','API_KEY']})
@Env({path: '.env.local',override: true,silent: true})classAppextendsBoot{}// In your .env:// DATABASE_URL=postgres://localhost:5432/mydb// API_KEY="secret-key"

🎯 Type-Safe Environment Variables (v2.0.1+)

import{z}from'zod';constEnvSchema=z.object({PORT: z.string().transform(Number),DATABASE_URL: z.string().url(),API_KEY: z.string().min(32)});typeEnv=z.infer<typeofEnvSchema>;
@Env<Env>({transform: (env)=>EnvSchema.parse(env),onTransformError: 'throw'// Fail fast on invalid env})classAppextendsBoot{constructor(){super();constenv=Settings.getInstance().getEnv<Env>();console.log(env.PORT);// Type: number (validated!)}}

📄 Configuration Files (v2.0.1+)

# .expressive-tea.yaml (YAML support!)port: 3000securePort: 4443database:
host: localhostport: 5432# Comments supported!cache:
enabled: truettl: 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

{
"compilerOptions": {
"target": "ES2017",
"module": "commonjs",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
// Recommended for maximum safety"strict": true,
"strictNullChecks": true,
"noImplicitAny": true
}
}

Install

# 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):
docker run -d --rm --name verdaccio-expressive-tea -p 4873:4873 verdaccio/verdaccio:latest
  1. Point npm to local registry and publish:
# 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/
  1. Optional: Use the repo-provided Verdaccio config for deterministic behavior:
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:

// server.tsimport'reflect-metadata';import{ServerSettings,Boot}from'@expressive-tea/core';
@ServerSettings({port: 3000,controllers: [HelloController]})classMyAppextendsBoot{}exportdefaultMyApp;

2. Add a controller:

// controllers/hello.controller.tsimport{Route,Get}from'@expressive-tea/core';
@Route('/hello')exportclassHelloController{
@Get('/')sayHello(){return{message: 'Hello, Expressive Tea! 🍵'};}}

3. Start it up:

// main.tsimportMyAppfrom'./server';constapp=newMyApp();app.start().then(()=>{console.log('🚀 Server is running!');});

📚 Full Tutorial →


🎓 Learn More

📖 Documentation

🆕 v2.0.1 Features

🔄 Migration & Upgrading

🛡️ Security


🤝 Contributing

We love contributions! Whether it's bug fixes, features, or docs.

Quick links:

# 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 - Agent-specific coding rules
    • ✅ Read and strictly adhere to 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:

// ✅ GOOD: AI-generated, reviewed, and refined by human
@Route('/api/users')classUserController{
@Get('/:id')asyncgetUser(@Param('id')id: string): Promise<User>{// Human: Added validation per AGENTS.md security guidelinesif(!id||!validator.isUUID(id)){thrownewBadRequestException('Invalid user ID');}returnthis.userService.findById(id);}}// ❌ BAD: AI-generated, unreviewed, missing error handling
@Route('/api/users')classUserController{
@Get('/:id')asyncgetUser(@Param('id')id: string){returnthis.userService.findById(id);// What if id is invalid?}}

📚 Required Reading for AI-Assisted Development:

Questions? Ask in GitHub Discussions before submitting AI-generated code.


💬 Community & Support

Get Help

Stay Connected


🌟 Built With

TechnologyPurpose
ExpressFast, unopinionated web framework
TypeScriptType-safe JavaScript
InversifyJSPowerful dependency injection
Reflect MetadataDecorator metadata support

🏆 Sponsors

Building Expressive Tea takes time and dedication. If this project helps you, consider sponsoring!

Principal Sponsor:

Zero-OneIT

Interested in sponsoring? Contact projects@zero-oneit.com


📄 License

Apache-2.0 License - see LICENSE file for details


📌 Versioning

We use Semantic Versioning (SemVer). See tags for available versions.


👥 Contributors

Lead Developer:Diego Resendez

See all contributors who've helped shape Expressive Tea.


❤️ Credits

Logo and banner designed by Freepik


Made with ☕ and 🍵 by the Expressive Tea Team
Start brewing better Node.js apps today!

About

A Simple, Clean, Flexible and Modulable web framework project, based on Express and Typescript

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

91 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages