@visulima/error-handler 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/CHANGELOG.md +9 -0
- package/LICENSE.md +193 -0
- package/README.md +388 -0
- package/dist/error-handler/html-error-handler.d.ts +16 -0
- package/dist/error-handler/html-error-handler.js +63 -0
- package/dist/error-handler/json-error-handler.d.ts +17 -0
- package/dist/error-handler/json-error-handler.js +31 -0
- package/dist/error-handler/jsonapi-error-handler.d.ts +6 -0
- package/dist/error-handler/jsonapi-error-handler.js +46 -0
- package/dist/error-handler/jsonp-error-handler.d.ts +18 -0
- package/dist/error-handler/jsonp-error-handler.js +36 -0
- package/dist/error-handler/problem-error-handler.d.ts +6 -0
- package/dist/error-handler/problem-error-handler.js +53 -0
- package/dist/error-handler/text-error-handler.d.ts +16 -0
- package/dist/error-handler/text-error-handler.js +28 -0
- package/dist/error-handler/xml-error-handler.d.ts +29 -0
- package/dist/error-handler/xml-error-handler.js +45 -0
- package/dist/handler/cli-handler.d.ts +30 -0
- package/dist/handler/cli-handler.js +173 -0
- package/dist/handler/http/fetch-handler.d.ts +11 -0
- package/dist/handler/http/fetch-handler.js +267 -0
- package/dist/handler/http/node-handler.d.ts +11 -0
- package/dist/handler/http/node-handler.js +17 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +8 -0
- package/dist/packem_shared/add-status-code-to-response-DdfxTQsK.js +17 -0
- package/dist/packem_shared/createNegotiatedErrorHandler-Cd7yj67Z.js +52 -0
- package/dist/packem_shared/send-json-o-t1rNfw.js +8 -0
- package/dist/packem_shared/set-error-headers-B6ZeX5k4.js +10 -0
- package/dist/packem_shared/types.d-DLy8CCca.d.ts +26 -0
- package/package.json +151 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { htmlErrorHandler } from '../../error-handler/html-error-handler.js';
|
|
2
|
+
import jsonapiErrorHandler from '../../error-handler/jsonapi-error-handler.js';
|
|
3
|
+
import problemErrorHandler from '../../error-handler/problem-error-handler.js';
|
|
4
|
+
import { textErrorHandler } from '../../error-handler/text-error-handler.js';
|
|
5
|
+
import { jsonErrorHandler } from '../../error-handler/json-error-handler.js';
|
|
6
|
+
import { jsonpErrorHandler } from '../../error-handler/jsonp-error-handler.js';
|
|
7
|
+
import { xmlErrorHandler } from '../../error-handler/xml-error-handler.js';
|
|
8
|
+
|
|
9
|
+
var __defProp$2 = Object.defineProperty;
|
|
10
|
+
var __name$2 = (target, value) => __defProp$2(target, "name", { value, configurable: true });
|
|
11
|
+
class MockServerResponse {
|
|
12
|
+
static {
|
|
13
|
+
__name$2(this, "MockServerResponse");
|
|
14
|
+
}
|
|
15
|
+
statusCode = 200;
|
|
16
|
+
statusMessage = "";
|
|
17
|
+
headers = {};
|
|
18
|
+
headersSent = false;
|
|
19
|
+
writable = true;
|
|
20
|
+
finished = false;
|
|
21
|
+
writableEnded = false;
|
|
22
|
+
writableFinished = false;
|
|
23
|
+
writableHighWaterMark = 16384;
|
|
24
|
+
writableLength = 0;
|
|
25
|
+
destroyed = false;
|
|
26
|
+
writableCorked = 0;
|
|
27
|
+
readable = false;
|
|
28
|
+
readableHighWaterMark = 16384;
|
|
29
|
+
readableLength = 0;
|
|
30
|
+
errored = null;
|
|
31
|
+
closed = false;
|
|
32
|
+
readableAborted = false;
|
|
33
|
+
readableDidRead = false;
|
|
34
|
+
readableEncoding = null;
|
|
35
|
+
readableEnded = false;
|
|
36
|
+
readableFlowing = null;
|
|
37
|
+
_events;
|
|
38
|
+
_eventsCount = 0;
|
|
39
|
+
_maxListeners;
|
|
40
|
+
body = "";
|
|
41
|
+
setHeader(name, value) {
|
|
42
|
+
this.headers[name.toLowerCase()] = value;
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
getHeader(name) {
|
|
46
|
+
return this.headers[name.toLowerCase()];
|
|
47
|
+
}
|
|
48
|
+
getHeaders() {
|
|
49
|
+
return { ...this.headers };
|
|
50
|
+
}
|
|
51
|
+
getHeaderNames() {
|
|
52
|
+
return Object.keys(this.headers);
|
|
53
|
+
}
|
|
54
|
+
hasHeader(name) {
|
|
55
|
+
return name.toLowerCase() in this.headers;
|
|
56
|
+
}
|
|
57
|
+
removeHeader(name) {
|
|
58
|
+
delete this.headers[name.toLowerCase()];
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
writeHead(statusCode, statusMessage, headers) {
|
|
62
|
+
this.statusCode = statusCode;
|
|
63
|
+
if (typeof statusMessage === "string") {
|
|
64
|
+
this.statusMessage = statusMessage;
|
|
65
|
+
}
|
|
66
|
+
if (typeof statusMessage === "object") {
|
|
67
|
+
headers = statusMessage;
|
|
68
|
+
}
|
|
69
|
+
if (headers) {
|
|
70
|
+
Object.assign(this.headers, headers);
|
|
71
|
+
}
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
write(chunk) {
|
|
75
|
+
this.body += chunk.toString();
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
end(data, encoding, cb) {
|
|
79
|
+
if (data) {
|
|
80
|
+
this.body += data.toString();
|
|
81
|
+
}
|
|
82
|
+
this.finished = true;
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
flushHeaders() {
|
|
86
|
+
this.headersSent = true;
|
|
87
|
+
}
|
|
88
|
+
// Stub methods for interface compliance
|
|
89
|
+
addListener = /* @__PURE__ */ __name$2(() => this, "addListener");
|
|
90
|
+
on = /* @__PURE__ */ __name$2(() => this, "on");
|
|
91
|
+
once = /* @__PURE__ */ __name$2(() => this, "once");
|
|
92
|
+
removeListener = /* @__PURE__ */ __name$2(() => this, "removeListener");
|
|
93
|
+
off = /* @__PURE__ */ __name$2(() => this, "off");
|
|
94
|
+
removeAllListeners = /* @__PURE__ */ __name$2(() => this, "removeAllListeners");
|
|
95
|
+
setMaxListeners = /* @__PURE__ */ __name$2(() => this, "setMaxListeners");
|
|
96
|
+
getMaxListeners = /* @__PURE__ */ __name$2(() => 10, "getMaxListeners");
|
|
97
|
+
listeners = /* @__PURE__ */ __name$2(() => [], "listeners");
|
|
98
|
+
rawListeners = /* @__PURE__ */ __name$2(() => [], "rawListeners");
|
|
99
|
+
emit = /* @__PURE__ */ __name$2(() => false, "emit");
|
|
100
|
+
eventNames = /* @__PURE__ */ __name$2(() => [], "eventNames");
|
|
101
|
+
listenerCount = /* @__PURE__ */ __name$2(() => 0, "listenerCount");
|
|
102
|
+
prependListener = /* @__PURE__ */ __name$2(() => this, "prependListener");
|
|
103
|
+
prependOnceListener = /* @__PURE__ */ __name$2(() => this, "prependOnceListener");
|
|
104
|
+
// Additional methods
|
|
105
|
+
cork = /* @__PURE__ */ __name$2(() => {
|
|
106
|
+
}, "cork");
|
|
107
|
+
uncork = /* @__PURE__ */ __name$2(() => {
|
|
108
|
+
}, "uncork");
|
|
109
|
+
destroy = /* @__PURE__ */ __name$2(() => this, "destroy");
|
|
110
|
+
read = /* @__PURE__ */ __name$2(() => null, "read");
|
|
111
|
+
setEncoding = /* @__PURE__ */ __name$2(() => this, "setEncoding");
|
|
112
|
+
pause = /* @__PURE__ */ __name$2(() => this, "pause");
|
|
113
|
+
resume = /* @__PURE__ */ __name$2(() => this, "resume");
|
|
114
|
+
isPaused = /* @__PURE__ */ __name$2(() => false, "isPaused");
|
|
115
|
+
destroySoon = /* @__PURE__ */ __name$2(() => this, "destroySoon");
|
|
116
|
+
pipe = /* @__PURE__ */ __name$2(() => ({}), "pipe");
|
|
117
|
+
unpipe = /* @__PURE__ */ __name$2(() => this, "unpipe");
|
|
118
|
+
unshift = /* @__PURE__ */ __name$2(() => {
|
|
119
|
+
}, "unshift");
|
|
120
|
+
wrap = /* @__PURE__ */ __name$2(() => this, "wrap");
|
|
121
|
+
setTimeout = /* @__PURE__ */ __name$2(() => this, "setTimeout");
|
|
122
|
+
assignSocket = /* @__PURE__ */ __name$2(() => {
|
|
123
|
+
}, "assignSocket");
|
|
124
|
+
detachSocket = /* @__PURE__ */ __name$2(() => {
|
|
125
|
+
}, "detachSocket");
|
|
126
|
+
writeContinue = /* @__PURE__ */ __name$2(() => {
|
|
127
|
+
}, "writeContinue");
|
|
128
|
+
writeEarlyHints = /* @__PURE__ */ __name$2(() => {
|
|
129
|
+
}, "writeEarlyHints");
|
|
130
|
+
sendDate = true;
|
|
131
|
+
strictContentLength = false;
|
|
132
|
+
chunkedEncoding = false;
|
|
133
|
+
shouldKeepAlive = true;
|
|
134
|
+
useChunkedEncodingByDefault = true;
|
|
135
|
+
_hasBody = true;
|
|
136
|
+
_trailer = "";
|
|
137
|
+
connection = null;
|
|
138
|
+
socket = null;
|
|
139
|
+
}
|
|
140
|
+
const fetchHtmlErrorHandler = /* @__PURE__ */ __name$2((options = {}) => {
|
|
141
|
+
const nodeHandler = htmlErrorHandler(options);
|
|
142
|
+
return async (error, request) => {
|
|
143
|
+
const mockReq = {
|
|
144
|
+
url: request.url,
|
|
145
|
+
method: request.method,
|
|
146
|
+
headers: Object.fromEntries(Array.from(request.headers.entries()))
|
|
147
|
+
};
|
|
148
|
+
const mockRes = new MockServerResponse();
|
|
149
|
+
await nodeHandler(error, mockReq, mockRes);
|
|
150
|
+
const contentType = mockRes.getHeader("content-type") || "text/html; charset=utf-8";
|
|
151
|
+
return new Response(mockRes.body, {
|
|
152
|
+
status: mockRes.statusCode,
|
|
153
|
+
headers: {
|
|
154
|
+
"content-type": contentType,
|
|
155
|
+
...mockRes.headers
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
}, "fetchHtmlErrorHandler");
|
|
160
|
+
|
|
161
|
+
var __defProp$1 = Object.defineProperty;
|
|
162
|
+
var __name$1 = (target, value) => __defProp$1(target, "name", { value, configurable: true });
|
|
163
|
+
const negotiateContentType = /* @__PURE__ */ __name$1((acceptHeader) => {
|
|
164
|
+
if (!acceptHeader) return "text/html";
|
|
165
|
+
const accept = acceptHeader.toLowerCase();
|
|
166
|
+
if (accept.includes("text/html")) return "text/html";
|
|
167
|
+
if (accept.includes("application/vnd.api+json")) return "application/vnd.api+json";
|
|
168
|
+
if (accept.includes("application/problem+json")) return "application/problem+json";
|
|
169
|
+
if (accept.includes("application/json")) return "application/json";
|
|
170
|
+
if (accept.includes("text/plain")) return "text/plain";
|
|
171
|
+
if (accept.includes("application/javascript") || accept.includes("text/javascript")) return "application/javascript";
|
|
172
|
+
if (accept.includes("application/xml") || accept.includes("text/xml")) return "application/xml";
|
|
173
|
+
return "text/html";
|
|
174
|
+
}, "negotiateContentType");
|
|
175
|
+
const adaptErrorHandlerToFetch = /* @__PURE__ */ __name$1((nodeHandler) => {
|
|
176
|
+
return async (error, request) => {
|
|
177
|
+
const mockReq = {
|
|
178
|
+
url: request.url,
|
|
179
|
+
method: request.method,
|
|
180
|
+
headers: Object.fromEntries(request.headers.entries())
|
|
181
|
+
};
|
|
182
|
+
const mockRes = {
|
|
183
|
+
statusCode: 200,
|
|
184
|
+
headers: {},
|
|
185
|
+
_body: "",
|
|
186
|
+
setHeader(name, value) {
|
|
187
|
+
this.headers[name.toLowerCase()] = value;
|
|
188
|
+
},
|
|
189
|
+
getHeader(name) {
|
|
190
|
+
return this.headers[name.toLowerCase()];
|
|
191
|
+
},
|
|
192
|
+
getHeaders() {
|
|
193
|
+
return { ...this.headers };
|
|
194
|
+
},
|
|
195
|
+
writeHead(statusCode) {
|
|
196
|
+
this.statusCode = statusCode;
|
|
197
|
+
},
|
|
198
|
+
write(chunk) {
|
|
199
|
+
this._body += chunk.toString();
|
|
200
|
+
},
|
|
201
|
+
end(data) {
|
|
202
|
+
if (data) {
|
|
203
|
+
this._body += data.toString();
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
flushHeaders() {
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
await nodeHandler(error, mockReq, mockRes);
|
|
210
|
+
const headers = {};
|
|
211
|
+
for (const [key, value] of Object.entries(mockRes.headers)) {
|
|
212
|
+
if (Array.isArray(value)) {
|
|
213
|
+
headers[key] = value.join(", ");
|
|
214
|
+
} else {
|
|
215
|
+
headers[key] = String(value);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return new Response(mockRes._body, {
|
|
219
|
+
status: mockRes.statusCode,
|
|
220
|
+
headers
|
|
221
|
+
});
|
|
222
|
+
};
|
|
223
|
+
}, "adaptErrorHandlerToFetch");
|
|
224
|
+
const createFetchNegotiatedErrorHandler = /* @__PURE__ */ __name$1((errorHandlers, showTrace, defaultHtmlHandler) => async (error, request) => {
|
|
225
|
+
const accept = request.headers.get("accept");
|
|
226
|
+
const chosenType = negotiateContentType(accept);
|
|
227
|
+
let fetchErrorHandler = defaultHtmlHandler || adaptErrorHandlerToFetch(problemErrorHandler);
|
|
228
|
+
if (chosenType === "text/html" && defaultHtmlHandler) {
|
|
229
|
+
fetchErrorHandler = defaultHtmlHandler;
|
|
230
|
+
} else if (chosenType === "application/vnd.api+json") {
|
|
231
|
+
fetchErrorHandler = adaptErrorHandlerToFetch(jsonapiErrorHandler);
|
|
232
|
+
} else if (chosenType === "application/problem+json") {
|
|
233
|
+
fetchErrorHandler = adaptErrorHandlerToFetch(problemErrorHandler);
|
|
234
|
+
} else if (chosenType === "application/json") {
|
|
235
|
+
fetchErrorHandler = adaptErrorHandlerToFetch(jsonErrorHandler());
|
|
236
|
+
} else if (chosenType === "text/plain") {
|
|
237
|
+
fetchErrorHandler = adaptErrorHandlerToFetch(textErrorHandler());
|
|
238
|
+
} else if (chosenType === "application/javascript") {
|
|
239
|
+
fetchErrorHandler = adaptErrorHandlerToFetch(jsonpErrorHandler());
|
|
240
|
+
} else if (chosenType === "application/xml") {
|
|
241
|
+
fetchErrorHandler = adaptErrorHandlerToFetch(xmlErrorHandler());
|
|
242
|
+
}
|
|
243
|
+
for (const { handler, regex } of errorHandlers) {
|
|
244
|
+
const headerStr = accept ?? "";
|
|
245
|
+
if (regex.test(headerStr)) {
|
|
246
|
+
fetchErrorHandler = handler;
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
error.expose = showTrace;
|
|
251
|
+
return fetchErrorHandler(error, request);
|
|
252
|
+
}, "createFetchNegotiatedErrorHandler");
|
|
253
|
+
|
|
254
|
+
var __defProp = Object.defineProperty;
|
|
255
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
256
|
+
const fetchHandler = /* @__PURE__ */ __name(async (error, options = {}) => {
|
|
257
|
+
const defaultHtml = fetchHtmlErrorHandler(options);
|
|
258
|
+
const negotiated = createFetchNegotiatedErrorHandler(options.extraHandlers ?? [], options.showTrace ?? true, defaultHtml);
|
|
259
|
+
return async (request) => {
|
|
260
|
+
if (options?.onError) {
|
|
261
|
+
await options.onError(error, request);
|
|
262
|
+
}
|
|
263
|
+
return negotiated(error, request);
|
|
264
|
+
};
|
|
265
|
+
}, "fetchHandler");
|
|
266
|
+
|
|
267
|
+
export { fetchHandler as default };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import { HtmlErrorHandlerOptions } from '../../error-handler/html-error-handler.js';
|
|
3
|
+
import { E as ErrorHandlers } from '../../packem_shared/types.d-DLy8CCca.js';
|
|
4
|
+
|
|
5
|
+
declare const httpHandler: (error: Error, options?: HtmlErrorHandlerOptions & {
|
|
6
|
+
showTrace?: boolean;
|
|
7
|
+
extraHandlers?: ErrorHandlers;
|
|
8
|
+
onError?: (error: Error, request: IncomingMessage, response: ServerResponse) => void | Promise<void>;
|
|
9
|
+
}) => Promise<(request: IncomingMessage, response: ServerResponse) => Promise<void>>;
|
|
10
|
+
|
|
11
|
+
export { httpHandler as default };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { htmlErrorHandler } from '../../error-handler/html-error-handler.js';
|
|
2
|
+
import createNegotiatedErrorHandler from '../../packem_shared/createNegotiatedErrorHandler-Cd7yj67Z.js';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
|
+
const httpHandler = /* @__PURE__ */ __name(async (error, options = {}) => {
|
|
7
|
+
const defaultHtml = htmlErrorHandler(options);
|
|
8
|
+
const negotiated = createNegotiatedErrorHandler(options.extraHandlers ?? [], options.showTrace ?? true, defaultHtml);
|
|
9
|
+
return async (request, response) => {
|
|
10
|
+
if (options?.onError) {
|
|
11
|
+
await options.onError(error, request, response);
|
|
12
|
+
}
|
|
13
|
+
await negotiated(error, request, response);
|
|
14
|
+
};
|
|
15
|
+
}, "httpHandler");
|
|
16
|
+
|
|
17
|
+
export { httpHandler as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { default as jsonapiErrorHandler } from './error-handler/jsonapi-error-handler.js';
|
|
2
|
+
export { default as problemErrorHandler } from './error-handler/problem-error-handler.js';
|
|
3
|
+
export { HtmlErrorHandlerOptions, htmlErrorHandler } from './error-handler/html-error-handler.js';
|
|
4
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
|
+
import { E as ErrorHandlers, a as ErrorHandler } from './packem_shared/types.d-DLy8CCca.js';
|
|
6
|
+
export { A as ApiFormat } from './packem_shared/types.d-DLy8CCca.js';
|
|
7
|
+
export { TextErrorFormatter, TextErrorHandlerOptions, textErrorHandler } from './error-handler/text-error-handler.js';
|
|
8
|
+
export { JsonErrorBody, JsonErrorFormatter, JsonErrorHandlerOptions, jsonErrorHandler } from './error-handler/json-error-handler.js';
|
|
9
|
+
export { JsonpErrorBody, JsonpErrorFormatter, JsonpErrorHandlerOptions, jsonpErrorHandler } from './error-handler/jsonp-error-handler.js';
|
|
10
|
+
export { ToXmlOptions, XmlErrorBody, XmlErrorFormatter, XmlErrorHandlerOptions, xmlErrorHandler } from './error-handler/xml-error-handler.js';
|
|
11
|
+
|
|
12
|
+
declare const createNegotiatedErrorHandler: <Request extends IncomingMessage, Response extends ServerResponse>(errorHandlers: ErrorHandlers, showTrace: boolean, defaultHtmlHandler?: ErrorHandler) => (error: Error, request: Request, response: Response) => Promise<void>;
|
|
13
|
+
|
|
14
|
+
export { ErrorHandler, ErrorHandlers, createNegotiatedErrorHandler };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { default as jsonapiErrorHandler } from './error-handler/jsonapi-error-handler.js';
|
|
2
|
+
export { default as problemErrorHandler } from './error-handler/problem-error-handler.js';
|
|
3
|
+
export { htmlErrorHandler } from './error-handler/html-error-handler.js';
|
|
4
|
+
export { default as createNegotiatedErrorHandler } from './packem_shared/createNegotiatedErrorHandler-Cd7yj67Z.js';
|
|
5
|
+
export { textErrorHandler } from './error-handler/text-error-handler.js';
|
|
6
|
+
export { jsonErrorHandler } from './error-handler/json-error-handler.js';
|
|
7
|
+
export { jsonpErrorHandler } from './error-handler/jsonp-error-handler.js';
|
|
8
|
+
export { xmlErrorHandler } from './error-handler/xml-error-handler.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { StatusCodes } from 'http-status-codes';
|
|
2
|
+
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
5
|
+
const addStatusCodeToResponse = /* @__PURE__ */ __name((response, error) => {
|
|
6
|
+
const err = error;
|
|
7
|
+
const candidate = Number(err.statusCode ?? err.status);
|
|
8
|
+
if (Number.isInteger(candidate) && candidate >= 400 && candidate <= 599) {
|
|
9
|
+
response.statusCode = candidate;
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (response.statusCode < 400) {
|
|
13
|
+
response.statusCode = StatusCodes.INTERNAL_SERVER_ERROR;
|
|
14
|
+
}
|
|
15
|
+
}, "addStatusCodeToResponse");
|
|
16
|
+
|
|
17
|
+
export { addStatusCodeToResponse as a };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import jsonapiErrorHandler from '../error-handler/jsonapi-error-handler.js';
|
|
2
|
+
import problemErrorHandler from '../error-handler/problem-error-handler.js';
|
|
3
|
+
import { textErrorHandler } from '../error-handler/text-error-handler.js';
|
|
4
|
+
import { jsonErrorHandler } from '../error-handler/json-error-handler.js';
|
|
5
|
+
import { jsonpErrorHandler } from '../error-handler/jsonp-error-handler.js';
|
|
6
|
+
import { xmlErrorHandler } from '../error-handler/xml-error-handler.js';
|
|
7
|
+
import { Accepts } from '@tinyhttp/accepts';
|
|
8
|
+
|
|
9
|
+
var __defProp = Object.defineProperty;
|
|
10
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
11
|
+
const createNegotiatedErrorHandler = /* @__PURE__ */ __name((errorHandlers, showTrace, defaultHtmlHandler) => async (error, request, response) => {
|
|
12
|
+
const accept = new Accepts(request);
|
|
13
|
+
const chosenType = accept.type([
|
|
14
|
+
"text/html",
|
|
15
|
+
"application/vnd.api+json",
|
|
16
|
+
"application/problem+json",
|
|
17
|
+
"application/json",
|
|
18
|
+
"text/plain",
|
|
19
|
+
"application/javascript",
|
|
20
|
+
"text/javascript",
|
|
21
|
+
"application/xml",
|
|
22
|
+
"text/xml"
|
|
23
|
+
]);
|
|
24
|
+
let errorHandler = defaultHtmlHandler || problemErrorHandler;
|
|
25
|
+
if (chosenType === "text/html" && defaultHtmlHandler) {
|
|
26
|
+
errorHandler = defaultHtmlHandler;
|
|
27
|
+
} else if (chosenType === "application/vnd.api+json") {
|
|
28
|
+
errorHandler = jsonapiErrorHandler;
|
|
29
|
+
} else if (chosenType === "application/problem+json") {
|
|
30
|
+
errorHandler = problemErrorHandler;
|
|
31
|
+
} else if (chosenType === "application/json") {
|
|
32
|
+
errorHandler = jsonErrorHandler();
|
|
33
|
+
} else if (chosenType === "text/plain") {
|
|
34
|
+
errorHandler = textErrorHandler();
|
|
35
|
+
} else if (chosenType === "application/javascript" || chosenType === "text/javascript") {
|
|
36
|
+
errorHandler = jsonpErrorHandler();
|
|
37
|
+
} else if (chosenType === "application/xml" || chosenType === "text/xml") {
|
|
38
|
+
errorHandler = xmlErrorHandler();
|
|
39
|
+
}
|
|
40
|
+
for (const { handler, regex } of errorHandlers) {
|
|
41
|
+
const headerVal = request.headers.accept ?? "";
|
|
42
|
+
const headerStr = Array.isArray(headerVal) ? headerVal.join(",") : headerVal;
|
|
43
|
+
if (regex.test(headerStr)) {
|
|
44
|
+
errorHandler = handler;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
error.expose = showTrace;
|
|
49
|
+
await errorHandler(error, request, response);
|
|
50
|
+
}, "createNegotiatedErrorHandler");
|
|
51
|
+
|
|
52
|
+
export { createNegotiatedErrorHandler as default };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
const sendJson = /* @__PURE__ */ __name((response, jsonBody, contentType = "application/json; charset=utf-8") => {
|
|
4
|
+
response.setHeader("content-type", contentType);
|
|
5
|
+
response.end(JSON.stringify(jsonBody));
|
|
6
|
+
}, "sendJson");
|
|
7
|
+
|
|
8
|
+
export { sendJson as s };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
const setErrorHeaders = /* @__PURE__ */ __name((response, error) => {
|
|
4
|
+
const headers = error.headers ?? {};
|
|
5
|
+
Object.keys(headers).forEach((header) => {
|
|
6
|
+
response.setHeader(header, headers[header]);
|
|
7
|
+
});
|
|
8
|
+
}, "setErrorHeaders");
|
|
9
|
+
|
|
10
|
+
export { setErrorHeaders as s };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
|
|
3
|
+
type ErrorHandler = <Request extends IncomingMessage, Response extends ServerResponse>(
|
|
4
|
+
error: Error,
|
|
5
|
+
request: Request,
|
|
6
|
+
response: Response,
|
|
7
|
+
) => Promise<void> | void;
|
|
8
|
+
|
|
9
|
+
type FetchErrorHandler = (
|
|
10
|
+
error: unknown,
|
|
11
|
+
request: Request,
|
|
12
|
+
) => Promise<Response> | Response;
|
|
13
|
+
|
|
14
|
+
type ErrorHandlers = {
|
|
15
|
+
handler: ErrorHandler;
|
|
16
|
+
regex: RegExp;
|
|
17
|
+
}[];
|
|
18
|
+
|
|
19
|
+
type FetchErrorHandlers = {
|
|
20
|
+
handler: FetchErrorHandler;
|
|
21
|
+
regex: RegExp;
|
|
22
|
+
}[];
|
|
23
|
+
|
|
24
|
+
type ApiFormat = "jsonapi" | "problem" | "html";
|
|
25
|
+
|
|
26
|
+
export type { ApiFormat as A, ErrorHandlers as E, FetchErrorHandlers as F, ErrorHandler as a };
|
package/package.json
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@visulima/error-handler",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Error handlers for use in development and production environments.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"visulima",
|
|
7
|
+
"error",
|
|
8
|
+
"exception",
|
|
9
|
+
"error-handlers",
|
|
10
|
+
"diagnostics",
|
|
11
|
+
"debugging",
|
|
12
|
+
"stacktrace",
|
|
13
|
+
"code-frame",
|
|
14
|
+
"codeframe",
|
|
15
|
+
"source-code-preview",
|
|
16
|
+
"content-negotiation",
|
|
17
|
+
"problem-json",
|
|
18
|
+
"rfc7807",
|
|
19
|
+
"jsonapi",
|
|
20
|
+
"json-api",
|
|
21
|
+
"jsonp",
|
|
22
|
+
"xml",
|
|
23
|
+
"html-error",
|
|
24
|
+
"cli",
|
|
25
|
+
"node",
|
|
26
|
+
"express",
|
|
27
|
+
"connect",
|
|
28
|
+
"middleware",
|
|
29
|
+
"http-errors",
|
|
30
|
+
"devtools",
|
|
31
|
+
"error-reporting",
|
|
32
|
+
"whoops",
|
|
33
|
+
"youch",
|
|
34
|
+
"anolilab",
|
|
35
|
+
"error-handler"
|
|
36
|
+
],
|
|
37
|
+
"author": {
|
|
38
|
+
"name": "Daniel Bannert",
|
|
39
|
+
"email": "d.bannert@anolilab.de"
|
|
40
|
+
},
|
|
41
|
+
"funding": [
|
|
42
|
+
{
|
|
43
|
+
"type": "github",
|
|
44
|
+
"url": "https://github.com/sponsors/prisis"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"type": "consulting",
|
|
48
|
+
"url": "https://anolilab.com/support"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"homepage": "https://visulima.com/packages/error-handler",
|
|
52
|
+
"license": "MIT",
|
|
53
|
+
"sideEffects": false,
|
|
54
|
+
"type": "module",
|
|
55
|
+
"exports": {
|
|
56
|
+
".": {
|
|
57
|
+
"types": "./dist/index.d.ts",
|
|
58
|
+
"default": "./dist/index.js"
|
|
59
|
+
},
|
|
60
|
+
"./handler/cli": {
|
|
61
|
+
"types": "./dist/handler/cli-handler.d.ts",
|
|
62
|
+
"default": "./dist/handler/cli-handler.js"
|
|
63
|
+
},
|
|
64
|
+
"./handler/http/node": {
|
|
65
|
+
"types": "./dist/handler/http/node-handler.d.ts",
|
|
66
|
+
"default": "./dist/handler/http/node-handler.js"
|
|
67
|
+
},
|
|
68
|
+
"./handler/http/hono": {
|
|
69
|
+
"types": "./dist/handler/http/fetch-handler.d.ts",
|
|
70
|
+
"default": "./dist/handler/http/fetch-handler.js"
|
|
71
|
+
},
|
|
72
|
+
"./handler/http/bun": {
|
|
73
|
+
"types": "./dist/handler/http/fetch-handler.d.ts",
|
|
74
|
+
"default": "./dist/handler/http/fetch-handler.js"
|
|
75
|
+
},
|
|
76
|
+
"./handler/http/cloudflare": {
|
|
77
|
+
"types": "./dist/handler/http/fetch-handler.d.ts",
|
|
78
|
+
"default": "./dist/handler/http/fetch-handler.js"
|
|
79
|
+
},
|
|
80
|
+
"./handler/http/deno": {
|
|
81
|
+
"types": "./dist/handler/http/fetch-handler.d.ts",
|
|
82
|
+
"default": "./dist/handler/http/fetch-handler.js"
|
|
83
|
+
},
|
|
84
|
+
"./handler/http/edge": {
|
|
85
|
+
"types": "./dist/handler/http/fetch-handler.d.ts",
|
|
86
|
+
"default": "./dist/handler/http/fetch-handler.js"
|
|
87
|
+
},
|
|
88
|
+
"./handler/fetch": {
|
|
89
|
+
"types": "./dist/handler/http/fetch-handler.d.ts",
|
|
90
|
+
"default": "./dist/handler/http/fetch-handler.js"
|
|
91
|
+
},
|
|
92
|
+
"./error-handler/html": {
|
|
93
|
+
"types": "./dist/error-handler/html-error-handler.d.ts",
|
|
94
|
+
"default": "./dist/error-handler/html-error-handler.js"
|
|
95
|
+
},
|
|
96
|
+
"./error-handler/problem": {
|
|
97
|
+
"types": "./dist/error-handler/problem-error-handler.d.ts",
|
|
98
|
+
"default": "./dist/error-handler/problem-error-handler.js"
|
|
99
|
+
},
|
|
100
|
+
"./error-handler/jsonapi": {
|
|
101
|
+
"types": "./dist/error-handler/jsonapi-error-handler.d.ts",
|
|
102
|
+
"default": "./dist/error-handler/jsonapi-error-handler.js"
|
|
103
|
+
},
|
|
104
|
+
"./error-handler/text": {
|
|
105
|
+
"types": "./dist/error-handler/text-error-handler.d.ts",
|
|
106
|
+
"default": "./dist/error-handler/text-error-handler.js"
|
|
107
|
+
},
|
|
108
|
+
"./error-handler/json": {
|
|
109
|
+
"types": "./dist/error-handler/json-error-handler.d.ts",
|
|
110
|
+
"default": "./dist/error-handler/json-error-handler.js"
|
|
111
|
+
},
|
|
112
|
+
"./error-handler/jsonp": {
|
|
113
|
+
"types": "./dist/error-handler/jsonp-error-handler.d.ts",
|
|
114
|
+
"default": "./dist/error-handler/jsonp-error-handler.js"
|
|
115
|
+
},
|
|
116
|
+
"./error-handler/xml": {
|
|
117
|
+
"types": "./dist/error-handler/xml-error-handler.d.ts",
|
|
118
|
+
"default": "./dist/error-handler/xml-error-handler.js"
|
|
119
|
+
},
|
|
120
|
+
"./package.json": "./package.json"
|
|
121
|
+
},
|
|
122
|
+
"files": [
|
|
123
|
+
"dist",
|
|
124
|
+
"README.md",
|
|
125
|
+
"CHANGELOG.md"
|
|
126
|
+
],
|
|
127
|
+
"repository": {
|
|
128
|
+
"type": "git",
|
|
129
|
+
"url": "git+https://github.com/visulima/visulima.git",
|
|
130
|
+
"directory": "packages/error-handler"
|
|
131
|
+
},
|
|
132
|
+
"bugs": {
|
|
133
|
+
"url": "https://github.com/visulima/visulima/issues"
|
|
134
|
+
},
|
|
135
|
+
"engines": {
|
|
136
|
+
"node": ">=20.19 <=24.*"
|
|
137
|
+
},
|
|
138
|
+
"publishConfig": {
|
|
139
|
+
"access": "public",
|
|
140
|
+
"provenance": true
|
|
141
|
+
},
|
|
142
|
+
"dependencies": {
|
|
143
|
+
"@tinyhttp/accepts": "^2.2.3",
|
|
144
|
+
"@visulima/boxen": "2.0.2",
|
|
145
|
+
"@visulima/error": "4.5.0",
|
|
146
|
+
"http-errors": "^2.0.0",
|
|
147
|
+
"http-status-codes": "^2.3.0",
|
|
148
|
+
"jstoxml": "^7.0.1",
|
|
149
|
+
"ts-japi": "^1.12.0"
|
|
150
|
+
}
|
|
151
|
+
}
|