express-version-api 2.0.4 → 2.0.6

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +157 -78
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.0.4] - 2026-02-27
11
+
12
+ ### Added
13
+
14
+ - Added `jsr.json` configuration and JSR package metadata.
15
+ - Added JSR publication support for `@braian-quintian/express-version-api`.
16
+
17
+ ### Changed
18
+
19
+ - Updated repository documentation to match the current runtime behavior and exports.
20
+ - Hardened release automation to validate npm authentication before publish.
21
+
22
+ ### Fixed
23
+
24
+ - Fixed `.npmrc` token interpolation to use `NODE_AUTH_TOKEN` in CI.
25
+ - Fixed GitHub Packages publication flow by using scoped package publish in workflow.
26
+
27
+ ## [2.0.3] - 2026-02-27
28
+
29
+ ### Changed
30
+
31
+ - Updated release workflow with explicit npm authentication verification.
32
+
10
33
  ## [2.0.0] - 2026-02-27
11
34
 
12
35
  ### Removed
package/README.md CHANGED
@@ -5,14 +5,30 @@
5
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
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
7
7
 
8
- Version-aware middleware for Express.js with semantic version matching.
8
+ Version-aware middleware for Express.js APIs with semantic version matching.
9
+
10
+ ## Why use this
11
+
12
+ - Routes requests by semantic version (`exact`, `~`, `^`).
13
+ - Supports extraction from header, query, path, or custom function.
14
+ - Handles missing or unmatched versions with configurable fallback strategies.
15
+ - Exposes `req.versionInfo` metadata for observability and debugging.
16
+ - Fully typed for TypeScript projects.
9
17
 
10
18
  ## Installation
11
19
 
20
+ ### npm
21
+
12
22
  ```bash
13
23
  npm install express-version-api
14
24
  ```
15
25
 
26
+ ### JSR
27
+
28
+ ```bash
29
+ deno add jsr:@braian-quintian/express-version-api
30
+ ```
31
+
16
32
  Requirements:
17
33
 
18
34
  - Node.js >= 18
@@ -26,71 +42,82 @@ import { versioningMiddleware } from 'express-version-api';
26
42
 
27
43
  const app = express();
28
44
 
29
- app.use(
30
- '/api',
45
+ app.get(
46
+ '/api/users',
31
47
  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
- },
48
+ '^1': (_req, res) => res.json({ version: '1.x', users: [] }),
49
+ '^2': (_req, res) => res.json({ version: '2.x', users: [], meta: { total: 0 } }),
50
+ '3.0.0': (_req, res) => res.json({ version: '3.0.0', users: [], paging: null }),
41
51
  })
42
52
  );
53
+
54
+ app.use((error, _req, res, _next) => {
55
+ res.status(500).json({ error: error.message });
56
+ });
43
57
  ```
44
58
 
45
59
  Request examples:
46
60
 
47
61
  ```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
62
+ curl -H "Accept-Version: 1.2.0" http://localhost:3000/api/users
63
+ curl -H "Accept-Version: 2.5.1" http://localhost:3000/api/users
64
+ curl -H "Accept-Version: 3.0.0" http://localhost:3000/api/users
51
65
  ```
52
66
 
53
67
  ## Import Modes
54
68
 
55
- ESM:
69
+ ESM (default + named):
56
70
 
57
71
  ```ts
58
72
  import versioningMiddleware, { parseVersion } from 'express-version-api';
59
73
  ```
60
74
 
61
- CommonJS:
75
+ CommonJS (named only):
62
76
 
63
77
  ```js
64
78
  const { versioningMiddleware, parseVersion } = require('express-version-api');
65
79
  ```
66
80
 
67
- ## Matching Rules
81
+ ## Version Matching Rules
68
82
 
69
83
  Supported handler keys:
70
84
 
71
85
  - Exact: `1.2.3`
72
- - Caret: `^1.2.3`
73
- - Tilde: `~1.2.3`
86
+ - Caret: `^1`, `^1.2`, `^1.2.3`
87
+ - Tilde: `~1.2`, `~1.2.3`
74
88
 
75
- Priority when multiple handlers match:
89
+ Matching priority when multiple handlers match:
76
90
 
77
91
  1. Exact
78
92
  2. Tilde
79
93
  3. Caret
80
94
 
81
- Notes:
95
+ Semantics:
96
+
97
+ - Exact: must match the same `major.minor.patch`.
98
+ - Tilde (`~`): same major and minor, patch must be `>=` requested patch.
99
+ - Caret (`^`): semver-compatible range.
100
+ - Caret with `0.x` follows strict semver-compatible behavior.
82
101
 
83
- - Caret behavior for `0.x` follows semver-compatible constraints.
84
- - Versions like `1`, `1.2`, and `1.2.3` are accepted.
102
+ Examples:
85
103
 
86
- ## Version Extraction
104
+ - `^1.2.3` matches `1.2.3`, `1.3.0`, `1.9.9`, but not `2.0.0`.
105
+ - `^0.2.3` matches `0.2.3` to `0.2.x`, but not `0.3.0`.
106
+ - `~2.1.4` matches `2.1.4` to `2.1.x`, but not `2.2.0`.
87
107
 
88
- Default extraction order:
108
+ ## How Version Extraction Works
109
+
110
+ The middleware resolves version in this order:
111
+
112
+ 1. `req.version` if already set by upstream middleware (source = `custom`)
113
+ 2. Configured extraction sources in order (`extraction.sources`)
114
+
115
+ Default source order:
89
116
 
90
117
  1. Header: `accept-version`
91
118
  2. Query: `v`
92
119
 
93
- You can configure `header`, `query`, `path`, or `custom` sources.
120
+ You can configure `header`, `query`, `path`, and `custom` extractors.
94
121
 
95
122
  ```ts
96
123
  versioningMiddleware(
@@ -110,57 +137,26 @@ versioningMiddleware(
110
137
  );
111
138
  ```
112
139
 
113
- ## Configuration
140
+ ## Fallback Strategies
114
141
 
115
- Defaults:
142
+ Fallback is used when no handler matches, and also when version is missing with `requireVersion: false`.
116
143
 
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'`
144
+ - `none`: respond with `VERSION_NOT_FOUND`.
145
+ - `latest`: execute the handler with the highest available version.
146
+ - `default`: execute `defaultHandler` if provided, otherwise fallback to `latest`.
124
147
 
125
148
  ```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
- }
149
+ versioningMiddleware(handlers, {
150
+ fallbackStrategy: 'default',
151
+ defaultHandler: (_req, res) => {
152
+ res.status(200).json({ fallback: true });
153
+ },
154
+ });
153
155
  ```
154
156
 
155
- ## Fallback Strategies
156
-
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`.
160
-
161
157
  ## Error Handling
162
158
 
163
- Error codes:
159
+ Error codes emitted by the middleware:
164
160
 
165
161
  - `MISSING_VERSION`
166
162
  - `INVALID_VERSION_FORMAT`
@@ -168,7 +164,13 @@ Error codes:
168
164
  - `INVALID_CONFIGURATION`
169
165
  - `INVALID_HANDLER`
170
166
 
171
- Default error response shape:
167
+ Default status codes:
168
+
169
+ - Missing version: `422`
170
+ - Version not found: `422`
171
+ - Invalid version format: `400`
172
+
173
+ Default response shape:
172
174
 
173
175
  ```json
174
176
  {
@@ -179,9 +181,28 @@ Default error response shape:
179
181
  }
180
182
  ```
181
183
 
182
- ## Version Info Metadata
184
+ Configure custom messages/statuses and override handling via `onError`:
183
185
 
184
- When `attachVersionInfo` is enabled, the middleware sets `req.versionInfo`:
186
+ ```ts
187
+ versioningMiddleware(handlers, {
188
+ errorResponse: {
189
+ missingVersionStatus: 400,
190
+ missingVersionMessage: 'Version header is required',
191
+ versionNotFoundMessage: (version) => `Version ${version} is not supported`,
192
+ onError: (error, _req, res) => {
193
+ if (error.code === 'INVALID_VERSION_FORMAT') {
194
+ res.status(400).json({ code: error.code, detail: error.message });
195
+ return true;
196
+ }
197
+ return false;
198
+ },
199
+ },
200
+ });
201
+ ```
202
+
203
+ ## Request Metadata (`req.versionInfo`)
204
+
205
+ When `attachVersionInfo` is `true`, the middleware adds:
185
206
 
186
207
  ```ts
187
208
  {
@@ -191,11 +212,57 @@ When `attachVersionInfo` is enabled, the middleware sets `req.versionInfo`:
191
212
  }
192
213
  ```
193
214
 
194
- ## API
215
+ Notes:
216
+
217
+ - `source` preserves the real extraction source, including fallback scenarios.
218
+ - When no version was provided and fallback is used, `versionInfo` is not attached because `requested` is undefined.
219
+
220
+ ## Runtime Defaults
195
221
 
196
- Main exports:
222
+ ```ts
223
+ {
224
+ extraction: {
225
+ sources: ['header', 'query'],
226
+ header: { name: 'accept-version' },
227
+ query: { name: 'v' },
228
+ path: { pattern: /\/v(\d+(?:\.\d+)?(?:\.\d+)?)\// },
229
+ custom: undefined
230
+ },
231
+ errorResponse: {
232
+ missingVersionStatus: 422,
233
+ versionNotFoundStatus: 422,
234
+ missingVersionMessage: 'API version is required',
235
+ versionNotFoundMessage: 'No handler found for the requested API version',
236
+ includeRequestedVersion: true,
237
+ onError: undefined
238
+ },
239
+ fallbackStrategy: 'default',
240
+ defaultHandler: undefined,
241
+ validateHandlers: true,
242
+ attachVersionInfo: true,
243
+ requireVersion: true
244
+ }
245
+ ```
246
+
247
+ ## Public API
248
+
249
+ Main middleware:
197
250
 
198
251
  - `versioningMiddleware`
252
+
253
+ Error helpers:
254
+
255
+ - `VersioningError`
256
+ - `createMissingVersionError`
257
+ - `createVersionNotFoundError`
258
+ - `createInvalidVersionFormatError`
259
+ - `createInvalidHandlerError`
260
+ - `createInvalidConfigurationError`
261
+ - `isVersioningError`
262
+ - `hasErrorCode`
263
+
264
+ Version utilities:
265
+
199
266
  - `parseVersion`
200
267
  - `parseVersionRange`
201
268
  - `versionSatisfies`
@@ -204,13 +271,15 @@ Main exports:
204
271
  - `isValidVersion`
205
272
  - `isValidVersionRange`
206
273
  - `normalizeVersion`
207
- - `VersioningError`
274
+
275
+ Config export:
276
+
208
277
  - `DEFAULT_CONFIG`
209
278
 
210
- ## Breaking Changes (v2.0.0)
279
+ ## Breaking Changes (v2)
211
280
 
212
281
  - Removed legacy `createVersionMiddleware` API.
213
- - CommonJS consumers must use named exports (no default export in CJS).
282
+ - CommonJS default export was removed; CJS must use named imports.
214
283
 
215
284
  ## Development
216
285
 
@@ -219,6 +288,16 @@ npm install
219
288
  npm run validate
220
289
  ```
221
290
 
291
+ Main scripts:
292
+
293
+ - `npm run typecheck`
294
+ - `npm run lint`
295
+ - `npm run format:check`
296
+ - `npm run test`
297
+ - `npm run test:coverage`
298
+ - `npm run build`
299
+ - `npm run test:types`
300
+
222
301
  ## License
223
302
 
224
303
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-version-api",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "description": "Middleware for versioning routes/APIs in Express.js using semantic versioning like ^1.0 or ~1.2.",
5
5
  "author": "Braian Quintian <bquintian.developer@gmail.com>",
6
6
  "license": "MIT",