express-version-api 1.0.6 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,40 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [2.0.0] - 2026-02-27
11
+
12
+ ### Removed
13
+
14
+ - Removed deprecated `createVersionMiddleware` API.
15
+ - Removed CommonJS default export path; CJS now uses named exports only.
16
+
17
+ ### Changed
18
+
19
+ - `test:types` now validates `test-types/**/*.test-d.ts` and runs in `validate`/CI.
20
+ - CI now targets `develop` and `main`, and PR checks use the actual base branch.
21
+ - `npm test` no longer writes coverage artifacts by default.
22
+ - Pre-commit hook now runs `lint-staged`.
23
+ - TypeScript incremental metadata moved outside publish output.
24
+ - Removed unused dev dependencies: `@types/semver`, `ts-node`.
25
+ - Updated README and package docs to match runtime behavior.
26
+
27
+ ### Fixed
28
+
29
+ - `fallbackStrategy` is now validated at config resolution.
30
+ - Async `defaultHandler` errors are forwarded to Express `next(error)`.
31
+ - Caret matching for `0.x` follows semver-compatible constraints.
32
+ - `missingVersionMessage` from config is now applied in responses.
33
+ - Path extraction is stable with global/sticky regex (`lastIndex` handling).
34
+ - `req.versionInfo.source` now preserves the original extraction source in fallback paths.
35
+
36
+ ## [1.0.6] - 2025-02-01
37
+
38
+ ### Added
39
+
40
+ - Stable baseline release published to npm.
package/README.md CHANGED
@@ -1,162 +1,224 @@
1
- # 📦 express-version-api
1
+ # express-version-api
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/express-version-api.svg)](https://www.npmjs.com/package/express-version-api)
4
- [![Build Status](https://img.shields.io/github/actions/workflow/status/Braian-Quintian/express-version-api/test.yml)](https://github.com/Braian-Quintian/express-version-api/actions)
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](./LICENSE)
6
- [![Coverage Status](https://img.shields.io/codecov/c/github/Braian-Quintian/express-version-api)](https://codecov.io/gh/Braian-Quintian/express-version-api)
7
- [![Node.js](https://img.shields.io/badge/node-%3E=14.0.0-brightgreen)](https://nodejs.org)
4
+ [![npm downloads](https://img.shields.io/npm/dm/express-version-api.svg)](https://www.npmjs.com/package/express-version-api)
5
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/Braian-Quintian/express-version-api/ci.yml?branch=develop)](https://github.com/Braian-Quintian/express-version-api/actions)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
8
7
 
9
- > Versioned routing middleware for Express.js based on semantic versioning (`semver`).
8
+ Version-aware middleware for Express.js with semantic version matching.
10
9
 
11
- ---
12
-
13
- **⚠️ NOTE:** This package is intended for personal use and experimentation. It is **not recommended** for production use.
14
-
15
- ---
16
-
17
- ## 🚧 Project Status
18
-
19
- This library is under **active development**. Features and improvements are being added frequently. Use at your own discretion in unstable environments.
20
-
21
- ---
22
-
23
- ## ✨ Features
24
-
25
- - ✅ Version-based routing (`^`, `~`, exact versions)
26
- - ✅ Automatic fallback to default or latest version
27
- - ✅ Fully compatible with Express middleware
28
- - ✅ Well-tested with Jest and Supertest
29
-
30
- ---
31
-
32
- ## 📦 Installation
10
+ ## Installation
33
11
 
34
12
  ```bash
35
13
  npm install express-version-api
36
14
  ```
37
15
 
38
- ---
16
+ Requirements:
39
17
 
40
- ## 🚀 Quick Usage
18
+ - Node.js >= 18
19
+ - Express >= 4
41
20
 
42
- ```js
43
- const express = require("express");
44
- const versionApi = require("express-version-api");
45
- const app = express();
21
+ ## Quick Start
46
22
 
47
- const handlerV1 = (req, res) => res.send("This is version 1.0.0");
48
- const handlerV2 = (req, res) => res.send("This is version 2.0.0");
23
+ ```ts
24
+ import express from 'express';
25
+ import { versioningMiddleware } from 'express-version-api';
49
26
 
50
- app.get(
51
- "/api",
52
- versionApi({
53
- "1.0.0": handlerV1,
54
- "2.0.0": handlerV2,
27
+ const app = express();
28
+
29
+ app.use(
30
+ '/api',
31
+ versioningMiddleware({
32
+ '^1': (_req, res) => {
33
+ res.json({ version: '1.x' });
34
+ },
35
+ '^2': (_req, res) => {
36
+ res.json({ version: '2.x' });
37
+ },
38
+ '3.0.0': (_req, res) => {
39
+ res.json({ version: '3.0.0' });
40
+ },
55
41
  })
56
42
  );
43
+ ```
57
44
 
58
- app.listen(3000, () => {
59
- console.log("Server running on port 3000");
60
- });
45
+ Request examples:
46
+
47
+ ```bash
48
+ curl -H "Accept-Version: 1.2.0" http://localhost:3000/api
49
+ curl -H "Accept-Version: 2.5.1" http://localhost:3000/api
50
+ curl -H "Accept-Version: 3.0.0" http://localhost:3000/api
61
51
  ```
62
52
 
63
- ---
53
+ ## Import Modes
64
54
 
65
- ## 🎯 Semver Support (`^`, `~`)
55
+ ESM:
56
+
57
+ ```ts
58
+ import versioningMiddleware, { parseVersion } from 'express-version-api';
59
+ ```
66
60
 
67
- | Symbol | Matches | Example Matches |
68
- | ------ | -------------------------- | ------------------ |
69
- | `^` | Major-compatible (`1.x.x`) | `^1.0.0` → `1.2.3` |
70
- | `~` | Minor-compatible (`2.1.x`) | `~2.1.0` → `2.1.4` |
71
- | Exact | Exact version only | `3.0.0` → `3.0.0` |
61
+ CommonJS:
72
62
 
73
63
  ```js
74
- app.get(
75
- "/api",
76
- versionApi({
77
- "^1.0.0": handlerV1,
78
- "~2.1.0": handlerV2,
79
- "3.0.0": handlerV3,
80
- })
81
- );
64
+ const { versioningMiddleware, parseVersion } = require('express-version-api');
82
65
  ```
83
66
 
84
- ---
67
+ ## Matching Rules
85
68
 
86
- ## 📥 Version Header
69
+ Supported handler keys:
87
70
 
88
- Clients should include the `Accept-Version` HTTP header in requests:
71
+ - Exact: `1.2.3`
72
+ - Caret: `^1.2.3`
73
+ - Tilde: `~1.2.3`
89
74
 
90
- ```bash
91
- curl -H "Accept-Version: 1.0.0" http://localhost:3000/api
92
- ```
75
+ Priority when multiple handlers match:
93
76
 
94
- ---
77
+ 1. Exact
78
+ 2. Tilde
79
+ 3. Caret
95
80
 
96
- ## 🧪 Running Tests
81
+ Notes:
97
82
 
98
- ```bash
99
- npm run test
100
- ```
101
-
102
- Tests are powered by [Jest](https://jestjs.io/) and [Supertest](https://github.com/visionmedia/supertest). Full coverage is included.
83
+ - Caret behavior for `0.x` follows semver-compatible constraints.
84
+ - Versions like `1`, `1.2`, and `1.2.3` are accepted.
103
85
 
104
- ---
86
+ ## Version Extraction
105
87
 
106
- ## 🧩 API
88
+ Default extraction order:
107
89
 
108
- ### `versionApi(handlers, defaultHandler?)`
90
+ 1. Header: `accept-version`
91
+ 2. Query: `v`
109
92
 
110
- - `handlers`: Object with semver-style version strings as keys and Express handlers as values.
111
- - `defaultHandler`: Optional fallback if no version matches.
93
+ You can configure `header`, `query`, `path`, or `custom` sources.
112
94
 
113
- ```js
114
- app.get(
115
- "/api",
116
- versionApi({
117
- "^1.0.0": v1Handler,
118
- "~2.0.0": v2Handler,
119
- "3.0.0": v3Handler,
120
- }, fallbackHandler)
95
+ ```ts
96
+ versioningMiddleware(
97
+ {
98
+ '^1': v1Handler,
99
+ '^2': v2Handler,
100
+ },
101
+ {
102
+ extraction: {
103
+ sources: ['header', 'query', 'path', 'custom'],
104
+ header: { name: 'x-api-version' },
105
+ query: { name: 'version' },
106
+ path: { pattern: /\/api\/v(\d+(?:\.\d+)?(?:\.\d+)?)\// },
107
+ custom: (req) => (req.hostname.startsWith('v2.') ? '2.0.0' : undefined),
108
+ },
109
+ }
121
110
  );
122
111
  ```
123
112
 
124
- ---
113
+ ## Configuration
114
+
115
+ Defaults:
116
+
117
+ - `requireVersion: true`
118
+ - `fallbackStrategy: 'default'`
119
+ - `attachVersionInfo: true`
120
+ - `validateHandlers: true`
121
+ - `errorResponse.missingVersionStatus: 422`
122
+ - `errorResponse.versionNotFoundStatus: 422`
123
+ - `errorResponse.missingVersionMessage: 'API version is required'`
124
+
125
+ ```ts
126
+ interface VersioningOptions {
127
+ extraction?: {
128
+ sources?: Array<'header' | 'query' | 'path' | 'custom'>;
129
+ header?: { name?: string };
130
+ query?: { name?: string };
131
+ path?: { pattern?: RegExp };
132
+ custom?: (req: Request) => string | undefined;
133
+ };
134
+ requireVersion?: boolean;
135
+ fallbackStrategy?: 'latest' | 'none' | 'default';
136
+ defaultHandler?: RequestHandler;
137
+ validateHandlers?: boolean;
138
+ attachVersionInfo?: boolean;
139
+ errorResponse?: {
140
+ missingVersionStatus?: number;
141
+ versionNotFoundStatus?: number;
142
+ missingVersionMessage?: string;
143
+ versionNotFoundMessage?: string | ((version: string) => string);
144
+ includeRequestedVersion?: boolean;
145
+ onError?: (
146
+ error: VersioningError,
147
+ req: Request,
148
+ res: Response,
149
+ next: NextFunction
150
+ ) => boolean | undefined;
151
+ };
152
+ }
153
+ ```
125
154
 
126
- ## 🔄 Fallback Strategy
155
+ ## Fallback Strategies
127
156
 
128
- If the version is not matched:
157
+ - `none`: return `VERSION_NOT_FOUND` error.
158
+ - `latest`: execute the highest available version handler.
159
+ - `default`: execute `defaultHandler` when provided; otherwise falls back to `latest`.
129
160
 
130
- 1. Use `defaultHandler` if defined
131
- 2. Otherwise, fallback to the latest available handler
132
- 3. If no handler matches, return `422 Unprocessable Entity`
161
+ ## Error Handling
133
162
 
134
- ---
163
+ Error codes:
135
164
 
136
- ## 📚 Examples
165
+ - `MISSING_VERSION`
166
+ - `INVALID_VERSION_FORMAT`
167
+ - `VERSION_NOT_FOUND`
168
+ - `INVALID_CONFIGURATION`
169
+ - `INVALID_HANDLER`
137
170
 
138
- Check the `test/` directory for integration examples and how `^`, `~` and fallbacks work in practice.
171
+ Default error response shape:
139
172
 
140
- ---
173
+ ```json
174
+ {
175
+ "error": "VERSION_NOT_FOUND",
176
+ "message": "No handler found for the requested API version",
177
+ "requestedVersion": "99.0.0",
178
+ "availableVersions": ["^1", "^2"]
179
+ }
180
+ ```
181
+
182
+ ## Version Info Metadata
183
+
184
+ When `attachVersionInfo` is enabled, the middleware sets `req.versionInfo`:
185
+
186
+ ```ts
187
+ {
188
+ requested: string;
189
+ matched: string;
190
+ source: 'header' | 'query' | 'path' | 'custom';
191
+ }
192
+ ```
193
+
194
+ ## API
141
195
 
142
- ## 🛣️ Roadmap
196
+ Main exports:
143
197
 
144
- - [x] Basic versioning with `^`, `~`, exact
145
- - [x] Default and latest fallback
146
- - [ ] Advanced semver range support (planned)
147
- - [ ] Improved validation and DX
148
- - [ ] Full ESM and CJS dual package
149
- - [ ] Typed handler inference with TypeScript
198
+ - `versioningMiddleware`
199
+ - `parseVersion`
200
+ - `parseVersionRange`
201
+ - `versionSatisfies`
202
+ - `compareVersions`
203
+ - `findLatestVersion`
204
+ - `isValidVersion`
205
+ - `isValidVersionRange`
206
+ - `normalizeVersion`
207
+ - `VersioningError`
208
+ - `DEFAULT_CONFIG`
150
209
 
151
- ---
210
+ ## Breaking Changes (v2.0.0)
152
211
 
153
- ## 🤝 Contributing
212
+ - Removed legacy `createVersionMiddleware` API.
213
+ - CommonJS consumers must use named exports (no default export in CJS).
154
214
 
155
- Contributions, issues, and feature requests are welcome!
156
- Contact: [bquintian.developer@gmail.com](mailto:bquintian.developer@gmail.com)
215
+ ## Development
157
216
 
158
- ---
217
+ ```bash
218
+ npm install
219
+ npm run validate
220
+ ```
159
221
 
160
- ## 🛡 License
222
+ ## License
161
223
 
162
- This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
224
+ MIT