@web-ts-toolkit/express-response-handler 0.31.0 → 0.31.2
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/create-handler.js +312 -39
- package/create-handler.mjs +322 -24
- package/error-format.js +14 -12
- package/error-format.mjs +13 -12
- package/error-formats.js +3 -1
- package/error-formats.mjs +2 -1
- package/http-response.js +117 -15
- package/http-response.mjs +102 -14
- package/index.js +603 -23
- package/index.mjs +609 -20
- package/package.json +3 -3
- package/public-types.js +10 -2
- package/public-types.mjs +6 -1
- package/responses/csv.d.mts +4 -1
- package/responses/csv.d.ts +4 -1
- package/responses/csv.js +24 -4
- package/responses/csv.mjs +20 -3
- package/responses/index.d.mts +4 -1
- package/responses/index.d.ts +4 -1
- package/responses/index.js +24 -4
- package/responses/index.mjs +20 -3
- package/responses/success.js +36 -21
- package/responses/success.mjs +33 -21
package/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,35 +17,613 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
19
31
|
var index_exports = {};
|
|
20
32
|
__export(index_exports, {
|
|
21
|
-
Accepted: () =>
|
|
22
|
-
AlreadyReported: () =>
|
|
23
|
-
CSVResponse: () =>
|
|
24
|
-
Created: () =>
|
|
25
|
-
ErrorFormats: () =>
|
|
26
|
-
HttpResponse: () =>
|
|
27
|
-
IMUsed: () =>
|
|
28
|
-
MultiStatus: () =>
|
|
29
|
-
NoContent: () =>
|
|
30
|
-
NonAuthoritativeInfo: () =>
|
|
31
|
-
OK: () =>
|
|
32
|
-
PartialContent: () =>
|
|
33
|
-
ResetContent: () =>
|
|
34
|
-
Response: () =>
|
|
35
|
-
createHandler: () =>
|
|
33
|
+
Accepted: () => Accepted,
|
|
34
|
+
AlreadyReported: () => AlreadyReported,
|
|
35
|
+
CSVResponse: () => CSVResponse,
|
|
36
|
+
Created: () => Created,
|
|
37
|
+
ErrorFormats: () => ErrorFormats,
|
|
38
|
+
HttpResponse: () => HttpResponse,
|
|
39
|
+
IMUsed: () => IMUsed,
|
|
40
|
+
MultiStatus: () => MultiStatus,
|
|
41
|
+
NoContent: () => NoContent,
|
|
42
|
+
NonAuthoritativeInfo: () => NonAuthoritativeInfo,
|
|
43
|
+
OK: () => OK,
|
|
44
|
+
PartialContent: () => PartialContent,
|
|
45
|
+
ResetContent: () => ResetContent,
|
|
46
|
+
Response: () => Response,
|
|
47
|
+
createHandler: () => createHandler,
|
|
36
48
|
default: () => index_default
|
|
37
49
|
});
|
|
38
50
|
module.exports = __toCommonJS(index_exports);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
var
|
|
42
|
-
var
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
var
|
|
46
|
-
|
|
51
|
+
|
|
52
|
+
// src/create-handler.ts
|
|
53
|
+
var import_assert = __toESM(require("assert"));
|
|
54
|
+
var import_utils3 = require("@web-ts-toolkit/utils");
|
|
55
|
+
|
|
56
|
+
// src/responses/csv.ts
|
|
57
|
+
var import_format = require("@fast-csv/format");
|
|
58
|
+
var import_utils = require("@web-ts-toolkit/utils");
|
|
59
|
+
var csvResponseBrand = /* @__PURE__ */ Symbol.for("@web-ts-toolkit/express-response-handler.csv-response");
|
|
60
|
+
var isCSVResponse = (value) => {
|
|
61
|
+
if (value instanceof CSVResponse) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
if (typeof value !== "object" || value === null) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
const candidate = value;
|
|
68
|
+
return candidate[csvResponseBrand] === true && typeof candidate.streamCsv === "function";
|
|
69
|
+
};
|
|
70
|
+
var _a;
|
|
71
|
+
_a = csvResponseBrand;
|
|
72
|
+
var CSVResponse = class {
|
|
73
|
+
constructor(dataset = [], options = {}) {
|
|
74
|
+
this[_a] = true;
|
|
75
|
+
this.dataset = (0, import_utils.castArray)(dataset);
|
|
76
|
+
this.filename = options.filename || "download.csv";
|
|
77
|
+
this.processor = options.processor || ((value) => value);
|
|
78
|
+
if ((0, import_utils.isBoolean)(options.headers)) {
|
|
79
|
+
this.headers = options.headers;
|
|
80
|
+
} else if (this.dataset.length > 0) {
|
|
81
|
+
this.headers = (0, import_utils.isPlainObject)(this.dataset[0]);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
streamCsv(res) {
|
|
85
|
+
const stream = (0, import_format.format)({ headers: this.headers });
|
|
86
|
+
res.set("Content-Type", "text/csv");
|
|
87
|
+
res.set("Content-Disposition", `attachment;filename=${this.filename}`);
|
|
88
|
+
stream.pipe(res);
|
|
89
|
+
stream.on("error", (error) => {
|
|
90
|
+
if (res.destroy) {
|
|
91
|
+
res.destroy(error);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
res.end();
|
|
95
|
+
});
|
|
96
|
+
stream.on("end", () => res.end());
|
|
97
|
+
this.dataset.forEach((value) => stream.write(this.processor(value)));
|
|
98
|
+
stream.end();
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// src/responses/index.ts
|
|
103
|
+
var responseBrand = /* @__PURE__ */ Symbol.for("@web-ts-toolkit/express-response-handler.response");
|
|
104
|
+
var isResponse = (value) => {
|
|
105
|
+
if (value instanceof Response) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
if (typeof value !== "object" || value === null) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
const candidate = value;
|
|
112
|
+
return candidate[responseBrand] === true && typeof candidate.statusCode === "number" && "data" in candidate;
|
|
113
|
+
};
|
|
114
|
+
var _a2;
|
|
115
|
+
_a2 = responseBrand;
|
|
116
|
+
var Response = class {
|
|
117
|
+
constructor(statusCode = 200, data) {
|
|
118
|
+
this[_a2] = true;
|
|
119
|
+
this.statusCode = statusCode;
|
|
120
|
+
this.data = data;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// src/responses/success.ts
|
|
125
|
+
var OK = class extends Response {
|
|
126
|
+
constructor(data) {
|
|
127
|
+
super(200, data);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
var Created = class extends Response {
|
|
131
|
+
constructor(data) {
|
|
132
|
+
super(201, data);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
var Accepted = class extends Response {
|
|
136
|
+
constructor(data) {
|
|
137
|
+
super(202, data);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
var NonAuthoritativeInfo = class extends Response {
|
|
141
|
+
constructor(data) {
|
|
142
|
+
super(203, data);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
var NoContent = class extends Response {
|
|
146
|
+
constructor() {
|
|
147
|
+
super(204, void 0);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
var ResetContent = class extends Response {
|
|
151
|
+
constructor(data) {
|
|
152
|
+
super(205, data);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
var PartialContent = class extends Response {
|
|
156
|
+
constructor(data) {
|
|
157
|
+
super(206, data);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
var MultiStatus = class extends Response {
|
|
161
|
+
constructor(data) {
|
|
162
|
+
super(207, data);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
var AlreadyReported = class extends Response {
|
|
166
|
+
constructor(data) {
|
|
167
|
+
super(208, data);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
var IMUsed = class extends Response {
|
|
171
|
+
constructor(data) {
|
|
172
|
+
super(226, data);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// src/http-response.ts
|
|
177
|
+
var import_http_errors = require("@web-ts-toolkit/http-errors");
|
|
178
|
+
var HttpResponse = {
|
|
179
|
+
ok: (...args) => new OK(...args),
|
|
180
|
+
created: (...args) => new Created(...args),
|
|
181
|
+
accepted: (...args) => new Accepted(...args),
|
|
182
|
+
nonAuthoritativeInfo: (...args) => new NonAuthoritativeInfo(...args),
|
|
183
|
+
noContent: (...args) => new NoContent(...args),
|
|
184
|
+
resetContent: (...args) => new ResetContent(...args),
|
|
185
|
+
partialContent: (...args) => new PartialContent(...args),
|
|
186
|
+
multiStatus: (...args) => new MultiStatus(...args),
|
|
187
|
+
alreadyReported: (...args) => new AlreadyReported(...args),
|
|
188
|
+
imUsed: (...args) => new IMUsed(...args),
|
|
189
|
+
badRequest: (...args) => new import_http_errors.BadRequestError(...args),
|
|
190
|
+
unauthorized: (...args) => new import_http_errors.UnauthorizedError(...args),
|
|
191
|
+
forbidden: (...args) => new import_http_errors.ForbiddenError(...args),
|
|
192
|
+
notFound: (...args) => new import_http_errors.NotFoundError(...args),
|
|
193
|
+
methodNotAllowed: (...args) => new import_http_errors.MethodNotAllowedError(...args),
|
|
194
|
+
notAcceptable: (...args) => new import_http_errors.NotAcceptableError(...args),
|
|
195
|
+
proxyAuthRequired: (...args) => new import_http_errors.ProxyAuthRequiredError(...args),
|
|
196
|
+
requestTimeout: (...args) => new import_http_errors.RequestTimeoutError(...args),
|
|
197
|
+
conflict: (...args) => new import_http_errors.ConflictError(...args),
|
|
198
|
+
gone: (...args) => new import_http_errors.GoneError(...args),
|
|
199
|
+
lengthRequired: (...args) => new import_http_errors.LengthRequiredError(...args),
|
|
200
|
+
preconditionFailed: (...args) => new import_http_errors.PreconditionFailedError(...args),
|
|
201
|
+
payloadTooLarge: (...args) => new import_http_errors.PayloadTooLargeError(...args),
|
|
202
|
+
uriTooLong: (...args) => new import_http_errors.UriTooLongError(...args),
|
|
203
|
+
unsupportedMediaType: (...args) => new import_http_errors.UnsupportedMediaTypeError(...args),
|
|
204
|
+
requestedRangeNotSatisfiable: (...args) => new import_http_errors.RequestedRangeNotSatisfiableError(...args),
|
|
205
|
+
expectationFailed: (...args) => new import_http_errors.ExpectationFailedError(...args),
|
|
206
|
+
teapot: (...args) => new import_http_errors.TeapotError(...args),
|
|
207
|
+
misdirectedRequest: (...args) => new import_http_errors.MisdirectedRequestError(...args),
|
|
208
|
+
unprocessableEntity: (...args) => new import_http_errors.UnprocessableEntityError(...args),
|
|
209
|
+
locked: (...args) => new import_http_errors.LockedError(...args),
|
|
210
|
+
failedDependency: (...args) => new import_http_errors.FailedDependencyError(...args),
|
|
211
|
+
upgradeRequired: (...args) => new import_http_errors.UpgradeRequiredError(...args),
|
|
212
|
+
preconditionRequired: (...args) => new import_http_errors.PreconditionRequiredError(...args),
|
|
213
|
+
tooManyRequests: (...args) => new import_http_errors.TooManyRequestsError(...args),
|
|
214
|
+
requestHeaderFieldsTooLarge: (...args) => new import_http_errors.RequestHeaderFieldsTooLargeError(...args),
|
|
215
|
+
unavailableForLegalReasons: (...args) => new import_http_errors.UnavailableForLegalReasonsError(...args),
|
|
216
|
+
json: (...args) => new OK(...args),
|
|
217
|
+
csv: (...args) => new CSVResponse(...args)
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// src/error-format.ts
|
|
221
|
+
var import_http_errors2 = require("@web-ts-toolkit/http-errors");
|
|
222
|
+
var import_utils2 = require("@web-ts-toolkit/utils");
|
|
223
|
+
var toStatusCode = (status, code, fallbackStatusCode) => {
|
|
224
|
+
if (typeof status === "number") {
|
|
225
|
+
return status;
|
|
226
|
+
}
|
|
227
|
+
return typeof code === "number" ? code : fallbackStatusCode;
|
|
228
|
+
};
|
|
229
|
+
var toOptionalString = (value) => typeof value === "string" ? value : void 0;
|
|
230
|
+
var toMetadata = (value) => {
|
|
231
|
+
return (0, import_utils2.toStringRecord)(value);
|
|
232
|
+
};
|
|
233
|
+
var toArray = (value) => {
|
|
234
|
+
if (value === void 0 || value === null) {
|
|
235
|
+
return void 0;
|
|
236
|
+
}
|
|
237
|
+
return (0, import_utils2.isArray)(value) ? value : [value];
|
|
238
|
+
};
|
|
239
|
+
var toHttpErrorShape = (error, fallbackDomain) => ({
|
|
240
|
+
statusCode: error.statusCode ?? 500,
|
|
241
|
+
status: error.status,
|
|
242
|
+
message: error.message ?? "",
|
|
243
|
+
reason: error.reason,
|
|
244
|
+
domain: error.domain ?? fallbackDomain,
|
|
245
|
+
metadata: toMetadata(error.metadata),
|
|
246
|
+
details: toArray(error.details),
|
|
247
|
+
errors: error.errors,
|
|
248
|
+
type: error.type,
|
|
249
|
+
title: error.title,
|
|
250
|
+
instance: error.instance
|
|
251
|
+
});
|
|
252
|
+
var toProblemDetailsSource = (result) => {
|
|
253
|
+
if ((0, import_utils2.isPlainObject)(result) && (0, import_utils2.isPlainObject)(result.error)) {
|
|
254
|
+
return result.error;
|
|
255
|
+
}
|
|
256
|
+
return (0, import_utils2.isPlainObject)(result) ? result : void 0;
|
|
257
|
+
};
|
|
258
|
+
var defaultErrorMessageProvider = function(error) {
|
|
259
|
+
const errorLike = error;
|
|
260
|
+
return errorLike.message ?? errorLike._message ?? String(error);
|
|
261
|
+
};
|
|
262
|
+
var toSimpleErrorPayload = (result) => (0, import_utils2.isString)(result) ? { message: result } : { ...result };
|
|
263
|
+
var toStructuredHttpErrorPayload = (error, errorDomain) => (0, import_http_errors2.toAip193ErrorPayload)(toHttpErrorShape(error, errorDomain), errorDomain);
|
|
264
|
+
var toRfc9457HttpErrorPayload = (error, errorDomain) => (0, import_http_errors2.toRfc9457ErrorPayload)(toHttpErrorShape(error, errorDomain));
|
|
265
|
+
var toStructuredGenericErrorPayload = (result, errorDomain) => {
|
|
266
|
+
if ((0, import_utils2.isPlainObject)(result) && (0, import_utils2.isPlainObject)(result.error)) {
|
|
267
|
+
const error = result.error;
|
|
268
|
+
const statusCode = typeof error.code === "number" ? error.code : 422;
|
|
269
|
+
const status = typeof error.status === "string" ? error.status : (0, import_http_errors2.getCanonicalStatus)(statusCode);
|
|
270
|
+
const message = typeof error.message === "string" ? error.message : "";
|
|
271
|
+
const details = toArray(error.details);
|
|
272
|
+
return {
|
|
273
|
+
error: {
|
|
274
|
+
code: statusCode,
|
|
275
|
+
status,
|
|
276
|
+
message,
|
|
277
|
+
...details ? { details } : {}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
if ((0, import_utils2.isPlainObject)(result)) {
|
|
282
|
+
const statusCode = typeof result.code === "number" ? result.code : 422;
|
|
283
|
+
const status = typeof result.status === "string" ? result.status : (0, import_http_errors2.getCanonicalStatus)(statusCode);
|
|
284
|
+
const message = typeof result.message === "string" ? result.message : "";
|
|
285
|
+
const details = toArray(result.details) || [(0, import_http_errors2.createAip193ErrorInfoDetail)(status, errorDomain)];
|
|
286
|
+
return {
|
|
287
|
+
error: {
|
|
288
|
+
code: statusCode,
|
|
289
|
+
status,
|
|
290
|
+
message,
|
|
291
|
+
...details ? { details } : {}
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
return {
|
|
296
|
+
error: {
|
|
297
|
+
code: 422,
|
|
298
|
+
status: (0, import_http_errors2.getCanonicalStatus)(422),
|
|
299
|
+
message: String(result),
|
|
300
|
+
details: [(0, import_http_errors2.createAip193ErrorInfoDetail)((0, import_http_errors2.getCanonicalStatus)(422), errorDomain)]
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
};
|
|
304
|
+
var toRfc9457GenericErrorPayload = (result) => {
|
|
305
|
+
const problem = toProblemDetailsSource(result);
|
|
306
|
+
if (problem) {
|
|
307
|
+
const statusCode = toStatusCode(problem.status, problem.code, 422);
|
|
308
|
+
return (0, import_http_errors2.toRfc9457ErrorPayload)({
|
|
309
|
+
statusCode,
|
|
310
|
+
message: toOptionalString(problem.detail) ?? toOptionalString(problem.message) ?? "",
|
|
311
|
+
errors: problem.errors,
|
|
312
|
+
type: toOptionalString(problem.type),
|
|
313
|
+
title: toOptionalString(problem.title),
|
|
314
|
+
instance: toOptionalString(problem.instance)
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
return (0, import_http_errors2.toRfc9457ErrorPayload)({
|
|
318
|
+
statusCode: 422,
|
|
319
|
+
message: String(result)
|
|
320
|
+
});
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
// src/error-formats.ts
|
|
324
|
+
var ErrorFormats = {
|
|
325
|
+
simple: "simple",
|
|
326
|
+
aip193: "aip193",
|
|
327
|
+
rfc9457: "rfc9457"
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// src/create-handler.ts
|
|
331
|
+
var promisify = (fn) => (value) => Promise.resolve().then(() => fn(value));
|
|
332
|
+
var invokePostHook = (hook, value) => {
|
|
333
|
+
void hook(value).catch(() => void 0);
|
|
334
|
+
};
|
|
335
|
+
var RFC_9457_CONTENT_TYPE = "application/problem+json";
|
|
336
|
+
var shouldSkipResponse = (res, event) => res.headersSent || event.canceled;
|
|
337
|
+
var sendProblemJson = (res, statusCode, payload, contentType) => {
|
|
338
|
+
res.status(statusCode);
|
|
339
|
+
res.set("Content-Type", contentType);
|
|
340
|
+
res.send(payload);
|
|
341
|
+
};
|
|
342
|
+
var sendHttpErrorByFormat = {
|
|
343
|
+
[ErrorFormats.simple]: (res, error) => {
|
|
344
|
+
const payload = { message: error.message ?? "" };
|
|
345
|
+
if (error.errors !== void 0) {
|
|
346
|
+
payload.errors = error.errors;
|
|
347
|
+
}
|
|
348
|
+
res.status(error.statusCode ?? 500).send(payload);
|
|
349
|
+
},
|
|
350
|
+
[ErrorFormats.aip193]: (res, error, domain) => {
|
|
351
|
+
res.status(error.statusCode ?? 500).send(toStructuredHttpErrorPayload(error, domain));
|
|
352
|
+
},
|
|
353
|
+
[ErrorFormats.rfc9457]: (res, error, domain) => {
|
|
354
|
+
sendProblemJson(res, error.statusCode ?? 500, toRfc9457HttpErrorPayload(error, domain), RFC_9457_CONTENT_TYPE);
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
var sendGenericErrorByFormat = {
|
|
358
|
+
[ErrorFormats.simple]: (res, result) => {
|
|
359
|
+
res.status(422).send(toSimpleErrorPayload(result));
|
|
360
|
+
},
|
|
361
|
+
[ErrorFormats.aip193]: (res, result, domain) => {
|
|
362
|
+
const payload = toStructuredGenericErrorPayload(result, domain);
|
|
363
|
+
res.status(payload.error.code).send(payload);
|
|
364
|
+
},
|
|
365
|
+
[ErrorFormats.rfc9457]: (res, result) => {
|
|
366
|
+
const payload = toRfc9457GenericErrorPayload(result);
|
|
367
|
+
sendProblemJson(res, payload.status ?? 422, payload, RFC_9457_CONTENT_TYPE);
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
var assertMiddleware = (fn) => {
|
|
371
|
+
import_assert.default.ok((0, import_utils3.isFunction)(fn), "middleware handler must be a function");
|
|
372
|
+
};
|
|
373
|
+
var normalizeMiddlewareList = (fns) => {
|
|
374
|
+
import_assert.default.ok(fns.length > 0, "at least one middleware handler is required");
|
|
375
|
+
if (fns.length > 1) {
|
|
376
|
+
fns.forEach(assertMiddleware);
|
|
377
|
+
return fns;
|
|
378
|
+
}
|
|
379
|
+
if ((0, import_utils3.isArray)(fns[0])) {
|
|
380
|
+
import_assert.default.ok(fns[0].length > 0, "at least one middleware handler is required");
|
|
381
|
+
fns[0].forEach(assertMiddleware);
|
|
382
|
+
return fns[0];
|
|
383
|
+
}
|
|
384
|
+
assertMiddleware(fns[0]);
|
|
385
|
+
return [fns[0]];
|
|
386
|
+
};
|
|
387
|
+
function createHandler(options = {}) {
|
|
388
|
+
const errorFormat = options.errorFormat ?? ErrorFormats.simple;
|
|
389
|
+
const errorDomain = options.errorDomain ?? "express-response-handler";
|
|
390
|
+
const rfc9457ContentType = options.rfc9457ContentType ?? RFC_9457_CONTENT_TYPE;
|
|
391
|
+
let errorMessageProvider = defaultErrorMessageProvider;
|
|
392
|
+
let preJson = null;
|
|
393
|
+
let postJson = null;
|
|
394
|
+
let preError = null;
|
|
395
|
+
let postError = null;
|
|
396
|
+
let preJsonHook = null;
|
|
397
|
+
let postJsonHook = null;
|
|
398
|
+
let preErrorHook = null;
|
|
399
|
+
let postErrorHook = null;
|
|
400
|
+
const updateHook = (fn, name, setState, rebuild) => {
|
|
401
|
+
if (fn === null) {
|
|
402
|
+
setState(null, null);
|
|
403
|
+
rebuild();
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
import_assert.default.ok((0, import_utils3.isFunction)(fn), `${name} hook must be a function`);
|
|
407
|
+
setState(fn, promisify(fn));
|
|
408
|
+
rebuild();
|
|
409
|
+
};
|
|
410
|
+
const sendBaseJson = function(res, data, event) {
|
|
411
|
+
if (shouldSkipResponse(res, event)) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
if (data === void 0) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (isResponse(data)) {
|
|
418
|
+
res.status(data.statusCode).json(data.data);
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
if (isCSVResponse(data)) {
|
|
422
|
+
data.streamCsv(res);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
res.json(data);
|
|
426
|
+
};
|
|
427
|
+
const sendBaseError = function(res, err, event) {
|
|
428
|
+
if (shouldSkipResponse(res, event)) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
const error = err;
|
|
432
|
+
if (error.statusCode) {
|
|
433
|
+
if (errorFormat === ErrorFormats.rfc9457) {
|
|
434
|
+
sendProblemJson(
|
|
435
|
+
res,
|
|
436
|
+
error.statusCode ?? 500,
|
|
437
|
+
toRfc9457HttpErrorPayload(error, errorDomain),
|
|
438
|
+
rfc9457ContentType
|
|
439
|
+
);
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
sendHttpErrorByFormat[errorFormat](res, error, errorDomain);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
const result = errorMessageProvider(err);
|
|
446
|
+
if (errorFormat === ErrorFormats.rfc9457) {
|
|
447
|
+
const payload = toRfc9457GenericErrorPayload(result);
|
|
448
|
+
sendProblemJson(res, payload.status ?? 422, payload, rfc9457ContentType);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
sendGenericErrorByFormat[errorFormat](res, result, errorDomain);
|
|
452
|
+
};
|
|
453
|
+
let sendJson = sendBaseJson;
|
|
454
|
+
let sendError = sendBaseError;
|
|
455
|
+
const rebuildSendJson = () => {
|
|
456
|
+
if (!preJsonHook && !postJsonHook) {
|
|
457
|
+
sendJson = sendBaseJson;
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
sendJson = function(res, data, event) {
|
|
461
|
+
const finalize = () => {
|
|
462
|
+
try {
|
|
463
|
+
sendBaseJson(res, data, event);
|
|
464
|
+
} catch (err) {
|
|
465
|
+
sendError(res, err, event);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (postJsonHook) {
|
|
469
|
+
invokePostHook(postJsonHook, data);
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
if (preJsonHook) {
|
|
473
|
+
preJsonHook(data).then(finalize, (err) => sendError(res, err, event));
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
finalize();
|
|
477
|
+
};
|
|
478
|
+
};
|
|
479
|
+
const rebuildSendError = () => {
|
|
480
|
+
if (!preErrorHook && !postErrorHook) {
|
|
481
|
+
sendError = sendBaseError;
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
sendError = function(res, err, event) {
|
|
485
|
+
const finalize = () => {
|
|
486
|
+
sendBaseError(res, err, event);
|
|
487
|
+
if (postErrorHook) {
|
|
488
|
+
invokePostHook(postErrorHook, err);
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
if (preErrorHook) {
|
|
492
|
+
preErrorHook(err).then(finalize, (hookErr) => sendBaseError(res, hookErr, event));
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
finalize();
|
|
496
|
+
};
|
|
497
|
+
};
|
|
498
|
+
const handlePromise = function(res, promise, event) {
|
|
499
|
+
Promise.resolve(promise).then((data) => {
|
|
500
|
+
if (event.nextError) {
|
|
501
|
+
sendError(res, event.nextError, event);
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
sendJson(res, data, event);
|
|
505
|
+
}).catch((err) => sendError(res, err, event));
|
|
506
|
+
};
|
|
507
|
+
const handleResult = function(res, result, event) {
|
|
508
|
+
if (shouldSkipResponse(res, event)) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
if (event.nextError) {
|
|
512
|
+
sendError(res, event.nextError, event);
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
if ((0, import_utils3.isPromise)(result)) {
|
|
516
|
+
handlePromise(res, result, event);
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
sendJson(res, result, event);
|
|
520
|
+
};
|
|
521
|
+
const nextFn = function(event, next) {
|
|
522
|
+
return function(...args) {
|
|
523
|
+
if (args.length === 0) {
|
|
524
|
+
event.canceled = true;
|
|
525
|
+
next();
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
if (args[0] instanceof Error) {
|
|
529
|
+
event.nextError = args[0];
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
event.nextError = new TypeError("next(value) is not supported; return a value instead");
|
|
533
|
+
};
|
|
534
|
+
};
|
|
535
|
+
const routerFn = function(fn) {
|
|
536
|
+
return function(req, res, next) {
|
|
537
|
+
const event = { canceled: false, nextError: null };
|
|
538
|
+
try {
|
|
539
|
+
const result = fn(req, res, nextFn(event, next));
|
|
540
|
+
handleResult(res, result, event);
|
|
541
|
+
} catch (err) {
|
|
542
|
+
if (res.headersSent) {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
sendError(res, err, event);
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
};
|
|
549
|
+
const handleResponse = function(...fns) {
|
|
550
|
+
const middlewares = normalizeMiddlewareList(fns);
|
|
551
|
+
return middlewares.length === 1 ? routerFn(middlewares[0]) : middlewares.map(routerFn);
|
|
552
|
+
};
|
|
553
|
+
return {
|
|
554
|
+
handleResponse,
|
|
555
|
+
handleResult,
|
|
556
|
+
handlePromise,
|
|
557
|
+
HttpResponse,
|
|
558
|
+
createHandler,
|
|
559
|
+
get errorMessageProvider() {
|
|
560
|
+
return errorMessageProvider;
|
|
561
|
+
},
|
|
562
|
+
set errorMessageProvider(fn) {
|
|
563
|
+
import_assert.default.ok((0, import_utils3.isFunction)(fn), "error message provider must be a function");
|
|
564
|
+
errorMessageProvider = fn;
|
|
565
|
+
},
|
|
566
|
+
get preJson() {
|
|
567
|
+
return preJson;
|
|
568
|
+
},
|
|
569
|
+
set preJson(fn) {
|
|
570
|
+
updateHook(
|
|
571
|
+
fn,
|
|
572
|
+
"pre-json",
|
|
573
|
+
(syncHook, asyncHook) => {
|
|
574
|
+
preJson = syncHook;
|
|
575
|
+
preJsonHook = asyncHook;
|
|
576
|
+
},
|
|
577
|
+
rebuildSendJson
|
|
578
|
+
);
|
|
579
|
+
},
|
|
580
|
+
get postJson() {
|
|
581
|
+
return postJson;
|
|
582
|
+
},
|
|
583
|
+
set postJson(fn) {
|
|
584
|
+
updateHook(
|
|
585
|
+
fn,
|
|
586
|
+
"post-json",
|
|
587
|
+
(syncHook, asyncHook) => {
|
|
588
|
+
postJson = syncHook;
|
|
589
|
+
postJsonHook = asyncHook;
|
|
590
|
+
},
|
|
591
|
+
rebuildSendJson
|
|
592
|
+
);
|
|
593
|
+
},
|
|
594
|
+
get preError() {
|
|
595
|
+
return preError;
|
|
596
|
+
},
|
|
597
|
+
set preError(fn) {
|
|
598
|
+
updateHook(
|
|
599
|
+
fn,
|
|
600
|
+
"pre-error",
|
|
601
|
+
(syncHook, asyncHook) => {
|
|
602
|
+
preError = syncHook;
|
|
603
|
+
preErrorHook = asyncHook;
|
|
604
|
+
},
|
|
605
|
+
rebuildSendError
|
|
606
|
+
);
|
|
607
|
+
},
|
|
608
|
+
get postError() {
|
|
609
|
+
return postError;
|
|
610
|
+
},
|
|
611
|
+
set postError(fn) {
|
|
612
|
+
updateHook(
|
|
613
|
+
fn,
|
|
614
|
+
"post-error",
|
|
615
|
+
(syncHook, asyncHook) => {
|
|
616
|
+
postError = syncHook;
|
|
617
|
+
postErrorHook = asyncHook;
|
|
618
|
+
},
|
|
619
|
+
rebuildSendError
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// src/index.ts
|
|
626
|
+
var apiHandler = createHandler();
|
|
47
627
|
var index_default = apiHandler;
|
|
48
628
|
// Annotate the CommonJS export names for ESM import in node:
|
|
49
629
|
0 && (module.exports = {
|