@web-ts-toolkit/express-response-handler 0.31.5 → 0.33.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 CHANGED
@@ -85,11 +85,11 @@ async function createUser() {
85
85
 
86
86
  app.post(
87
87
  '/users',
88
- handleResponse(async () => Created(await createUser())),
88
+ handleResponse(async () => new Created(await createUser())),
89
89
  );
90
90
  app.delete(
91
91
  '/users/:id',
92
- handleResponse(async () => NoContent()),
92
+ handleResponse(async () => new NoContent()),
93
93
  );
94
94
  ```
95
95
 
@@ -111,3 +111,51 @@ import { handleResponse, HttpResponse } from '@web-ts-toolkit/express-response-h
111
111
  Full package documentation lives in `website/docs/packages/express-response-handler.md`.
112
112
 
113
113
  - live docs: https://web-ts-toolkit.pages.dev/docs/packages/express-response-handler
114
+
115
+ ## Hooks
116
+
117
+ Hooks are observational side effects. They receive the value or error being handled, may return `void` or `Promise<void>`, and returned values never transform the response payload.
118
+
119
+ - `preJson` runs before a non-`undefined` success value is serialized.
120
+ - `postJson` runs after the HTTP response emits `finish` for a successful JSON, `HttpResponse`, or CSV response.
121
+ - `preError` runs before an error response is serialized.
122
+ - `postError` runs after the HTTP response emits `finish` for an error response.
123
+
124
+ If a handler returns `undefined`, the library assumes the handler owns the response and does not run `postJson`. `postJson` and `postError` do not run on client `close` or failed serialization paths that never emit `finish`.
125
+
126
+ Pre-hook failures are routed through the normal error response path. Post-hook failures happen after the response has completed, so they are passed to Express with `next(err)` for server-side logging/observability without creating a second client response.
127
+
128
+ The default export is a mutable process-wide singleton. Use `createHandler()` when you need isolated hook or error-provider state.
129
+
130
+ ## Error Security
131
+
132
+ Unexpected non-HTTP failures are treated as server errors and return status `500` with the generic client message `Internal Server Error`. The original thrown value is still passed to `preError`, `postError`, and Express error middleware if serialization itself fails, so log there instead of exposing raw exception text to clients.
133
+
134
+ Only finite integer `4xx` and `5xx` status codes are serialized as HTTP errors. Invalid status values are rejected before response headers are written.
135
+
136
+ Breaking change: older versions returned generic thrown `Error` messages as `422` responses. Use typed errors from `@web-ts-toolkit/http-errors` for intentional client-facing `4xx` payloads, or set `errorMessageProvider` when you deliberately want a sanitized custom generic payload.
137
+
138
+ ## CSV Security
139
+
140
+ `CSVResponse` writes cell values exactly as supplied. It does not automatically neutralize spreadsheet formulas such as values beginning with `=`, `+`, `-`, or `@` because some exports intentionally include formulas.
141
+
142
+ If user-controlled cells may be opened in spreadsheet software, neutralize them with the `processor` option before streaming:
143
+
144
+ ```ts
145
+ const safeCell = (value: unknown) => (typeof value === 'string' && /^[=+\-@]/.test(value) ? `'${value}` : value);
146
+
147
+ const safeRow = (row: unknown) => {
148
+ if (!row || typeof row !== 'object' || Array.isArray(row)) {
149
+ return safeCell(row);
150
+ }
151
+
152
+ return Object.fromEntries(Object.entries(row).map(([key, value]) => [key, safeCell(value)]));
153
+ };
154
+
155
+ return new CSVResponse(rows, {
156
+ filename: 'users.csv',
157
+ processor: safeRow,
158
+ });
159
+ ```
160
+
161
+ See `ERH-12.md` for the root import measurement and CSV formula-injection policy rationale.
@@ -1,9 +1,10 @@
1
1
  import { ExpressResponseHandlerOptions, ExpressResponseHandler } from './public-types.mjs';
2
+ import 'express-serve-static-core';
2
3
  import './http-response.mjs';
4
+ import './responses/csv.mjs';
3
5
  import '@web-ts-toolkit/http-errors';
4
6
  import './responses/success.mjs';
5
7
  import './responses/index.mjs';
6
- import './responses/csv.mjs';
7
8
  import './error-formats.mjs';
8
9
 
9
10
  /**
@@ -1,9 +1,10 @@
1
1
  import { ExpressResponseHandlerOptions, ExpressResponseHandler } from './public-types.js';
2
+ import 'express-serve-static-core';
2
3
  import './http-response.js';
4
+ import './responses/csv.js';
3
5
  import '@web-ts-toolkit/http-errors';
4
6
  import './responses/success.js';
5
7
  import './responses/index.js';
6
- import './responses/csv.js';
7
8
  import './error-formats.js';
8
9
 
9
10
  /**