@salespark/route-utils 1.0.0
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/README.md +217 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +232 -0
- package/dist/index.js.map +1 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# SalesPark Route Utils v1 - Documentation
|
|
2
|
+
|
|
3
|
+
## @salespark/route-utils
|
|
4
|
+
|
|
5
|
+
Vendor-agnostic helpers for **Express.js** routes.
|
|
6
|
+
Provides a unified way to wrap async route handlers, normalize responses, and handle logging without binding to a specific vendor (e.g., Rollbar, Sentry, Console).
|
|
7
|
+
|
|
8
|
+
By default, if no logger is provided, **no logs are emitted** (silent mode).
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 📦 Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @salespark/route-utils
|
|
16
|
+
# or
|
|
17
|
+
yarn add @salespark/route-utils
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Supports both **CommonJS** and **ESM** imports.
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
// ESM
|
|
24
|
+
import { wrapRoute, createResponder, makeRouteUtils, resolveRouteResponse } from "@salespark/route-utils";
|
|
25
|
+
|
|
26
|
+
// CommonJS
|
|
27
|
+
const { wrapRoute, createResponder, makeRouteUtils, resolveRouteResponse } = require("@salespark/route-utils");
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 🚀 Introduction
|
|
33
|
+
|
|
34
|
+
This utility reduces boilerplate in Express.js routes by enforcing:
|
|
35
|
+
|
|
36
|
+
- Consistent response shape across all endpoints
|
|
37
|
+
- Safe error handling with `try/catch` wrappers
|
|
38
|
+
- Prevention of double responses (`res.headersSent`)
|
|
39
|
+
- Configurable vendor-agnostic logging (console, Rollbar, Sentry, etc.)
|
|
40
|
+
- Predictable HTTP status codes for both success and error cases
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 📐 Response Shape Specification
|
|
45
|
+
|
|
46
|
+
All route handlers must return an object with the following structure:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
{
|
|
50
|
+
status: boolean; // required: true for success, false for failure
|
|
51
|
+
data?: any; // optional: payload for success or error
|
|
52
|
+
http?: number; // optional: explicit HTTP status code
|
|
53
|
+
headers?: Record<string,any>;// optional: extra HTTP headers to set
|
|
54
|
+
meta?: any; // optional: metadata (e.g., pagination info)
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Status Rules
|
|
59
|
+
|
|
60
|
+
- ✅ `status: true` → Success
|
|
61
|
+
- ❌ `status: false` → Failure
|
|
62
|
+
- 🚨 Missing `status` → treated as malformed response (`500` with `MissingStatus`)
|
|
63
|
+
|
|
64
|
+
### Default HTTP Mapping
|
|
65
|
+
|
|
66
|
+
- Success with data → `200 OK`
|
|
67
|
+
- Success without data (`null`, `undefined`, `""`) → `204 No Content`
|
|
68
|
+
- Failure → `400 Bad Request`
|
|
69
|
+
- Explicit `http` value (100–599) always overrides
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 🏗️ Factory: `makeRouteUtils`
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { makeRouteUtils } from "@salespark/route-utils";
|
|
77
|
+
|
|
78
|
+
const { wrapRoute, createResponder, resolveRouteResponse } = makeRouteUtils({
|
|
79
|
+
logger: console.error, // or rollbar.error, sentry.captureException, etc.
|
|
80
|
+
tagPrefix: "/routes/producers", // optional prefix for logs
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Parameters
|
|
85
|
+
|
|
86
|
+
- **`logger`**: `(payload, tag) => void`
|
|
87
|
+
- **`tagPrefix`**: string (optional)
|
|
88
|
+
|
|
89
|
+
### Returns
|
|
90
|
+
|
|
91
|
+
- `wrapRoute`
|
|
92
|
+
- `createResponder`
|
|
93
|
+
- `resolveRouteResponse`
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## ⚡ Functions
|
|
98
|
+
|
|
99
|
+
### `wrapRoute`
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
router.get(
|
|
103
|
+
"/achievements",
|
|
104
|
+
validateAuth,
|
|
105
|
+
wrapRoute(
|
|
106
|
+
async (req, res) => {
|
|
107
|
+
const producerId = res.locals.auth.producer_id;
|
|
108
|
+
return ops.getProducerAchievements(producerId);
|
|
109
|
+
},
|
|
110
|
+
{ tag: "GET /achievements" }
|
|
111
|
+
)
|
|
112
|
+
);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
### `createResponder`
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
router.get("/achievements", validateAuth, async (req, res) => {
|
|
121
|
+
const respond = createResponder(res, { tag: "GET /achievements" });
|
|
122
|
+
await respond(() => ops.getProducerAchievements(res.locals.auth.producer_id));
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### `resolveRouteResponse`
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
const response = await ops.doSomething();
|
|
132
|
+
if (!resolveRouteResponse(res, response)) {
|
|
133
|
+
res.status(500).json({ status: false, error: "No response sent" });
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 🧪 Usage Examples
|
|
140
|
+
|
|
141
|
+
### Example 1: Silent Mode (default)
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
app.get(
|
|
145
|
+
"/ping",
|
|
146
|
+
wrapRoute(async () => ({ status: true, data: "pong" }))
|
|
147
|
+
);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Example 2: With Console Logger
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
const { wrapRoute } = makeRouteUtils({
|
|
154
|
+
logger: (payload, tag) => console.log("[LOG]", tag, payload),
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Example 3: With Rollbar
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
const rollbar = require("./rollbar");
|
|
162
|
+
|
|
163
|
+
const { wrapRoute } = makeRouteUtils({
|
|
164
|
+
logger: rollbar.error.bind(rollbar),
|
|
165
|
+
tagPrefix: "[API] ",
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Example 4: POST with Validation
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
app.post(
|
|
173
|
+
"/items",
|
|
174
|
+
wrapRoute(async (req) => {
|
|
175
|
+
if (!req.body.name) {
|
|
176
|
+
return { status: false, data: { error: "ValidationError", message: "Name required" }, http: 422 };
|
|
177
|
+
}
|
|
178
|
+
return { status: true, data: { id: 1, name: req.body.name }, http: 201 };
|
|
179
|
+
})
|
|
180
|
+
);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Example 5: Using Sentry
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import * as Sentry from "@sentry/node";
|
|
187
|
+
|
|
188
|
+
Sentry.init({ dsn: process.env.SENTRY_DSN });
|
|
189
|
+
|
|
190
|
+
const { wrapRoute } = makeRouteUtils({
|
|
191
|
+
logger: (payload, tag) => {
|
|
192
|
+
Sentry.captureException(payload instanceof Error ? payload : new Error(JSON.stringify(payload)));
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## 📦 NPM Package
|
|
200
|
+
|
|
201
|
+
This module is published as:
|
|
202
|
+
👉 [`@salespark/route-utils`](https://www.npmjs.com/package/@salespark/route-utils)
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
npm install @salespark/route-utils
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 📄 License
|
|
211
|
+
|
|
212
|
+
MIT © [SalesPark](https://salespark.io)
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
_Document version: 1_
|
|
217
|
+
_Last update: 16-08-2025_
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/****************************************************************************************************************
|
|
2
|
+
* ##: Route Utils (TypeScript)
|
|
3
|
+
* Vendor-agnostic helpers for Express-like route handlers.
|
|
4
|
+
*
|
|
5
|
+
* What you get:
|
|
6
|
+
* - Normalized responses: { status:boolean, data?, http?, headers?, meta? }
|
|
7
|
+
* - Safe guards against double responses (res.headersSent)
|
|
8
|
+
* - No vendor lock-in for logging (optional logger function, silent by default)
|
|
9
|
+
* - Two ergonomics:
|
|
10
|
+
* a) wrapRoute(handler, { tag?, logger? }) -> middleware
|
|
11
|
+
* b) createResponder(res, { tag?, logger? }) -> in-route responder
|
|
12
|
+
* - Core primitive: resolveRouteResponse(res, response) -> boolean
|
|
13
|
+
*
|
|
14
|
+
* Logging:
|
|
15
|
+
* - Provide a function logger(payload, tag?) if you want logs (e.g. rollbar.error.bind(rollbar))
|
|
16
|
+
* - If omitted, nothing is logged (silent mode)
|
|
17
|
+
*
|
|
18
|
+
* History:
|
|
19
|
+
* 16-08-2025: Initial version
|
|
20
|
+
****************************************************************************************************************/
|
|
21
|
+
export type LoggerFn = (payload: unknown, tag?: unknown) => void;
|
|
22
|
+
/**
|
|
23
|
+
* Minimal response interface to avoid a hard dependency on Express types.
|
|
24
|
+
* Any Express-like object with these methods/properties is supported.
|
|
25
|
+
*/
|
|
26
|
+
export interface ResLike {
|
|
27
|
+
status: (code: number) => ResLike;
|
|
28
|
+
json: (body?: unknown) => ResLike;
|
|
29
|
+
send: (body?: unknown) => ResLike;
|
|
30
|
+
setHeader?: (name: string, value: string) => void;
|
|
31
|
+
headersSent?: boolean;
|
|
32
|
+
[key: string]: any;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Normalized API response contract used throughout the utilities.
|
|
36
|
+
* - `status` is mandatory and must be boolean.
|
|
37
|
+
* - `http` is optional and, when valid, overrides default status code mapping.
|
|
38
|
+
* - `headers` are optional additional response headers to apply.
|
|
39
|
+
*/
|
|
40
|
+
export interface ApiResponse<T = unknown, M = unknown> {
|
|
41
|
+
status: boolean;
|
|
42
|
+
data?: T;
|
|
43
|
+
http?: number;
|
|
44
|
+
headers?: Record<string, string>;
|
|
45
|
+
meta?: M;
|
|
46
|
+
}
|
|
47
|
+
/****************************************************************************************************************
|
|
48
|
+
* ##: Factory
|
|
49
|
+
* makeRouteUtils({ logger?, tagPrefix? })
|
|
50
|
+
*
|
|
51
|
+
* Creates helpers bound to provided defaults, so you can avoid passing the same logger/tag repeatedly.
|
|
52
|
+
*
|
|
53
|
+
* @param logger Optional function `(payload, tag?) => void`. If omitted, no logs are emitted.
|
|
54
|
+
* @param tagPrefix Optional prefix applied to all generated tags (e.g., a file or module path).
|
|
55
|
+
*
|
|
56
|
+
* @returns { wrapRoute, createResponder, resolveRouteResponse }
|
|
57
|
+
* History:
|
|
58
|
+
* 16-08-2025: Created
|
|
59
|
+
****************************************************************************************************************/
|
|
60
|
+
export declare const makeRouteUtils: ({ logger, tagPrefix, }?: {
|
|
61
|
+
logger?: LoggerFn | undefined;
|
|
62
|
+
tagPrefix?: string | undefined;
|
|
63
|
+
}) => {
|
|
64
|
+
wrapRoute: (handler: (req: any, res: ResLike) => Promise<ApiResponse> | ApiResponse, options?: {
|
|
65
|
+
tag?: string | undefined;
|
|
66
|
+
logger?: LoggerFn | undefined;
|
|
67
|
+
}) => (req: any, res: ResLike, _next?: any) => Promise<void>;
|
|
68
|
+
createResponder: (res: ResLike, options?: {
|
|
69
|
+
tag?: string | undefined;
|
|
70
|
+
logger?: LoggerFn | undefined;
|
|
71
|
+
}) => (workFn: () => Promise<ApiResponse> | ApiResponse) => Promise<boolean>;
|
|
72
|
+
resolveRouteResponse: (res: ResLike, response: any) => boolean;
|
|
73
|
+
};
|
|
74
|
+
/****************************************************************************************************************
|
|
75
|
+
* ##: Core Primitive - Resolve Route Response
|
|
76
|
+
* resolveRouteResponse(res, response) => boolean
|
|
77
|
+
*
|
|
78
|
+
* Normalizes and sends the HTTP response based on the ApiResponse contract:
|
|
79
|
+
* - Validates the `res` object
|
|
80
|
+
* - Prevents double responses (`headersSent`)
|
|
81
|
+
* - Applies optional headers
|
|
82
|
+
* - Chooses HTTP status code (custom `http` if valid; else 200/204/400 defaults)
|
|
83
|
+
* - Serializes success/error shapes predictably
|
|
84
|
+
*
|
|
85
|
+
* @param res Express-like response object
|
|
86
|
+
* @param response Expected ApiResponse (must include boolean `status`)
|
|
87
|
+
* @returns true if a response was sent; false if `res` looked invalid (no send)
|
|
88
|
+
* History:
|
|
89
|
+
* 16-08-2025: Created
|
|
90
|
+
****************************************************************************************************************/
|
|
91
|
+
export declare const resolveRouteResponse: (res: ResLike, response: any) => boolean;
|
|
92
|
+
export declare const wrapRoute: (handler: (req: any, res: ResLike) => Promise<ApiResponse> | ApiResponse, options?: {
|
|
93
|
+
tag?: string | undefined;
|
|
94
|
+
logger?: LoggerFn | undefined;
|
|
95
|
+
}) => (req: any, res: ResLike, _next?: any) => Promise<void>;
|
|
96
|
+
export declare const createResponder: (res: ResLike, options?: {
|
|
97
|
+
tag?: string | undefined;
|
|
98
|
+
logger?: LoggerFn | undefined;
|
|
99
|
+
}) => (workFn: () => Promise<ApiResponse> | ApiResponse) => Promise<boolean>;
|
|
100
|
+
/** Default export bundle (optional convenience) */
|
|
101
|
+
declare const _default: {
|
|
102
|
+
makeRouteUtils: ({ logger, tagPrefix, }?: {
|
|
103
|
+
logger?: LoggerFn | undefined;
|
|
104
|
+
tagPrefix?: string | undefined;
|
|
105
|
+
}) => {
|
|
106
|
+
wrapRoute: (handler: (req: any, res: ResLike) => ApiResponse<unknown, unknown> | Promise<ApiResponse<unknown, unknown>>, options?: {
|
|
107
|
+
tag?: string | undefined;
|
|
108
|
+
logger?: LoggerFn | undefined;
|
|
109
|
+
}) => (req: any, res: ResLike, _next?: any) => Promise<void>;
|
|
110
|
+
createResponder: (res: ResLike, options?: {
|
|
111
|
+
tag?: string | undefined;
|
|
112
|
+
logger?: LoggerFn | undefined;
|
|
113
|
+
}) => (workFn: () => ApiResponse<unknown, unknown> | Promise<ApiResponse<unknown, unknown>>) => Promise<boolean>;
|
|
114
|
+
resolveRouteResponse: (res: ResLike, response: any) => boolean;
|
|
115
|
+
};
|
|
116
|
+
wrapRoute: (handler: (req: any, res: ResLike) => ApiResponse<unknown, unknown> | Promise<ApiResponse<unknown, unknown>>, options?: {
|
|
117
|
+
tag?: string | undefined;
|
|
118
|
+
logger?: LoggerFn | undefined;
|
|
119
|
+
}) => (req: any, res: ResLike, _next?: any) => Promise<void>;
|
|
120
|
+
createResponder: (res: ResLike, options?: {
|
|
121
|
+
tag?: string | undefined;
|
|
122
|
+
logger?: LoggerFn | undefined;
|
|
123
|
+
}) => (workFn: () => ApiResponse<unknown, unknown> | Promise<ApiResponse<unknown, unknown>>) => Promise<boolean>;
|
|
124
|
+
resolveRouteResponse: (res: ResLike, response: any) => boolean;
|
|
125
|
+
};
|
|
126
|
+
export default _default;
|
|
127
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;kHAmBkH;AAElH,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;AAEjE;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAClC,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC;IAClC,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC;IAClC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO;IACnD,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,CAAC,CAAC;CACV;AAKD;;;;;;;;;;;;kHAYkH;AAClH,eAAO,MAAM,cAAc;;;;+BAoBS,GAAG,OAAO,OAAO,KAAK,QAAQ,WAAW,CAAC,GAAG,WAAW;;;gBAGrE,GAAG,OAAO,OAAO,UAAU,GAAG;2BAuCrB,OAAO;;;mBAIb,MAAM,QAAQ,WAAW,CAAC,GAAG,WAAW;gCA4CxB,OAAO,YAAY,GAAG,KAAG,OAAO;CAnBzE,CAAC;AAEF;;;;;;;;;;;;;;;;kHAgBkH;AAClH,eAAO,MAAM,oBAAoB,QAAS,OAAO,YAAY,GAAG,KAAG,OAiFlE,CAAC;AAOF,eAAO,MAAM,SAAS,kBAlLc,GAAG,OAAO,OAAO,KAAK,QAAQ,WAAW,CAAC,GAAG,WAAW;;;YAGrE,GAAG,OAAO,OAAO,UAAU,GAAG,kBA+KZ,CAAC;AAC1C,eAAO,MAAM,eAAe,QAzII,OAAO;;;eAIb,MAAM,QAAQ,WAAW,CAAC,GAAG,WAAW,qBAqIb,CAAC;AAEtD,mDAAmD;;;;;;;;;;;;;;;;;;;;;;;;;;AACnD,wBAKE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/****************************************************************************************************************
|
|
3
|
+
* ##: Route Utils (TypeScript)
|
|
4
|
+
* Vendor-agnostic helpers for Express-like route handlers.
|
|
5
|
+
*
|
|
6
|
+
* What you get:
|
|
7
|
+
* - Normalized responses: { status:boolean, data?, http?, headers?, meta? }
|
|
8
|
+
* - Safe guards against double responses (res.headersSent)
|
|
9
|
+
* - No vendor lock-in for logging (optional logger function, silent by default)
|
|
10
|
+
* - Two ergonomics:
|
|
11
|
+
* a) wrapRoute(handler, { tag?, logger? }) -> middleware
|
|
12
|
+
* b) createResponder(res, { tag?, logger? }) -> in-route responder
|
|
13
|
+
* - Core primitive: resolveRouteResponse(res, response) -> boolean
|
|
14
|
+
*
|
|
15
|
+
* Logging:
|
|
16
|
+
* - Provide a function logger(payload, tag?) if you want logs (e.g. rollbar.error.bind(rollbar))
|
|
17
|
+
* - If omitted, nothing is logged (silent mode)
|
|
18
|
+
*
|
|
19
|
+
* History:
|
|
20
|
+
* 16-08-2025: Initial version
|
|
21
|
+
****************************************************************************************************************/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.createResponder = exports.wrapRoute = exports.resolveRouteResponse = exports.makeRouteUtils = void 0;
|
|
24
|
+
/** No-op logger (silent). Used when no logger function is provided. */
|
|
25
|
+
const noopLogger = () => { };
|
|
26
|
+
/****************************************************************************************************************
|
|
27
|
+
* ##: Factory
|
|
28
|
+
* makeRouteUtils({ logger?, tagPrefix? })
|
|
29
|
+
*
|
|
30
|
+
* Creates helpers bound to provided defaults, so you can avoid passing the same logger/tag repeatedly.
|
|
31
|
+
*
|
|
32
|
+
* @param logger Optional function `(payload, tag?) => void`. If omitted, no logs are emitted.
|
|
33
|
+
* @param tagPrefix Optional prefix applied to all generated tags (e.g., a file or module path).
|
|
34
|
+
*
|
|
35
|
+
* @returns { wrapRoute, createResponder, resolveRouteResponse }
|
|
36
|
+
* History:
|
|
37
|
+
* 16-08-2025: Created
|
|
38
|
+
****************************************************************************************************************/
|
|
39
|
+
const makeRouteUtils = ({ logger = noopLogger, tagPrefix = "", } = {}) => {
|
|
40
|
+
/****************************************************************************************************************
|
|
41
|
+
* ##: wrapRoute(handler, options?)
|
|
42
|
+
* Express-style middleware wrapper:
|
|
43
|
+
* - Executes your async handler and expects an ApiResponse
|
|
44
|
+
* - Uses resolveRouteResponse to send output
|
|
45
|
+
* - Catches and logs unexpected shapes/errors (only if a logger is provided)
|
|
46
|
+
*
|
|
47
|
+
* @param handler Async route handler: (req, res) => ApiResponse | Promise<ApiResponse>
|
|
48
|
+
* @param options { tag?: string; logger?: LoggerFn }
|
|
49
|
+
* @returns (req, res, next) => Promise<void>
|
|
50
|
+
* History:
|
|
51
|
+
* 16-08-2025: Created
|
|
52
|
+
****************************************************************************************************************/
|
|
53
|
+
const wrapRoute = (handler, options = {}) => {
|
|
54
|
+
const routeLogger = typeof options.logger === "function" ? options.logger : logger;
|
|
55
|
+
return async (req, res, _next) => {
|
|
56
|
+
// Build a tag for logging; default to METHOD + originalUrl
|
|
57
|
+
const baseTag = options.tag || `${req?.method ?? "?"} ${req?.originalUrl ?? "?"}`;
|
|
58
|
+
const tag = tagPrefix ? `${tagPrefix}${baseTag}` : baseTag;
|
|
59
|
+
try {
|
|
60
|
+
const response = await handler(req, res);
|
|
61
|
+
if ((0, exports.resolveRouteResponse)(res, response))
|
|
62
|
+
return; // Early exit: a response has been sent
|
|
63
|
+
// If we got here, the handler returned an unexpected shape
|
|
64
|
+
routeLogger({ message: "Unexpected response shape", response, route: tag }, tag);
|
|
65
|
+
if (!res.headersSent) {
|
|
66
|
+
res.status(500).json({ status: false, error: "UnexpectedResponseShape" });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
// Unhandled error in the handler
|
|
71
|
+
routeLogger(err, `${tag}/catch`);
|
|
72
|
+
if (!res.headersSent) {
|
|
73
|
+
res.status(500).json({ status: false, error: err?.message || "Unexpected error" });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
/****************************************************************************************************************
|
|
79
|
+
* ##: createResponder(res, options?)
|
|
80
|
+
* In-route responder:
|
|
81
|
+
* - Lets you keep the route signature untouched
|
|
82
|
+
* - You call it with a work function returning an ApiResponse
|
|
83
|
+
* - Ensures normalized output and consistent error handling
|
|
84
|
+
*
|
|
85
|
+
* @param res Express-like response object
|
|
86
|
+
* @param options { tag?: string; logger?: LoggerFn }
|
|
87
|
+
* @returns (workFn) => Promise<true>
|
|
88
|
+
* History:
|
|
89
|
+
* 16-08-2025: Created
|
|
90
|
+
****************************************************************************************************************/
|
|
91
|
+
const createResponder = (res, options = {}) => {
|
|
92
|
+
const tagBase = options.tag;
|
|
93
|
+
const routeLogger = typeof options.logger === "function" ? options.logger : logger;
|
|
94
|
+
return async (workFn) => {
|
|
95
|
+
try {
|
|
96
|
+
const response = await workFn();
|
|
97
|
+
if ((0, exports.resolveRouteResponse)(res, response))
|
|
98
|
+
return true; // Responded successfully
|
|
99
|
+
// Unexpected shape
|
|
100
|
+
routeLogger({ message: "Unexpected response shape", response }, tagBase || "createResponder");
|
|
101
|
+
if (!res.headersSent) {
|
|
102
|
+
res.status(500).json({ status: false, error: "UnexpectedResponseShape" });
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
// Unhandled error inside workFn
|
|
108
|
+
routeLogger(error, `${tagBase || "createResponder"}/catch`);
|
|
109
|
+
if (!res.headersSent) {
|
|
110
|
+
res.status(500).json({ status: false, error: error?.message || "Unexpected error" });
|
|
111
|
+
}
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
return { wrapRoute, createResponder, resolveRouteResponse: exports.resolveRouteResponse };
|
|
117
|
+
};
|
|
118
|
+
exports.makeRouteUtils = makeRouteUtils;
|
|
119
|
+
/****************************************************************************************************************
|
|
120
|
+
* ##: Core Primitive - Resolve Route Response
|
|
121
|
+
* resolveRouteResponse(res, response) => boolean
|
|
122
|
+
*
|
|
123
|
+
* Normalizes and sends the HTTP response based on the ApiResponse contract:
|
|
124
|
+
* - Validates the `res` object
|
|
125
|
+
* - Prevents double responses (`headersSent`)
|
|
126
|
+
* - Applies optional headers
|
|
127
|
+
* - Chooses HTTP status code (custom `http` if valid; else 200/204/400 defaults)
|
|
128
|
+
* - Serializes success/error shapes predictably
|
|
129
|
+
*
|
|
130
|
+
* @param res Express-like response object
|
|
131
|
+
* @param response Expected ApiResponse (must include boolean `status`)
|
|
132
|
+
* @returns true if a response was sent; false if `res` looked invalid (no send)
|
|
133
|
+
* History:
|
|
134
|
+
* 16-08-2025: Created
|
|
135
|
+
****************************************************************************************************************/
|
|
136
|
+
const resolveRouteResponse = (res, response) => {
|
|
137
|
+
try {
|
|
138
|
+
// Guard: ensure `res` looks like a valid Express-like response object
|
|
139
|
+
if (!res || typeof res.status !== "function" || typeof res.send !== "function")
|
|
140
|
+
return false;
|
|
141
|
+
// Prevent double responses
|
|
142
|
+
if (res.headersSent)
|
|
143
|
+
return true;
|
|
144
|
+
// Validate presence of `status`
|
|
145
|
+
const hasStatus = response && typeof response === "object" && Object.prototype.hasOwnProperty.call(response, "status");
|
|
146
|
+
if (!hasStatus) {
|
|
147
|
+
res.status(500).json({ status: false, error: "MissingStatus", message: "Missing `status` on response object" });
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
const isOk = response.status === true;
|
|
151
|
+
const isFail = response.status === false;
|
|
152
|
+
// Compute HTTP code:
|
|
153
|
+
// - If a valid custom `http` is provided (100–599), use it.
|
|
154
|
+
// - Otherwise:
|
|
155
|
+
// - Success with undefined/null/empty-string data => 204
|
|
156
|
+
// - Success with data => 200
|
|
157
|
+
// - Failure => 400
|
|
158
|
+
const explicit = Number.isInteger(response?.http) && response.http >= 100 && response.http <= 599;
|
|
159
|
+
const http = explicit ? response.http : isOk ? (response.data === undefined || response.data === null || response.data === "" ? 204 : 200) : 400;
|
|
160
|
+
// Apply optional headers
|
|
161
|
+
if (response?.headers && typeof response.headers === "object") {
|
|
162
|
+
for (const [k, v] of Object.entries(response.headers)) {
|
|
163
|
+
try {
|
|
164
|
+
res.setHeader?.(k, String(v));
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
/* ignore header errors */
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Success path
|
|
172
|
+
if (isOk) {
|
|
173
|
+
if (http === 204) {
|
|
174
|
+
res.status(http).send();
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
const out = { status: true };
|
|
178
|
+
if (response.data !== undefined)
|
|
179
|
+
out.data = response.data;
|
|
180
|
+
if (response.meta !== undefined)
|
|
181
|
+
out.meta = response.meta;
|
|
182
|
+
res.status(http).json(out);
|
|
183
|
+
}
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
// Error path
|
|
187
|
+
if (isFail) {
|
|
188
|
+
const raw = response.data;
|
|
189
|
+
const errBody = raw instanceof Error
|
|
190
|
+
? { error: raw.name || "Error", message: raw.message }
|
|
191
|
+
: raw && typeof raw === "object"
|
|
192
|
+
? {
|
|
193
|
+
...(raw.error ? { error: raw.error } : {}),
|
|
194
|
+
...(raw.message ? { message: raw.message } : {}),
|
|
195
|
+
}
|
|
196
|
+
: { error: "RequestFailed", message: typeof raw === "string" ? raw : "Request failed" };
|
|
197
|
+
res.status(http).json({ status: false, ...errBody, ...(response.meta !== undefined ? { meta: response.meta } : {}) });
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
// Fallback: `status` is neither true nor false
|
|
201
|
+
res.status(500).json({ status: false, error: "InvalidStatusField", message: "`status` must be boolean" });
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
// Absolute last resort: catch unexpected errors inside the responder
|
|
206
|
+
try {
|
|
207
|
+
if (!res.headersSent)
|
|
208
|
+
res.status(500).json({ status: false, error: "UnhandledResponderError", message: error?.message || "Unexpected error" });
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
// If even this fails, we assume there's nothing else we can safely do
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
exports.resolveRouteResponse = resolveRouteResponse;
|
|
218
|
+
/****************************************************************************************************************
|
|
219
|
+
* Pre-bound (silent) helpers
|
|
220
|
+
* These export a default, no-logger configuration so consumers can import directly without a factory.
|
|
221
|
+
****************************************************************************************************************/
|
|
222
|
+
const silent = (0, exports.makeRouteUtils)(); // logger: noop (silent)
|
|
223
|
+
exports.wrapRoute = silent.wrapRoute;
|
|
224
|
+
exports.createResponder = silent.createResponder;
|
|
225
|
+
/** Default export bundle (optional convenience) */
|
|
226
|
+
exports.default = {
|
|
227
|
+
makeRouteUtils: exports.makeRouteUtils,
|
|
228
|
+
wrapRoute: exports.wrapRoute,
|
|
229
|
+
createResponder: exports.createResponder,
|
|
230
|
+
resolveRouteResponse: exports.resolveRouteResponse,
|
|
231
|
+
};
|
|
232
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@salespark/route-utils",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Vendor-agnostic helpers for Express route handlers with normalized responses and optional logging.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc -p tsconfig.build.json",
|
|
12
|
+
"clean": "rm -rf dist",
|
|
13
|
+
"prepublishOnly": "yarn run clean && yarn run build"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"express",
|
|
17
|
+
"middleware",
|
|
18
|
+
"http",
|
|
19
|
+
"routes",
|
|
20
|
+
"api",
|
|
21
|
+
"response",
|
|
22
|
+
"logger",
|
|
23
|
+
"salespark"
|
|
24
|
+
],
|
|
25
|
+
"author": "SalesPark",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/salespark/route-utils.git"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"typescript": "^5.4.0",
|
|
36
|
+
"@types/express": "^4.17.21"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"express": ">=4"
|
|
40
|
+
}
|
|
41
|
+
}
|