@digitaldefiance/node-express-suite
v3.6.7
Published
Generic express application and routing library with decorator support
Maintainers
Readme
@digitaldefiance/node-express-suite
An opinionated, secure, extensible Node.js/Express service framework built on Digital Defiance cryptography libraries, providing complete backend infrastructure for secure applications.
It is an 'out of the box' solution with a specific recipe (Mongo, Express, React, Node, (MERN) stack) with ejs templating, JWT authentication, role-based access control, custom multi-language support via @digitaldefiance/i18n-lib, and a dynamic model registry system. You might either find it limiting or freeing, depending on your use case. It includes mnemonic authentication, ECIES encryption/decryption, PBKDF2 key derivation, email token workflows, and more.
Part of Express Suite
What's New in v3.0
✨ Major Dependency Upgrade - Upgraded to @digitaldefiance/suite-core-lib v3.0.0 and @digitaldefiance/ecies-lib v4.1.0. This brings significant improvements in type safety, performance, and security.
Features
- 🔐 ECIES Encryption/Decryption: End-to-end encryption using elliptic curve cryptography
- 🔑 PBKDF2 Key Derivation: Secure password hashing with configurable profiles
- 👥 Role-Based Access Control (RBAC): Flexible permission system with user roles
- 🌍 Multi-Language i18n: Plugin-based internationalization with 8+ languages
- 📊 Dynamic Model Registry: Extensible document model system
- 🔧 Runtime Configuration: Override defaults at runtime for advanced use cases
- 🛡️ JWT Authentication: Secure token-based authentication
- 📧 Email Token System: Verification, password reset, and recovery workflows
- 💾 MongoDB Integration: Full database layer with Mongoose schemas
- 🧪 Comprehensive Testing: 100+ tests covering all major functionality
- 🏗️ Modern Architecture: Service container, fluent builders, plugin system
- ⚡ Simplified Generics: 87.5% reduction in type complexity
- 🔄 Automatic Transactions: Decorator-based transaction management
- 🎨 Fluent APIs: Validation, response, pipeline, and route builders
Installation
npm install @digitaldefiance/node-express-suite
# or
yarn add @digitaldefiance/node-express-suiteQuick Start
Basic Server Setup
import { Application, DatabaseInitializationService, emailServiceRegistry } from '@digitaldefiance/node-express-suite';
import { CoreLanguage } from '@digitaldefiance/i18n-lib';
import { EmailService } from './services/email'; // Your concrete implementation
// Create application instance
const app = new Application({
port: 3000,
mongoUri: 'mongodb://localhost:27017/myapp',
jwtSecret: process.env.JWT_SECRET,
defaultLanguage: CoreLanguage.EnglishUS
});
// Configure email service (required before using middleware)
emailServiceRegistry.setService(new EmailService(app));
// Initialize database with default users and roles
const initResult = await DatabaseInitializationService.initUserDb(app);
// Start server
await app.start();
console.log(`Server running on port ${app.environment.port}`);User Authentication
import { JwtService, UserService } from '@digitaldefiance/node-express-suite';
// Create services
const jwtService = new JwtService(app);
const userService = new UserService(app);
// Sign in user
const user = await userService.findByUsername('alice');
const { token, roles } = await jwtService.signToken(user, app.environment.jwtSecret);
// Verify token
const tokenUser = await jwtService.verifyToken(token);
console.log(`User ${tokenUser.userId} authenticated with roles:`, tokenUser.roles);Core Components
Dynamic Model Registry
The package uses a dynamic model registration system for extensibility:
import { ModelRegistry } from '@digitaldefiance/node-express-suite';
// Register a custom model
ModelRegistry.instance.register({
modelName: 'Organization',
schema: organizationSchema,
model: OrganizationModel,
collection: 'organizations',
});
// Retrieve model anywhere in your app
const OrgModel = ModelRegistry.instance.get<IOrganizationDocument>('Organization').model;
// Use the model
const org = await OrgModel.findById(orgId);Built-in Models
The framework includes these pre-registered models:
- User: User accounts with authentication
- Role: Permission roles for RBAC
- UserRole: User-to-role associations
- EmailToken: Email verification and recovery tokens
- Mnemonic: Encrypted mnemonic storage
- UsedDirectLoginToken: One-time login token tracking
Extending Models and Schemas
All model functions support generic type parameters for custom model names and collections:
import { UserModel, EmailTokenModel } from '@digitaldefiance/node-express-suite';
// Use with default enums
const defaultUserModel = UserModel(connection);
// Use with custom model names and collections
const customUserModel = UserModel(
connection,
'CustomUser',
'custom_users'
);Extending Schemas
Clone and extend base schemas with additional fields:
import { EmailTokenSchema } from '@digitaldefiance/node-express-suite';
import { Schema } from 'mongoose';
// Clone and extend the schema
const ExtendedEmailTokenSchema = EmailTokenSchema.clone();
ExtendedEmailTokenSchema.add({
customField: { type: String, required: false },
metadata: { type: Schema.Types.Mixed, required: false },
});
// Use with custom model
const MyEmailTokenModel = connection.model(
'ExtendedEmailToken',
ExtendedEmailTokenSchema,
'extended_email_tokens'
);Extending Model Functions
Create custom model functions that wrap extended schemas:
import { IEmailTokenDocument } from '@digitaldefiance/node-express-suite';
import { Connection, Model } from 'mongoose';
// Extend the document interface
interface IExtendedEmailTokenDocument extends IEmailTokenDocument {
customField?: string;
metadata?: any;
}
// Create extended schema (as shown above)
const ExtendedEmailTokenSchema = EmailTokenSchema.clone();
ExtendedEmailTokenSchema.add({
customField: { type: String },
metadata: { type: Schema.Types.Mixed },
});
// Create custom model function
export function ExtendedEmailTokenModel<
TModelName extends string = 'ExtendedEmailToken',
TCollection extends string = 'extended_email_tokens'
>(
connection: Connection,
modelName: TModelName = 'ExtendedEmailToken' as TModelName,
collection: TCollection = 'extended_email_tokens' as TCollection,
): Model<IExtendedEmailTokenDocument> {
return connection.model<IExtendedEmailTokenDocument>(
modelName,
ExtendedEmailTokenSchema,
collection,
);
}
// Use the extended model
const model = ExtendedEmailTokenModel(connection);
const token = await model.create({
userId,
type: EmailTokenType.AccountVerification,
token: 'abc123',
email: '[email protected]',
customField: 'custom value',
metadata: { source: 'api' },
});Custom Enumerations
Extend the base enumerations for your application:
import { BaseModelName, SchemaCollection } from '@digitaldefiance/node-express-suite';
// Extend base enums
enum MyModelName {
User = BaseModelName.User,
Role = BaseModelName.Role,
Organization = 'Organization',
Project = 'Project',
}
enum MyCollection {
User = SchemaCollection.User,
Role = SchemaCollection.Role,
Organization = 'organizations',
Project = 'projects',
}
// Use with model functions
const orgModel = UserModel<MyModelName, MyCollection>(
connection,
MyModelName.Organization,
MyCollection.Organization
);Complete Extension Example
Combining schemas, documents, and model functions:
import { IUserDocument, UserSchema } from '@digitaldefiance/node-express-suite';
import { Connection, Model, Schema } from 'mongoose';
// 1. Extend document interface
interface IOrganizationUserDocument extends IUserDocument {
organizationId: string;
department?: string;
}
// 2. Extend schema
const OrganizationUserSchema = UserSchema.clone();
OrganizationUserSchema.add({
organizationId: { type: String, required: true },
department: { type: String },
});
// 3. Create model function
export function OrganizationUserModel(
connection: Connection,
): Model<IOrganizationUserDocument> {
return connection.model<IOrganizationUserDocument>(
'OrganizationUser',
OrganizationUserSchema,
'organization_users',
);
}
// 4. Use in application
const model = OrganizationUserModel(connection);
const user = await model.create({
username: 'alice',
email: '[email protected]',
organizationId: 'org-123',
department: 'Engineering',
});Services
ECIESService
Encryption and key management:
import { ECIESService } from '@digitaldefiance/node-express-suite';
const eciesService = new ECIESService();
// Generate mnemonic
const mnemonic = eciesService.generateNewMnemonic();
// Encrypt data
const encrypted = await eciesService.encryptSimpleOrSingle(
false, // single mode
recipientPublicKey,
Buffer.from('secret message')
);
// Decrypt data
const decrypted = await eciesService.decryptSimpleOrSingleWithHeader(
false,
privateKey,
encrypted
);KeyWrappingService
Secure key storage and retrieval:
import { KeyWrappingService } from '@digitaldefiance/node-express-suite';
const keyWrapping = new KeyWrappingService(app);
// Wrap a key with password
const wrapped = await keyWrapping.wrapKey(
privateKey,
password,
salt
);
// Unwrap key
const unwrapped = await keyWrapping.unwrapKey(
wrapped,
password,
salt
);RoleService
Role and permission management:
import { RoleService } from '@digitaldefiance/node-express-suite';
const roleService = new RoleService(app);
// Get user roles
const roles = await roleService.getUserRoles(userId);
// Check permissions
const hasPermission = await roleService.userHasRole(userId, 'admin');
// Create role
const adminRole = await roleService.createRole({
name: 'admin',
description: 'Administrator role',
permissions: ['read', 'write', 'delete']
});BackupCodeService
Backup code generation and validation:
import { BackupCodeService } from '@digitaldefiance/node-express-suite';
const backupCodeService = new BackupCodeService(app);
// Generate backup codes
const codes = await backupCodeService.generateBackupCodes(userId);
// Validate code
const isValid = await backupCodeService.validateBackupCode(userId, userCode);
// Mark code as used
await backupCodeService.useBackupCode(userId, userCode);Database Initialization
Initialize database with default users and roles:
import { DatabaseInitializationService } from '@digitaldefiance/node-express-suite';
// Initialize with default admin, member, and system users
const result = await DatabaseInitializationService.initUserDb(app);
if (result.success) {
console.log('Admin user:', result.data.adminUsername);
console.log('Admin password:', result.data.adminPassword);
console.log('Admin mnemonic:', result.data.adminMnemonic);
console.log('Backup codes:', result.data.adminBackupCodes);
}Middleware
Email Service Configuration
Before using middleware that requires email functionality, configure the email service:
import { emailServiceRegistry, IEmailService } from '@digitaldefiance/node-express-suite';
// Implement the IEmailService interface
class MyEmailService implements IEmailService {
async sendEmail(to: string, subject: string, text: string, html: string): Promise<void> {
// Your email implementation (AWS SES, SendGrid, etc.)
}
}
// Register at application startup
emailServiceRegistry.setService(new MyEmailService());Authentication Middleware
import { authMiddleware } from '@digitaldefiance/node-express-suite';
// Protect routes with JWT authentication
app.get('/api/protected', authMiddleware, (req, res) => {
// req.user contains authenticated user info
res.json({ user: req.user });
});Role-Based Authorization
import { requireRole } from '@digitaldefiance/node-express-suite';
// Require specific role
app.delete('/api/users/:id',
authMiddleware,
requireRole('admin'),
async (req, res) => {
// Only admins can access this route
await userService.deleteUser(req.params.id);
res.json({ success: true });
}
);Runtime Configuration Registry
Override defaults at runtime for advanced use cases:
import {
getExpressRuntimeConfiguration,
registerExpressRuntimeConfiguration,
} from '@digitaldefiance/node-express-suite';
// Get current configuration
const config = getExpressRuntimeConfiguration();
console.log('Bcrypt rounds:', config.BcryptRounds);
// Register custom configuration
const customKey = Symbol('custom-express-config');
registerExpressRuntimeConfiguration(customKey, {
BcryptRounds: 12,
JWT: {
ALGORITHM: 'HS512',
EXPIRATION_SEC: 7200
}
});
// Use custom configuration
const customConfig = getExpressRuntimeConfiguration(customKey);Available Configuration Options
interface IExpressRuntimeConfiguration {
BcryptRounds: number;
JWT: {
ALGORITHM: string;
EXPIRATION_SEC: number;
};
BACKUP_CODES: {
Count: number;
Length: number;
};
// ... more options
}Internationalization
Built-in support for multiple languages using the plugin-based i18n architecture:
import { getGlobalI18nEngine, translateExpressSuite } from '@digitaldefiance/node-express-suite';
import { CoreLanguage } from '@digitaldefiance/i18n-lib';
// Get the global i18n engine
const i18n = getGlobalI18nEngine();
// Translate strings
const message = translateExpressSuite(
ExpressSuiteStringKey.Common_Ready,
{},
CoreLanguage.French
);
// "Prêt"
// Change language globally
i18n.setLanguage(CoreLanguage.Spanish);Supported Languages
- English (US)
- Spanish
- French
- Mandarin Chinese
- Japanese
- German
- Ukrainian
Error Handling
Comprehensive error types with localization:
import {
TranslatableError,
InvalidJwtTokenError,
TokenExpiredError,
UserNotFoundError
} from '@digitaldefiance/node-express-suite';
try {
const user = await userService.findByEmail(email);
} catch (error) {
if (error instanceof UserNotFoundError) {
// Handle user not found
res.status(404).json({
error: error.message // Automatically localized
});
} else if (error instanceof TranslatableError) {
// Handle other translatable errors
res.status(400).json({ error: error.message });
}
}Testing
Comprehensive test suite with 604 passing tests:
# Run all tests
npm test
# Run specific test suites
npm test -- database-initialization.spec.ts
npm test -- jwt.spec.ts
npm test -- role.spec.ts
# Run with coverage
npm test -- --coverageTest Utilities
Test helpers and mocks are available via the /testing entry point:
// Import test utilities
import {
mockFunctions,
setupTestEnv,
// ... other test helpers
} from '@digitaldefiance/node-express-suite/testing';
// Use in your tests
beforeAll(async () => {
await setupTestEnv();
});Note: The /testing entry point requires @faker-js/faker as a peer dependency. Install it in your dev dependencies:
npm install -D @faker-js/faker
# or
yarn add -D @faker-js/fakerTest Coverage (v2.1)
- 604 tests passing (100% success rate)
- 57.86% overall coverage
- 11 modules at 100% coverage
- All critical paths tested (validation, auth, services)
Best Practices
Security
Always use environment variables for sensitive configuration:
const app = new Application({ jwtSecret: process.env.JWT_SECRET, mongoUri: process.env.MONGO_URI, });Validate all user input before processing:
import { EmailString } from '@digitaldefiance/ecies-lib'; try { const email = new EmailString(userInput); // Email is validated } catch (error) { // Invalid email format }Use secure password hashing with appropriate bcrypt rounds:
const config = getExpressRuntimeConfiguration(); const hashedPassword = await bcrypt.hash(password, config.BcryptRounds);
Performance
Use async operations to avoid blocking:
const [user, roles] = await Promise.all([ userService.findById(userId), roleService.getUserRoles(userId) ]);Implement caching for frequently accessed data:
const cachedRoles = await cache.get(`user:${userId}:roles`); if (!cachedRoles) { const roles = await roleService.getUserRoles(userId); await cache.set(`user:${userId}:roles`, roles, 3600); }Use database indexes for common queries:
userSchema.index({ email: 1 }, { unique: true }); userSchema.index({ username: 1 }, { unique: true });
API Reference
Application
new Application(config)- Create application instancestart()- Start the Express serverstop()- Stop the server gracefullyenvironment- Access configuration
Services
ECIESService- Encryption and key managementKeyWrappingService- Secure key storageJwtService- JWT token operationsRoleService- Role and permission managementUserService- User account operationsBackupCodeService- Backup code managementMnemonicService- Mnemonic storage and retrievalSystemUserService- System user operations
Utilities
ModelRegistry- Dynamic model registrationdebugLog()- Conditional logging utilitywithTransaction()- MongoDB transaction wrapper
Testing
Testing Approach
The node-express-suite package uses comprehensive testing with 604 tests covering all services, middleware, controllers, and database operations.
Test Framework: Jest with TypeScript support
Property-Based Testing: fast-check for validation properties
Coverage: 57.86% overall, 100% on critical paths
Database: MongoDB Memory Server for isolated testing
Test Structure
tests/
├── unit/ # Unit tests for services and utilities
├── integration/ # Integration tests for multi-service flows
├── e2e/ # End-to-end API tests
├── middleware/ # Middleware tests
└── fixtures/ # Test data and mocksRunning Tests
# Run all tests
npm test
# Run with coverage
npm test -- --coverage
# Run specific test suite
npm test -- user-service.spec.ts
# Run in watch mode
npm test -- --watchTest Patterns
Testing Services
import { UserService, Application } from '@digitaldefiance/node-express-suite';
describe('UserService', () => {
let app: Application;
let userService: UserService;
beforeAll(async () => {
app = new Application({
mongoUri: 'mongodb://localhost:27017/test',
jwtSecret: 'test-secret'
});
await app.start();
userService = new UserService(app);
});
afterAll(async () => {
await app.stop();
});
it('should create user', async () => {
const user = await userService.create({
username: 'alice',
email: '[email protected]',
password: 'SecurePass123!'
});
expect(user.username).toBe('alice');
});
});Testing Middleware
import { authMiddleware } from '@digitaldefiance/node-express-suite';
import { Request, Response, NextFunction } from 'express';
describe('Auth Middleware', () => {
it('should reject requests without token', async () => {
const req = { headers: {} } as Request;
const res = {
status: jest.fn().mockReturnThis(),
json: jest.fn()
} as unknown as Response;
const next = jest.fn() as NextFunction;
await authMiddleware(req, res, next);
expect(res.status).toHaveBeenCalledWith(401);
expect(next).not.toHaveBeenCalled();
});
});Testing Controllers
import { UserController } from '@digitaldefiance/node-express-suite';
describe('UserController', () => {
it('should register new user', async () => {
const controller = new UserController(app);
const req = {
body: {
username: 'alice',
email: '[email protected]',
password: 'SecurePass123!'
}
} as Request;
const result = await controller.register(req, res, next);
expect(result.statusCode).toBe(201);
expect(result.response.data.user).toBeDefined();
});
});Testing Database Operations
import { connectMemoryDB, disconnectMemoryDB, clearMemoryDB } from '@digitaldefiance/express-suite-test-utils';
import { UserModel } from '@digitaldefiance/node-express-suite';
describe('User Model', () => {
beforeAll(async () => {
await connectMemoryDB();
});
afterAll(async () => {
await disconnectMemoryDB();
});
afterEach(async () => {
await clearMemoryDB();
});
it('should validate user schema', async () => {
const User = UserModel(connection);
const user = new User({
username: 'alice',
email: '[email protected]'
});
await expect(user.validate()).resolves.not.toThrow();
});
});Testing Best Practices
- Use MongoDB Memory Server for isolated database testing
- Test with transactions to ensure data consistency
- Mock external services like email providers
- Test error conditions and edge cases
- Test middleware in isolation and integration
- Test authentication and authorization flows
Cross-Package Testing
Testing integration with other Express Suite packages:
import { Application } from '@digitaldefiance/node-express-suite';
import { ECIESService } from '@digitaldefiance/node-ecies-lib';
import { IBackendUser } from '@digitaldefiance/suite-core-lib';
describe('Cross-Package Integration', () => {
it('should integrate ECIES with user management', async () => {
const app = new Application({ /* config */ });
const ecies = new ECIESService();
// Create user with encrypted data
const user = await app.services.get(ServiceKeys.USER).create({
username: 'alice',
email: '[email protected]',
// ... encrypted fields
});
expect(user).toBeDefined();
});
});Documentation
📚 Comprehensive documentation is available in the docs/ directory.
Quick Links
- 📚 Documentation Index - Complete documentation index
- 🏗️ Architecture - System design and architecture
- 🎮 Controllers - Controller system and decorators
- ⚙️ Services - Business logic and service container
- 📊 Models - Data models and registry
- 🔌 Middleware - Request pipeline
- 💾 Transactions - Transaction management
- 🔧 Plugins - Plugin system
See the full documentation index for all available documentation.
License
MIT © Digital Defiance
Related Packages
@digitaldefiance/ecies-lib- Core ECIES encryption library@digitaldefiance/node-ecies-lib- Node.js ECIES implementation@digitaldefiance/i18n-lib- Internationalization framework@digitaldefiance/suite-core-lib- Core user management primitives
Contributing
Contributions are welcome! Please read the contributing guidelines in the main repository.
Support
For issues and questions:
- GitHub Issues: https://github.com/Digital-Defiance/node-express-suite/issues
- Email: [email protected]
Architecture Refactor (2025)
Major improvements with large complexity reduction:
New Features
Service Container
// Centralized dependency injection
const jwtService = app.services.get(ServiceKeys.JWT);
const userService = app.services.get(ServiceKeys.USER);Simplified Generics
// Before: IApplication<T, I, TBaseDoc, TEnv, TConst, ...>
// After: IApplication
const app: IApplication = ...;Validation Builder
validation: function(lang) {
return ValidationBuilder.create(lang, this.constants)
.for('email').isEmail().withMessage(key)
.for('username').matches(c => c.UsernameRegex).withMessage(key)
.build();
}Transaction Decorator
@Post('/register', { transaction: true })
async register() {
// this.session available automatically
await this.userService.create(data, this.session);
}Response Builder
return Response.created()
.message(SuiteCoreStringKey.Registration_Success)
.data({ user, mnemonic })
.build();Plugin System
class MyPlugin implements IApplicationPlugin {
async init(app: IApplication) { /* setup */ }
async stop() { /* cleanup */ }
}
app.plugins.register(new MyPlugin());Route Builder DSL
RouteBuilder.create()
.post('/register')
.auth()
.validate(validation)
.transaction()
.handle(this.register);Migration Guide (v1.x → v2.0)
Overview
Version 2.0 introduces a major architecture refactor with 50% complexity reduction while maintaining backward compatibility where possible. This guide helps you migrate from v1.x to v2.0.
Breaking Changes
1. Simplified Generic Parameters
Before (v1.x):
class Application<T, I, TInitResults, TModelDocs, TBaseDocument, TEnvironment, TConstants, TAppRouter>
class UserController<I, D, S, A, TUser, TTokenRole, TTokenUser, TApplication, TLanguage>After (v2.0):
class Application // No generic parameters
class UserController<TConfig extends ControllerConfig, TLanguage>Migration:
- Remove all generic type parameters from Application instantiation
- Update controller signatures to use ControllerConfig interface
- Type information now inferred from configuration objects
2. Service Instantiation
Before (v1.x):
const jwtService = new JwtService(app);
const userService = new UserService(app);
const roleService = new RoleService(app);After (v2.0):
const jwtService = app.services.get(ServiceKeys.JWT);
const userService = app.services.get(ServiceKeys.USER);
const roleService = app.services.get(ServiceKeys.ROLE);Migration:
- Replace direct service instantiation with container access
- Services are now singletons managed by the container
- Import ServiceKeys enum for type-safe service access
Recommended Migrations (Non-Breaking)
3. Transaction Handling
Before (v1.x):
async register(req: Request, res: Response, next: NextFunction) {
return await withTransaction(
this.application.db.connection,
this.application.environment.mongo.useTransactions,
undefined,
async (session) => {
const user = await this.userService.create(data, session);
const mnemonic = await this.mnemonicService.store(userId, session);
return { statusCode: 201, response: { user, mnemonic } };
}
);
}After (v2.0):
@Post('/register', { transaction: true })
async register(req: Request, res: Response, next: NextFunction) {
const user = await this.userService.create(data, this.session);
const mnemonic = await this.mnemonicService.store(userId, this.session);
return Response.created().data({ user, mnemonic }).build();
}Benefits:
- 70% reduction in transaction boilerplate
- Automatic session management
- Cleaner, more readable code
4. Response Construction
Before (v1.x):
return {
statusCode: 201,
response: {
message: getSuiteCoreTranslation(SuiteCoreStringKey.Registration_Success, undefined, lang),
data: { user, mnemonic }
}
};After (v2.0):
return Response.created()
.message(SuiteCoreStringKey.Registration_Success)
.data({ user, mnemonic })
.build();Benefits:
- 40% reduction in response boilerplate
- Fluent, chainable API
- Automatic translation handling
5. Validation
Before (v1.x):
protected getValidationRules(lang: TLanguage) {
return [
body('username')
.matches(this.constants.UsernameRegex)
.withMessage(getSuiteCoreTranslation(key, undefined, lang)),
body('email')
.isEmail()
.withMessage(getSuiteCoreTranslation(key, undefined, lang))
];
}After (v2.0):
validation: function(lang: TLanguage) {
return ValidationBuilder.create(lang, this.constants)
.for('username').matches(c => c.UsernameRegex).withMessage(key)
.for('email').isEmail().withMessage(key)
.build();
}Benefits:
- 50% reduction in validation code
- Constants automatically injected
- Type-safe field access
- Cleaner syntax
6. Middleware Composition
Before (v1.x):
router.post('/backup-codes',
authMiddleware,
authenticateCryptoMiddleware,
validateSchema(backupCodeSchema),
this.getBackupCodes.bind(this)
);After (v2.0):
@Post('/backup-codes', {
pipeline: Pipeline.create()
.use(Auth.token())
.use(Auth.crypto())
.use(Validate.schema(backupCodeSchema))
.build()
})
async getBackupCodes() { /* ... */ }Benefits:
- Explicit middleware ordering
- Reusable pipeline definitions
- Better readability
Step-by-Step Migration
Step 1: Update Dependencies
npm install @digitaldefiance/node-express-suite@^2.0.0
# or
yarn add @digitaldefiance/node-express-suite@^2.0.0Step 2: Update Application Initialization
Before:
const app = new Application<MyTypes, MyIds, MyResults, MyModels, MyDoc, MyEnv, MyConst, MyRouter>({
port: 3000,
mongoUri: process.env.MONGO_URI,
jwtSecret: process.env.JWT_SECRET
});After:
const app = new Application({
port: 3000,
mongoUri: process.env.MONGO_URI,
jwtSecret: process.env.JWT_SECRET
});Step 3: Update Service Access
Find and replace service instantiation:
# Find
new JwtService(app)
# Replace with
app.services.get(ServiceKeys.JWT)
# Find
new UserService(app)
# Replace with
app.services.get(ServiceKeys.USER)Step 4: Migrate Controllers (Gradual)
Start with high-traffic endpoints:
- Add transaction decorator to write operations
- Replace response construction with Response builder
- Update validation to use ValidationBuilder
- Migrate middleware to Pipeline builder
Step 5: Test Thoroughly
# Run full test suite
npm test
# Run specific controller tests
npm test -- user-controller.spec.ts
# Check for deprecation warnings
DEBUG=* npm startMigration Checklist
- [ ] Update package to v2.0.0
- [ ] Remove generic parameters from Application
- [ ] Update service instantiation to use container
- [ ] Migrate transaction handling (high-priority endpoints)
- [ ] Migrate response construction (high-priority endpoints)
- [ ] Update validation rules (new endpoints first)
- [ ] Migrate middleware composition (optional)
- [ ] Run full test suite
- [ ] Check for deprecation warnings
- [ ] Update documentation
- [ ] Deploy to staging
- [ ] Monitor for issues
- [ ] Deploy to production
Backward Compatibility
The following v1.x patterns still work in v2.0:
✅ Direct service instantiation (with deprecation warning) ✅ Manual transaction wrapping with withTransaction ✅ Manual response construction ✅ Traditional validation rules ✅ Direct middleware composition
Performance Considerations
- Service container adds negligible overhead (~0.1ms per request)
- Transaction decorator has same performance as manual wrapping
- Response builder is optimized for common cases
- Validation builder compiles to same express-validator chains
Troubleshooting
Issue: Type errors after upgrade
Solution: Remove generic type parameters from Application and controller signatures.
Issue: Services not found in container
Solution: Ensure services are registered during application initialization. Check ServiceKeys enum.
Issue: Transaction session undefined
Solution: Add { transaction: true } to route decorator options.
Issue: Validation not working
Solution: Ensure ValidationBuilder.create receives correct language and constants.
Getting Help
- Documentation: See REFACTOR_INDEX.md for complete refactor docs
- Examples: See REFACTOR_EXAMPLES.md for code examples
- Issues: Report bugs at GitHub Issues
- Support: Email [email protected]
Additional Resources
ChangeLog
Version 3.6.7
- Update mongoose-types
Version 3.6.6
- Update suite-core
- Properly use @digitaldefiance/mongoose-types throughout
- Add models from suite-core-lib
Version 3.6.2
- Use @digitaldefiance/mongoose-types to suppose mongoose generic types
Version 3.6.1
- Fix mongoose schema to support generic ids
Version 3.6.0
- Version updates to reduce circular dependency
Version 3.5.8
- Library updates
Version 3.5.7
- Library updates
Version 3.5.0
Type Safety Improvements
- ELIMINATED: All unsafe
as anytype casts from production code - IMPROVED: Mongoose query patterns - replaced projection objects with
.select()method - ENHANCED: Generic type handling in
SystemUserServiceandBackupCodeService - FIXED: Type compatibility between Mongoose documents and service interfaces
- ADDED: Explanatory comments for necessary type assertions
- VERIFIED: All 1164 tests passing with full type safety
- VERIFIED: Build successful with strict TypeScript checking
Technical Details
- Replaced
{ password: 0 } as anywith.select('-password')in authentication middleware - Made
SystemUserService.setSystemUsergeneric to accept different ID types - Updated test mocks to support new query method chains
- Documented remaining
as unknowncasts (2 instances, both necessary for generic compatibility)
Version 3.0.0
- Upgrade to
@digitaldefiance/suite-core-libv3.0.0 - Upgrade to
@digitaldefiance/ecies-libv4.1.0 - Upgrade to
@digitaldefiance/node-ecies-libv4.1.0
Version 2.2.36
- Update suite-core-lib
Version 2.2.35
- Update suite-core-lib
Version 2.2.34
- Update suite-core-lib
Version 2.2.33
- Update suite-core-lib
Version 2.2.32
- Fourth attempt to fix roles on login
Version 2.2.31
- Third attempt to fix roles on login
Version 2.2.30
- Second attempt to fix roles on login
Version 2.2.29
- Fix roles on login
Version 2.2.28
- Update libs
Version 2.2.27
- Update suite-core-lib
Version 2.2.26
- Fix user controller direct/email login requestUserDTO response
Version 2.2.25
- Fix user schema validation/tests
Version 2.2.24
- Update user schema for currency
- Update request user function for currency
Version 2.2.23
- Documentation, library updates
Version 2.2.22
- Documentation, library updates
- Add settings endpoint
Version 2.2.21
- Update libs
Version 2.2.20
- Add darkMode endpoint
- Add user settings controller endpoint
- Add user settings service function
Version 2.2.19
- Update suite-core-lib
- Fix default expectations for directChallenge
Version 2.2.18
- Update suite-core-lib
Version 2.2.17
- Update suite-core-lib
Version 2.2.16
- Update suite-core-lib
- Clarify InvalidModelError/ModelNotRegisteredError
Version 2.2.15
- Add this.name to errors
- Update suite-core-lib
Version 2.2.14
- Enable directChallenge login by default
Version 2.2.11
- Fix req.user serialization
- Update suite-core-lib
Version 2.2.10
- Add darkMode user preference
Version 2.2.9
- fix authenticateCrypto
Version 2.2.8
- Changes to base controller
Version 2.2.7
- Working on handleable error handling
Version 2.2.6
- Working on handleable error handling
Version 2.2.5
- Working on handleable error handling
Version 2.2.4
- Working on handleable error handling
Version 2.2.3
- Fix user controller
Version 2.2.2
- Fix Handleable loop
- Print db init failures in application base
Version 2.2.1
- Library upgrade for ecies, etc
- Testing improvements
Version 2.1.67
- Print server init results on dev init
Version 2.1.66
- Add host to HTTPS
Version 2.1.65
- Clarify message
Version 2.1.64
- Don't throw for devDatabase
Version 2.1.63
- Improve EmailRegistry
Version 2.1.62
- Upates to test utils
Version 2.1.61
- Fixes to testing
Version 2.1.60
- Add hostname to constants
Version 2.1.59
- Improve database initialization prints
Version 2.1.58
- Improve database initialization
Version 2.1.57
- Update suite-core
Version 2.1.56
- Update suite-core
- Add .env print to db init fcn
Version 2.1.55
- Fix EnvNotSet error
Version 2.1.47
- Add SiteEmailDomain
Version 2.1.46
- Update suite-core for flags and ISuccessMessage
Version 2.1.44
- Update suite-core for flags
Version 2.1.43
- Upgrade suite-core for adding strings
Version 2.1.42
- Upgrade ecies
- Add regexes to constants
- Add mnemonic encryption key regex/validation
Version 2.1.40
- Alignment with Express Suite packages
- All packages updated to v2.1.40 (i18n, ecies-lib, node-ecies-lib, suite-core-lib, node-express-suite, express-suite-react-components)
- Test utilities remain at v1.0.7
/testingentry point exports test utilities (mockFunctions, setupTestEnv, etc.)- Requires
@faker-js/fakeras dev dependency for test utilities
Version 2.1.35
- Upgrade i18n/bring config through
Version 2.1.27
- Upgrade node-ecies, use new express-suite-test-utils
Version 2.1.25
- Upgrade underlying libraries
- Improve test coverage
Version 2.1.24
- Provide mocks/fixtures for use in testing
- Provide concrete/runnable ApplicationConcrete class
- Export DummyEmailService for testing
- Further streamline Application generics
Version 2.1.22
- Updates from suite-core
Version 2.1.21
- Continued bugfixes
Version 2.1.20
- Minor bugfixes for database-initialization
Version 2.1.19
- minor bugfix for translation in database-initialization
Version 2.1.18
- minor bugfix for translation in database-initialization
Version 2.1.17
- minor bugfix for translation in database-initialization
Version 2.1.16
- Upgrade i18n
Version 2.1.15
- Upgrade i18n
Version 2.1.14
- Minor update to i18n area of node-express-suite in database initialization
Version 2.1.13
- Update i18n
Version 2.1.12
- Minor bump for node-ecies
Version 2.1.11
- Minor change from suite-core for createSuiteCoreComponentConfig()
Version 2.1.10
- Convergence bump/upgrades from i18n/ecies
Version 2.1.7
- Minor version bump from suite-core-lib
Version 2.1.6
- Minor version bump from i18n/ecies
Version 2.1.5
- Minor version bump from i18n/ecies
Version 2.1.3 (January 2025)
Test Suite Stabilization
- FIXED: i18n initialization using correct
initSuiteCoreI18nEngine()function - FIXED: Language registry duplicate registration errors in tests
- FIXED: Validation builder chain initialization before
withMessage() - FIXED: Translation mock signatures to match actual implementation
- FIXED: Environment timezone type expectations
- ADDED: 21 new tests for index exports coverage (604 total, 100% passing)
- IMPROVED: Code coverage from 53.35% to 57.86% (+4.51%)
- IMPROVED: 11 modules now at 100% coverage
- ENHANCED: Clean test output with proper console mocking
Version 2.1.0 (November 2025)
Quality & Stability Release
- UPGRADED: All dependencies to latest stable versions
- @digitaldefiance/[email protected]
- @digitaldefiance/[email protected]
- @digitaldefiance/[email protected]
- @digitaldefiance/[email protected]
- IMPROVED: Test suite with 604 passing tests (100% success rate)
- IMPROVED: Code coverage to 57.86% (+4.5% improvement)
- IMPROVED: 11 modules at 100% coverage
- FIXED: i18n initialization and language registry management
- FIXED: Validation builder chain initialization
- FIXED: Translation mock signatures in tests
- ENHANCED: Type safety throughout the codebase
- ENHANCED: Clean test output with proper console mocking
Version 2.0.0 (Architecture Refactor)
- BREAKING: Simplified IApplication interface (removed 5 generic parameters)
- NEW: Service Container for centralized dependency injection
- NEW: ValidationBuilder with fluent API and constants injection
- NEW: Middleware Pipeline builder for explicit composition
- NEW: Route Builder DSL as alternative to decorators
- NEW: Automatic transaction management via decorators
- NEW: Response Builder with fluent API
- NEW: Application Builder for simplified construction
- NEW: Plugin System for extensibility
- NEW: Router Config separation
- NEW: Database Initializer interface
- NEW: Config Objects pattern throughout
- IMPROVED: 50% overall complexity reduction
- IMPROVED: 87.5% reduction in generic parameters
- IMPROVED: 70% reduction in transaction boilerplate
- IMPROVED: 40% reduction in response boilerplate
- IMPROVED: Better IDE support and type inference
Version 1.3.28
- Bind this on controller validation
Version 1.3.27
- Upgrade i18n, ecies, suite-core
Version 1.3.26
- Refactor middlewares further
Version 1.3.25
- Refactor middlewares to be more extensible
Version 1.3.24
- AppRouter factory to make AppRouter extensible as well
Version 1.3.23
- Make vars protected
Version 1.3.22
- Overridable view rendering
Version 1.3.21
- Minor fix on dist dir detection
Version 1.3.20
- Version bump
- Wired the express-suite package to the shared constant stack: default exports now expose LocalhostConstants, and every service/schema/controller pulls constants from the application instance instead of hard-coding them.
- Propagated the richer constant set (keyring, wrapped-key, PBKDF2 profiles, encryption metadata) into createExpressRuntimeConfiguration, the checksum/FEC services, and type definitions so downstream apps share ECIES/node defaults.
- Updated system-user, backup-code, JWT, mnemonic, key-wrapping, and user flows to accept injected constants, including rewrapping logic and password/KDF validation paths.
- Tightened controller/router/service generics and typings, clarified validation guard rails, and swapped several equality checks to operate on Uint8Array for safer crypto comparisons.
- Refreshed mocks/tests to consume LocalhostConstants, fixed registry helpers, and expanded tsconfig.spec to compile the runtime sources so the new injections are covered.
Version 1.3.18
- Make application factory pattern for api router
Version 1.3.17
- Upgrade i18n with aliases for t() fn
- Handle database initialization errors
Version 1.3.16
- Fix StringName strings
- Fix constatnts during database initialization
Version 1.3.15
- Homogenize versions
Version 1.0.26
- Update libs
Version 1.0.25
- Properly export db-init-cache
Version 1.0.24
- Re-release with js
Version 1.0.23
- Upgrade to es2022/nx monorepo
Version 1.0.22
- Update libs
- Upgrade various things to pluginI18nengine
Version 1.0.21
- Update suite-core
- Update IApplication/Application so that IEnvironment is more extensible
Version 1.0.20
- Update libs
Version 1.0.19
- Pull in i18n registration updates up through suite-core-lib
Version 1.0.18
- Update suite-core
Version 1.0.17
- Update ecies/i18n/suite-core
Version 1.0.16
- Update suite-core
Version 1.0.15
- Update suite-core
Version 1.0.14
- Use typed/handleable from i18n
Version 1.0.13
- Update libs
Version 1.0.12
- Update libs
Version 1.0.11
- Update libs
- Add test
Version 1.0.10
- Export api router
Version 1.0.9
- Update suite-core-lib to include new error classes
- improve role/user services
Version 1.0.8
- Export missing role schema
Version 1.0.7
- Export missing enumeration
Version 1.0.6
- Export enumerations
Version 1.0.5
- Export schemas
Version 1.0.4
- Update suite-core
Version 1.0.3
- Update ecies libs
Version 1.0.0
- Initial release with complete Express.js framework
- Dynamic model registry system
- JWT authentication and RBAC
- Multi-language i18n support
- Comprehensive service layer
- Database initialization utilities
