Skip to content

Changelog

All notable changes to Veloce-TS are documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

  • CORS on error responses: error handler responses (401, 422, 500, application/problem+json, etc.) now include Access-Control-Allow-Origin and the rest of the configured CORS headers, consistent with successful responses (mergeVeloceCorsHeaders, VELOCE_CORS_HEADERS_KEY, VeloceCorsHeadersSnapshot).
  • Same CORS fix as attempted in 0.4.4; npm does not allow republishing an unpublished version, so 0.4.5 is the installable release.

Do not use: the npm tarball was broken (404). After unpublish, the registry blocks reusing this version number. Use 0.4.5 for the CORS fix.


  • RFC 9457 (Problem Details): error responses default to Content-Type: application/problem+json with type, title, status, detail, instance, and extensions (violations / details for validation; debug on 500 in development only).
  • VeloceTSConfig.errorResponseFormat: 'rfc9457' (default) or 'legacy' for the previous { error, statusCode, details? } JSON shape.
  • Exported helpers: problemTypeUri, resolveProblemType, resolveProblemTitle, buildProblemInstance, toLegacyErrorBody, sendErrorResponse, PROBLEM_JSON_MEDIA_TYPE, DEFAULT_PROBLEM_TYPE_BASE.
  • HTTPExceptionOptions: optional problemType and title on HTTPException.
  • Auth exceptions (AuthenticationException, AuthorizationException) use the unified error format with authentication-error / authorization-error problem types.
  • @module headers across core, errors, validation, DI, responses, logging, middleware, adapters, testing, and barrels.
  • Benchmarks refreshed for v0.4.3.
  • Error JSON still includes error and statusCode alongside RFC 9457 fields. Clients that require application/json on errors can set errorResponseFormat: 'legacy'.

  • HealthCheckPlugin: checker names are set in a Bun-safe way (Object.defineProperty + fallback) so assigning .name on async checkers no longer throws.
  • @Req export: the parameter decorator is now exported from the main package entry (import { Req } from 'veloce-ts').
  • Guides and API reference updated for @Ctx(), @Req(), and the real HealthCheckPlugin API (checks array, HealthCheckers.database / memory / disk).

  • include() no longer drops decorator-set route fields such as statusCode (@HttpCode) and responseSchema (@ResponseSchema) when registering controller routes.
  • Comprehensive test suite (53 tests) covering functional API routing, decorator routing, body/query validation, HTTP exceptions, and DI container.
  • Console-based fallback logger: if pino is not installed the framework falls back silently to console instead of crashing.
  • pino, pino-pretty, and ioredis moved to optionalDependencies — no longer installed automatically (~7 MB lighter install by default). Install explicitly with bun add pino pino-pretty or bun add ioredis if needed.
  • winston removed from dependencies (it was listed but never used).
  • Core bundle reduced from 444 KB → 408 KB (minified ESM).
  • FastAPITS named export: use VeloceTS or the shorter Veloce alias. FastAPITS will be removed in v1.0.0.

This release is the largest update since the initial launch — over 25 new features spread across three waves of work (high, medium, and low priority), covering the full chain from route generation to OpenAPI documentation, testing, ORM, and the CLI.

Five one-liner decorators as a concise alternative to @ApiDoc({...}):

  • @Summary(text) — short description visible in the Swagger UI route list
  • @Description(text) — long description shown in the operation detail panel
  • @Tag(name) — assigns a single tag; stackable with multiple @Tag
  • @Tags(...names) — assigns several tags in a single decorator
  • @Deprecated() — marks the route as deprecated (shown with strikethrough in Swagger UI)
@Get('/products')
@Summary('List all products')
@Description('Returns a paginated list of all available products')
@Tags('Products', 'Catalog')
async listProducts() {
return products;
}
@Delete('/products/:id')
@Deprecated()
@Summary('Delete a product (deprecated)')
async deleteProduct(@Param('id') id: string) {
return { success: true };
}
  • @HttpCode(statusCode) — overrides the HTTP response code for the handler (e.g. 201 for creation). Also used by the OpenAPI generator as the documented success code
  • @ResponseSchema(schema, statusCode?) — validates and sanitizes the handler response with a Zod schema; informs the response model in the OpenAPI spec
@Post('/products')
@HttpCode(201)
@ResponseSchema(ProductSchema)
async createProduct(@Body(CreateProductSchema) data: any) {
return await db.create(data);
}
  • @Timeout(ms, message?) — aborts the request with 408 Request Timeout if the handler exceeds the limit. Automatically injects the middleware at the start of the pipeline and emits the X-Timeout-Ms header
  • @RateLimit(options) — applies rate-limiting at the individual route level using the same configuration as createRateLimitMiddleware(). Standard X-RateLimit-* headers are sent automatically
@Get('/slow-operation')
@Timeout(5000, 'Operation timed out')
async slowOperation() {
await heavyProcessing();
return result;
}
@Post('/submit')
@RateLimit({ windowMs: 60_000, max: 5 })
async submitForm(@Body(FormSchema) data: any) {
return process(data);
}
  • Auto-tagging: automatically derives tags from the first path segment (/products/:id → tag "Products") without manual annotation
  • Bearer security scheme: adds components.securitySchemes.bearerAuth to the spec and applies security: [{ bearerAuth: [] }] to protected routes automatically
  • Automatic 401: protected routes receive a documented 401 Unauthorized response without additional configuration
  • @HttpCode support: uses the decorator’s statusCode as the key for the success block in responses
  • @ResponseSchema in spec: when present, the Zod schema is converted to JSON Schema format for the response content block

Six new exception classes for common error cases:

  • ConflictException (409)
  • GoneException (410)
  • PayloadTooLargeException (413)
  • UnprocessableEntityException (422)
  • TooManyRequestsException (429)
  • ServiceUnavailableException (503)
  • 5xx errors are logged with getLogger().error including path, method, status, and stack
  • 4xx errors are logged as warn in development environment
  • Generic uncaught errors also pass through Pino
  • @UseMiddleware: now always calls MetadataRegistry.defineRoute so middleware is not lost regardless of decorator execution order
  • @Cache / @CacheInvalidate: same pattern — metadata is correctly merged regardless of stacking order

MetadataCompiler — Lazy Cache with Snapshots

Section titled “MetadataCompiler — Lazy Cache with Snapshots”
  • Lazy compilation: a route is only recompiled if its metadata changed (JSON snapshot comparison)
  • Unique IDs for functional handlers via WeakMap<Function, number> — prevents cache collisions when different app instances register the same path with different handlers (critical bug in parallel tests)
  • clearCache() method exposed to clean state between tests

🧪 TestClient — Fluent API and Auth Helpers

Section titled “🧪 TestClient — Fluent API and Auth Helpers”

Complete rewrite of TestClient:

  • TestResponse — new response class with status, headers, body, text, ok properties and chainable assertion methods:
    • expectStatus(code), expectOk(), expectCreated(), expectNotFound(), etc.
    • expectJson(partialObject) — partial body check
    • expectField(field, value?) — verify a specific field
    • expectHeader(name, value?) — verify a response header
    • expectArrayLength(n) — verify array length in response
  • withToken(token) — creates an immutable client instance with the Authorization: Bearer header already set
  • withHeaders(headers) — creates an immutable instance with additional headers
  • loginAs(credentials, endpoint?) — logs in, extracts the JWT, and injects it into the current client for subsequent requests
  • registerAndLogin(user, endpoints?) — registers and logs in with a single call
  • clearAuth() — clears the stored token
const client = new TestClient(app);
// Fluent assertions
const response = await client.get('/users');
await response.expectOk().expectArrayLength(2);
// Auth helpers
const authClient = await client.loginAs({ email: 'user@example.com', password: 'pass' });
await authClient.get('/profile').then(r => r.expectOk());
// Chain assertions
const res = await client.post('/products', productData);
await res.expectCreated().expectField('id').expectJson({ name: 'Product A' });
  • Uses fs.statfs (Node 18+ / Bun) to obtain real disk metrics: total, free, used, and percentage
  • Graceful fallback to "healthy" on unsupported platforms
  • The fullstack template now generates src/index.ts with GraphQLPlugin and WebSocketPlugin correctly imported and instantiated
  • Added ./src/auth/index.ts, ./src/adapters/base.ts, ./src/adapters/hono.ts, ./src/adapters/express.ts as explicit entrypoints so veloce-ts/auth and veloce-ts/adapters/* imports work correctly

New module to connect Drizzle (or another ORM) to the dependency injection container:

import { registerDrizzle, InjectDB } from 'veloce-ts';
// Register the DB instance
registerDrizzle(app, db);
// Inject into controllers
@Get('/')
async list(@InjectDB() db: DrizzleDB) {
return await db.select().from(products);
}
  • DB_TOKEN — default symbol for the injection token
  • registerDrizzle(app, db, token?) — registers as singleton in the DIContainer
  • @InjectDB(token?) — parameter decorator, alias of @Depends(DB_TOKEN)
  • PaginationMeta includes from and to (1-based range, e.g. from: 11, to: 20)
  • CursorPaginatedResult includes count (actual items returned in the page)
  • createCursorPaginatedResult(data, limit, cursorField, hadPrevCursor) — the new hadPrevCursor parameter correctly activates hasPrev: true when navigating forward with cursor
  • createMultiCursor(entity, fields[]) — creates composite cursors by multiple fields for stable ordering (e.g. { createdAt, id })
  • decodeMultiCursor(cursor) — decodes a multi-field cursor back to an object
  • paginate<T>(data, total, page, limit) — builds { data, meta } in one call, without instantiating PaginationHelper
  • parseCursorQuery(query, defaultLimit?, maxLimit?) — extracts cursor and limit from query params without throwing exceptions
  • PaginationHelper.parsePaginationQuery(query, defaultLimit?, maxLimit?) — equivalent for offset pagination

🔌 Express Adapter — ESM Compatibility

Section titled “🔌 Express Adapter — ESM Compatibility”

Complete rewrite of the adapter:

  • Loads Express lazily and safely using Function('return require')() for ESM compatibility without needing declare const require: any
  • Accepts a pre-created Express instance as the second constructor argument (to add your own middleware before the bridge)
  • Correct handling of raw body (Buffer) vs parsed body (JSON/urlencoded)
  • Omits the transfer-encoding header when forwarding responses (was a source of errors in Express)
  • Delegates unexpected errors to the Express error pipeline via next(err) instead of responding with 500 directly
  • ZodError cross-module: instanceof ZodError failed when the consuming app had a different Zod instance than the framework (common with bun link). Added fallback error.name === 'ZodError' to guarantee 422 responses in all cases
  • GET routes marked public returned 401: app.use() applied middleware to all methods; fixed using app.on(['POST', 'PUT', 'DELETE'], path, middleware) to restrict only write methods
  • Cache collision in MetadataCompiler: different functional handlers with the same path in different app instances shared the incorrect compiled result; fixed with unique IDs per function
  • @Cache / @UseMiddleware lost metadata: when stacked in reverse order of decorator execution, metadata could be overwritten; fixed by explicitly updating the registry in each decorator

The 422 error response now includes additional structured information:

  • field in conventional format: items[0].price instead of items.0.price
  • received — received type (when Zod reports it)
  • expected — expected type (when applicable)
  • minimum / maximum — numeric limits in range errors
{
"error": "Validation Error",
"statusCode": 422,
"details": [
{ "field": "email", "message": "Invalid email", "code": "invalid_string" },
{ "field": "age", "message": "Number must be ≥ 18", "code": "too_small", "minimum": 18 },
{ "field": "tags[1]", "message": "String must not be empty", "code": "too_small" }
]
}

None — all changes are backward compatible. The createCursorPaginatedResult signature has a new optional hadPrevCursor parameter (fourth argument, false by default).


  • JSON Response Serialization: Fixed critical bug where JSON responses were not being serialized correctly
  • CLI Version Resolution: Confirmed CLI correctly fetches and uses latest npm version
  • Application Compilation: Fixed missing await app.compile() call in generated templates
  • Version Fetching: CLI now correctly fetches latest version from npm registry
  • Template Generation: All templates now include proper await app.compile() call
  • Error Handling: Improved error handling in CLI operations

Patch release with internal build fixes. No functional changes.


  • Latest Version Fetching: CLI now automatically fetches the latest VeloceTS version from npm registry
  • Improved Error Handling: Better error messages and cleanup on project creation failure
  • Type Safety: Fixed TypeScript errors in CLI with proper type definitions for npm registry API
  • Better User Experience: Enhanced progress messages and visual feedback during project creation
  • Robust Fallbacks: Multiple fallback strategies for version detection when npm is unavailable
  • npm Registry Integration: Fixed CLI to use correct npm registry endpoint
  • Template Compilation: All generated templates include mandatory await app.compile() call

  • In-Memory Cache Store: Fast LRU-based caching with automatic cleanup
  • Redis Cache Store: Distributed caching support for multi-instance deployments
  • @Cache() Decorator: Declarative response caching with flexible TTL configuration
  • @CacheInvalidate() Decorator: Pattern-based cache invalidation for mutations
  • TTL Support: Flexible time-to-live with string format ('5m', '1h', '1d') or seconds
  • Pattern Invalidation: Wildcard pattern matching for cache invalidation ('products:*')
  • Cache Headers: Automatic X-Cache headers (HIT/MISS) in responses
@Get('/products')
@Cache({ ttl: '5m', key: 'products:list' })
async getProducts() {
return await db.products.findAll();
}
@Post('/products')
@CacheInvalidate('products:*')
async createProduct(@Body(ProductSchema) data: any) {
return await db.products.create(data);
}
  • Automatic Request IDs: UUID generation for every request
  • @RequestId() Decorator: Inject request ID into controller methods
  • @AbortSignal() Decorator: Request cancellation support for long-running operations
  • Request Timeouts: Configurable timeouts per route or globally
  • X-Request-ID header: Automatic header in all responses
@Get('/data')
async getData(
@RequestId() requestId: string,
@AbortSignal() signal: AbortSignal
) {
logger.info({ requestId }, 'Processing request');
return await longRunningQuery(signal);
}
  • Request Context Integration: Automatic request ID in all log entries
  • Child Loggers: Enhanced contextual logging with inheritance
  • Structured Logging: JSON-formatted logs for production
  • Pretty Printing: Human-readable logs for development
  • createRequestContextMiddleware(): Initialize request context with ID, timeout, and logging
  • createSimpleRequestIdMiddleware(): Minimal request ID middleware
  • createCacheMiddleware(): Functional API route caching
  • createCacheInvalidationMiddleware(): Functional API cache invalidation

None — all changes are additive and backward compatible.


  • Query Export: Added missing Query export from main index to resolve import conflicts
  • Parameter Decorators: HTTP @Query decorator now properly exported alongside GraphQL decorators
  • Import Resolution: Fixed “Export named ‘Query’ not found” error in applications
  • GraphQL Query Conflict: Removed conflicting alias Query from GraphQL decorators
  • Import Resolution: GraphQL decorators now use GQLQuery to avoid conflicts with HTTP @Query decorator
  • Type Safety: Eliminated TypeScript errors caused by decorator name conflicts
  • GraphQL queries now use @GQLQuery instead of @Query to avoid conflicts with HTTP parameter decorator
  • Query Decorator: Fixed @Query decorator to properly handle parameters without schemas
  • Query Parameter Extraction: Improved query parameter handling in router compiler
  • Validation: Added proper validation for query parameters with optional Zod schemas
  • Error Handling: Fixed missing ValidationError import, now using BadRequestException
  • Query Decorator Flexibility: @Query now supports multiple usage patterns:
    • @Query() - Extract all query parameters
    • @Query('param') - Extract specific parameter
    • @Query(Schema) - Validate with Zod schema
  • Router Compiler: Enhanced parameter extraction and validation logic
  • Type Safety: Better TypeScript support for query parameter handling
  • None
  • WebSocket Exports: Fixed missing WebSocket decorator export from WebSocket module
  • Import Resolution: WebSocket decorators now properly exported from veloce-ts/websocket
  • GraphQL Decorators: Added missing Query, Mutation, and Subscription aliases for GraphQL decorators
  • Import Conflicts: Fixed naming conflicts between params and GraphQL decorators
  • GraphQL Aliases: More intuitive names for GraphQL decorators:
    • @GQLQuery@Query (GraphQL)
    • @GQLMutation@Mutation (GraphQL)
    • @GQLSubscription@Subscription (GraphQL)
  • CLI Version Resolution: Fixed CLI template to always use latest compatible version
  • Package Generation: Improved package.json generation in CLI
  • Major Feature Release: Complete rewrite with enhanced functionality
  • Authentication System: JWT-based authentication with refresh tokens
  • Role-Based Access Control (RBAC): Hierarchical roles and permissions
  • GraphQL Support: Full GraphQL integration with schema generation
  • WebSocket Support: Real-time communication capabilities
  • SQLite Integration: Built-in database support
  • OpenAPI Documentation: Automatic API documentation generation
  • CLI Tool: Project scaffolding and code generation
  • Dependency Injection: Advanced DI container with scopes
  • Middleware System: Custom middleware support
  • Validation Engine: Zod-based request validation
  • Error Handling: Comprehensive error handling system
  • Type Safety: Improved TypeScript support throughout
  • Performance: Optimized routing and request handling
  • Developer Experience: Better debugging and development tools
  • Complete API redesign from v0.1.x
  • New decorator syntax and patterns
  • Updated project structure
  • Minor bug fixes and improvements
  • Basic decorator support
  • Simple routing system
  • Initial framework structure
  • Core application class
  • Project setup and configuration
  • Basic TypeScript support
  • Initial package configuration
  • Package metadata and basic structure
  • Initial release
  • Basic framework structure
  • Package setup

:::tip Latest Version We recommend always using the latest version of Veloce-TS for the best experience and latest features. :::

:::note Breaking Changes Breaking changes are clearly marked in each release. Please review the changelog before upgrading to a new major version. :::