@fastly/expressly 2.1.0 → 2.2.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/dist/lib/routing/error-middleware.d.ts +5 -4
- package/dist/lib/routing/errors.d.ts +6 -2
- package/dist/lib/routing/errors.js +9 -2
- package/dist/lib/routing/router.d.ts +13 -4
- package/dist/lib/routing/router.js +45 -45
- package/package.json +1 -1
- package/test-d/error-test-d.ts +34 -0
package/CHANGELOG.md
ADDED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { EReq } from "./request";
|
|
2
2
|
import { ERes } from "./response";
|
|
3
|
-
|
|
4
|
-
export
|
|
3
|
+
import { EErr } from "./errors";
|
|
4
|
+
export type ErrorMiddlewareCallback<Err extends EErr = EErr, Req extends EReq = EReq, Res extends ERes = ERes> = (err: Err, req: Req, res: Res) => Promise<any> | void;
|
|
5
|
+
export declare class ErrorMiddleware<Err extends EErr = EErr, Req extends EReq = EReq, Res extends ERes = ERes> {
|
|
5
6
|
private matchFn;
|
|
6
7
|
private callback;
|
|
7
8
|
constructor(matchFn: Function, callback: ErrorMiddlewareCallback);
|
|
8
|
-
check(event:
|
|
9
|
-
run(err:
|
|
9
|
+
check(event: Req): 0 | 404 | string[];
|
|
10
|
+
run(err: Err, req: Req, res: Res): Promise<any>;
|
|
10
11
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
export declare class
|
|
1
|
+
export declare class EErr extends Error {
|
|
2
|
+
status: number;
|
|
3
|
+
constructor(message?: string);
|
|
4
|
+
}
|
|
5
|
+
export declare class ErrorNotFound extends EErr {
|
|
2
6
|
status: number;
|
|
3
7
|
constructor();
|
|
4
8
|
}
|
|
5
|
-
export declare class ErrorMethodNotAllowed extends
|
|
9
|
+
export declare class ErrorMethodNotAllowed extends EErr {
|
|
6
10
|
status: number;
|
|
7
11
|
allow: string;
|
|
8
12
|
constructor(allowedMethods: string[]);
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
export class
|
|
1
|
+
export class EErr extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.status = 500;
|
|
5
|
+
Object.setPrototypeOf(this, EErr.prototype);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export class ErrorNotFound extends EErr {
|
|
2
9
|
constructor() {
|
|
3
10
|
super("Not Found");
|
|
4
11
|
this.status = 404;
|
|
5
12
|
Object.setPrototypeOf(this, ErrorNotFound.prototype);
|
|
6
13
|
}
|
|
7
14
|
}
|
|
8
|
-
export class ErrorMethodNotAllowed extends
|
|
15
|
+
export class ErrorMethodNotAllowed extends EErr {
|
|
9
16
|
constructor(allowedMethods) {
|
|
10
17
|
super("Method Not Allowed");
|
|
11
18
|
this.status = 405;
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import { EConfig, Method } from ".";
|
|
2
2
|
import { RequestHandler, RequestHandlerCallback } from "./request-handler";
|
|
3
3
|
import { ErrorMiddleware, ErrorMiddlewareCallback } from "./error-middleware";
|
|
4
|
+
import { EErr } from "./errors";
|
|
4
5
|
import { EReq } from "./request";
|
|
5
6
|
import { ERes } from "./response";
|
|
6
|
-
export declare class Router<Req extends EReq = EReq, Res extends ERes = ERes> {
|
|
7
|
-
requestHandlers: Array<RequestHandler
|
|
8
|
-
errorHandlers: Array<ErrorMiddleware
|
|
7
|
+
export declare class Router<Req extends EReq = EReq, Res extends ERes = ERes, Err extends EErr = EErr> {
|
|
8
|
+
requestHandlers: Array<RequestHandler<Req, Res>>;
|
|
9
|
+
errorHandlers: Array<ErrorMiddleware<Err, Req, Res>>;
|
|
9
10
|
config: EConfig;
|
|
10
11
|
constructor(config?: EConfig);
|
|
11
12
|
listen(): void;
|
|
12
13
|
private handler;
|
|
13
|
-
|
|
14
|
+
private defaultErrorHandler;
|
|
15
|
+
/**
|
|
16
|
+
* Handles preflight requests from trusted origins configured by the user when initializing a router.
|
|
17
|
+
* Note that the wildcard value "*" will fail if the request is sent with credentials (see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin#directives)
|
|
18
|
+
* @param autoCorsPreflight the object containing CORS preflight option of trustedOrigins, an array of trusted origins.
|
|
19
|
+
* @returns 200 if the preflight request succeeds, 403 if it fails
|
|
20
|
+
*/
|
|
21
|
+
private preflightHandler;
|
|
22
|
+
use(path: string | RequestHandlerCallback<Req, Res> | ErrorMiddlewareCallback<Err, Req, Res>, callback?: RequestHandlerCallback<Req, Res> | ErrorMiddlewareCallback<Err, Req, Res>): void;
|
|
14
23
|
route(methods: Method[], pattern: string, callback: RequestHandlerCallback<Req, Res>): void;
|
|
15
24
|
all(pattern: string, callback: RequestHandlerCallback<Req, Res>): void;
|
|
16
25
|
get(pattern: string, callback: RequestHandlerCallback<Req, Res>): void;
|
|
@@ -5,49 +5,6 @@ import { ErrorNotFound, ErrorMethodNotAllowed } from "./errors";
|
|
|
5
5
|
import { ERequest } from "./request";
|
|
6
6
|
import { EResponse } from "./response";
|
|
7
7
|
const pathMatcherCache = new Map();
|
|
8
|
-
const defaultErrorHandler = (auto405) => async (err, req, res) => {
|
|
9
|
-
if (err instanceof ErrorNotFound || (err instanceof ErrorMethodNotAllowed && !auto405)) {
|
|
10
|
-
return res.sendStatus(404);
|
|
11
|
-
}
|
|
12
|
-
else if (err instanceof ErrorMethodNotAllowed) {
|
|
13
|
-
res.headers.set("Allow", err.allow);
|
|
14
|
-
return res.sendStatus(405);
|
|
15
|
-
}
|
|
16
|
-
console.error(err);
|
|
17
|
-
res.withStatus(500).json({ error: err.message });
|
|
18
|
-
};
|
|
19
|
-
/**
|
|
20
|
-
* Handles preflight requests from trusted origins configured by the user when initializing a router.
|
|
21
|
-
* Note that the wildcard value "*" will fail if the request is sent with credentials (see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin#directives)
|
|
22
|
-
* @param autoCorsPreflight the object containing CORS preflight option of trustedOrigins, an array of trusted origins.
|
|
23
|
-
* @returns 200 if the preflight request succeeds, 403 if it fails
|
|
24
|
-
*/
|
|
25
|
-
const preflightHandler = (autoCorsPreflight) => async (req, res) => {
|
|
26
|
-
if (autoCorsPreflight.trustedOrigins.length === 0) {
|
|
27
|
-
return res.sendStatus(403);
|
|
28
|
-
}
|
|
29
|
-
let originHeaderValue = null;
|
|
30
|
-
if (autoCorsPreflight.trustedOrigins.length === 1 && autoCorsPreflight.trustedOrigins[0] === "*") {
|
|
31
|
-
originHeaderValue = "*";
|
|
32
|
-
}
|
|
33
|
-
else if (req.headers.has("origin")) {
|
|
34
|
-
const origin = req.headers.get("origin").toLowerCase();
|
|
35
|
-
if (autoCorsPreflight.trustedOrigins.some((trustedOrigin) => trustedOrigin.toLowerCase() === origin)) {
|
|
36
|
-
originHeaderValue = origin;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
if (!originHeaderValue) {
|
|
40
|
-
return res.sendStatus(403);
|
|
41
|
-
}
|
|
42
|
-
if (req.headers.has("access-control-request-method")) {
|
|
43
|
-
res.headers.set("access-control-allow-methods", req.headers.get("access-control-request-method"));
|
|
44
|
-
}
|
|
45
|
-
if (req.headers.has("access-control-request-headers")) {
|
|
46
|
-
res.headers.set("access-control-allow-headers", req.headers.get("access-control-request-headers"));
|
|
47
|
-
}
|
|
48
|
-
res.headers.set("access-control-allow-origin", originHeaderValue);
|
|
49
|
-
return res.sendStatus(200);
|
|
50
|
-
};
|
|
51
8
|
export class Router {
|
|
52
9
|
constructor(config) {
|
|
53
10
|
this.requestHandlers = [];
|
|
@@ -63,7 +20,7 @@ export class Router {
|
|
|
63
20
|
...config
|
|
64
21
|
};
|
|
65
22
|
if (this.config.autoCorsPreflight) {
|
|
66
|
-
this.options("*",
|
|
23
|
+
this.options("*", this.preflightHandler);
|
|
67
24
|
}
|
|
68
25
|
}
|
|
69
26
|
listen() {
|
|
@@ -78,12 +35,55 @@ export class Router {
|
|
|
78
35
|
}
|
|
79
36
|
catch (err) {
|
|
80
37
|
// Add default error handler.
|
|
81
|
-
this.use(
|
|
38
|
+
this.use(this.defaultErrorHandler);
|
|
82
39
|
// Run error handler stack.
|
|
83
40
|
await this.runErrorHandlers(err, req, res);
|
|
84
41
|
}
|
|
85
42
|
return Router.serializeResponse(res);
|
|
86
43
|
}
|
|
44
|
+
async defaultErrorHandler(err, req, res) {
|
|
45
|
+
if (err instanceof ErrorNotFound || (err instanceof ErrorMethodNotAllowed && !this.config.auto405)) {
|
|
46
|
+
return res.sendStatus(404);
|
|
47
|
+
}
|
|
48
|
+
else if (err instanceof ErrorMethodNotAllowed) {
|
|
49
|
+
res.headers.set("Allow", err.allow);
|
|
50
|
+
return res.sendStatus(405);
|
|
51
|
+
}
|
|
52
|
+
console.error(err);
|
|
53
|
+
res.withStatus(500).json({ error: err.message });
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Handles preflight requests from trusted origins configured by the user when initializing a router.
|
|
57
|
+
* Note that the wildcard value "*" will fail if the request is sent with credentials (see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin#directives)
|
|
58
|
+
* @param autoCorsPreflight the object containing CORS preflight option of trustedOrigins, an array of trusted origins.
|
|
59
|
+
* @returns 200 if the preflight request succeeds, 403 if it fails
|
|
60
|
+
*/
|
|
61
|
+
async preflightHandler(req, res) {
|
|
62
|
+
if (this.config.autoCorsPreflight.trustedOrigins.length === 0) {
|
|
63
|
+
return res.sendStatus(403);
|
|
64
|
+
}
|
|
65
|
+
let originHeaderValue = null;
|
|
66
|
+
if (this.config.autoCorsPreflight.trustedOrigins.includes("*")) {
|
|
67
|
+
originHeaderValue = "*";
|
|
68
|
+
}
|
|
69
|
+
else if (req.headers.has("origin")) {
|
|
70
|
+
const origin = req.headers.get("origin").toLowerCase();
|
|
71
|
+
if (this.config.autoCorsPreflight.trustedOrigins.some((trustedOrigin) => trustedOrigin.toLowerCase() === origin)) {
|
|
72
|
+
originHeaderValue = origin;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!originHeaderValue) {
|
|
76
|
+
return res.sendStatus(403);
|
|
77
|
+
}
|
|
78
|
+
if (req.headers.has("access-control-request-method")) {
|
|
79
|
+
res.headers.set("access-control-allow-methods", req.headers.get("access-control-request-method"));
|
|
80
|
+
}
|
|
81
|
+
if (req.headers.has("access-control-request-headers")) {
|
|
82
|
+
res.headers.set("access-control-allow-headers", req.headers.get("access-control-request-headers"));
|
|
83
|
+
}
|
|
84
|
+
res.headers.set("access-control-allow-origin", originHeaderValue);
|
|
85
|
+
return res.sendStatus(200);
|
|
86
|
+
}
|
|
87
87
|
// Middleware attach point.
|
|
88
88
|
use(path, callback) {
|
|
89
89
|
const cb = path instanceof Function ? path : callback;
|
package/package.json
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { expectType } from 'tsd';
|
|
2
|
+
import { Router } from "../dist";
|
|
3
|
+
import { EReq } from "../dist/lib/routing/request";
|
|
4
|
+
import { ERes } from '../dist/lib/routing/response';
|
|
5
|
+
import { EErr } from "../dist/lib/routing/errors";
|
|
6
|
+
|
|
7
|
+
// Default Err types
|
|
8
|
+
{
|
|
9
|
+
const router = new Router();
|
|
10
|
+
router.use(async (err, _, res) => {
|
|
11
|
+
expectType<EErr>(err)
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Custom Req and Res types
|
|
16
|
+
{
|
|
17
|
+
interface MeowErr extends EErr {
|
|
18
|
+
meow(): string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface WoofErr extends EErr {
|
|
22
|
+
woof(): string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface MyErr extends MeowErr, WoofErr { }
|
|
26
|
+
|
|
27
|
+
const router = new Router<EReq,ERes,MyErr>();
|
|
28
|
+
router.use(async (err, _, res) => {
|
|
29
|
+
expectType<MyErr>(err)
|
|
30
|
+
err.meow()
|
|
31
|
+
err.woof()
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
}
|