@server/next 0.21.12 → 0.21.14
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/package.json +1 -1
- package/src/helpers/config.js +23 -14
- package/src/helpers/cors.js +15 -15
- package/src/helpers/cors.test.js +64 -0
- package/src/index.js +1 -1
- package/src/index.test.js +2 -2
- package/src/parseResponse.js +7 -4
- package/src/reply.js +2 -4
- package/src/url.test.js +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@server/next",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.14",
|
|
4
4
|
"description": "A fully-fledged web server with routing, file uploads, sessions, static files, schema validation, websockets, testing, etc.",
|
|
5
5
|
"homepage": "https://server-js.com/",
|
|
6
6
|
"repository": "https://github.com/franciscop/server-next.git",
|
package/src/helpers/config.js
CHANGED
|
@@ -12,20 +12,29 @@ export default function config(options = {}) {
|
|
|
12
12
|
|
|
13
13
|
// CORS
|
|
14
14
|
options.cors = options.cors || env.CORS || null;
|
|
15
|
-
if (options.cors
|
|
16
|
-
options.cors
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
options.cors
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
options.cors.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
options.cors.
|
|
15
|
+
if (options.cors) {
|
|
16
|
+
if (options.cors === true) {
|
|
17
|
+
options.cors = { origin: options.cors };
|
|
18
|
+
}
|
|
19
|
+
if (typeof options.cors === "string") {
|
|
20
|
+
options.cors = { origin: options.cors };
|
|
21
|
+
}
|
|
22
|
+
if (Array.isArray(options.cors)) {
|
|
23
|
+
options.cors = { origin: options.cors };
|
|
24
|
+
}
|
|
25
|
+
if (Array.isArray(options.cors.origin)) {
|
|
26
|
+
options.cors.origin = options.cors.origin.join(",");
|
|
27
|
+
}
|
|
28
|
+
if (typeof options.cors.origin === "string") {
|
|
29
|
+
options.cors.origin = options.cors.origin.toLowerCase();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!options.cors.methods) {
|
|
33
|
+
options.cors.methods = "GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS";
|
|
34
|
+
}
|
|
35
|
+
if (!options.cors.headers) {
|
|
36
|
+
options.cors.headers = "*";
|
|
37
|
+
}
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
// Bucket
|
package/src/helpers/cors.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
// A star should always return a star
|
|
3
|
-
if (configOrigin === "*") return "*";
|
|
1
|
+
const localhost = /^https?:\/\/localhost(:\d+)?$/;
|
|
4
2
|
|
|
3
|
+
// Based on https://expressjs.com/en/resources/middleware/cors.html#configuration-options
|
|
4
|
+
export default function cors(config, origin = "") {
|
|
5
5
|
origin = origin.toLowerCase();
|
|
6
6
|
|
|
7
|
-
//
|
|
8
|
-
if (
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
// When it's true, reflect the origin
|
|
8
|
+
if (config === true) return origin || null;
|
|
9
|
+
|
|
10
|
+
// A star should always return a star
|
|
11
|
+
if (config === "*") return "*";
|
|
12
|
+
|
|
13
|
+
// No origin, it's okay since that means we don't need CORS
|
|
14
|
+
if (!origin) return null;
|
|
12
15
|
|
|
13
16
|
// Coming from localhost
|
|
14
|
-
if (
|
|
15
|
-
return origin;
|
|
16
|
-
}
|
|
17
|
+
if (localhost.test(origin)) return origin;
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
19
|
+
const arr = Array.isArray(config) ? config : config.split(/\s*,\s*/g);
|
|
20
|
+
if (arr.includes(origin)) return origin;
|
|
21
21
|
|
|
22
|
-
console.warn(`CORS: Origin "${origin}"
|
|
22
|
+
console.warn(`CORS: Origin "${origin}" not allowed. Allowed "${config}"`);
|
|
23
23
|
return null;
|
|
24
24
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import server from "../index.js";
|
|
2
|
+
|
|
3
|
+
const origin = "http://localhost:3000/";
|
|
4
|
+
|
|
5
|
+
describe("cors", () => {
|
|
6
|
+
it("can simply enable the cors", async () => {
|
|
7
|
+
const cors = "*";
|
|
8
|
+
const { headers } = await server({ cors })
|
|
9
|
+
.get("/", () => 200)
|
|
10
|
+
.test()
|
|
11
|
+
.get("/", { headers: { origin } });
|
|
12
|
+
|
|
13
|
+
expect(headers).toEqual({
|
|
14
|
+
"access-control-allow-origin": "*",
|
|
15
|
+
"access-control-allow-headers": "*",
|
|
16
|
+
"access-control-allow-methods": "GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS",
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("can disable the cors", async () => {
|
|
21
|
+
const cors = false;
|
|
22
|
+
const { headers } = await server({ cors })
|
|
23
|
+
.get("/", () => 200)
|
|
24
|
+
.test()
|
|
25
|
+
.get("/", { headers: { origin } });
|
|
26
|
+
expect(headers["access-control-allow-origin"]).toBe(undefined);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("gets the wildcard without the origin", async () => {
|
|
30
|
+
const cors = "*";
|
|
31
|
+
const { headers } = await server({ cors })
|
|
32
|
+
.get("/", () => 200)
|
|
33
|
+
.test()
|
|
34
|
+
.get("/");
|
|
35
|
+
expect(headers["access-control-allow-origin"]).toBe("*");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("gets the origin with true", async () => {
|
|
39
|
+
const cors = true;
|
|
40
|
+
const { headers } = await server({ cors })
|
|
41
|
+
.get("/", () => 200)
|
|
42
|
+
.test()
|
|
43
|
+
.get("/", { headers: { origin } });
|
|
44
|
+
expect(headers["access-control-allow-origin"]).toBe(origin);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("gets the correct origin with multiple as string", async () => {
|
|
48
|
+
const cors = "https://a.com/,https://b.com/";
|
|
49
|
+
const { headers } = await server({ cors })
|
|
50
|
+
.get("/", () => 200)
|
|
51
|
+
.test()
|
|
52
|
+
.get("/", { headers: { origin: "https://b.com/" } });
|
|
53
|
+
expect(headers["access-control-allow-origin"]).toBe("https://b.com/");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("gets the correct origin with multiple as array", async () => {
|
|
57
|
+
const cors = ["https://a.com/", "https://b.com/"];
|
|
58
|
+
const { headers } = await server({ cors })
|
|
59
|
+
.get("/", () => 200)
|
|
60
|
+
.test()
|
|
61
|
+
.get("/", { headers: { origin: "https://b.com/" } });
|
|
62
|
+
expect(headers["access-control-allow-origin"]).toBe("https://b.com/");
|
|
63
|
+
});
|
|
64
|
+
});
|
package/src/index.js
CHANGED
|
@@ -224,7 +224,7 @@ server.prototype.test = function () {
|
|
|
224
224
|
const fetch = async (path, options = {}) => {
|
|
225
225
|
if (!options.headers) options.headers = {};
|
|
226
226
|
if (options.body && typeof options.body !== "string") {
|
|
227
|
-
options.headers["content-type"] = "application/json
|
|
227
|
+
options.headers["content-type"] = "application/json";
|
|
228
228
|
options.body = JSON.stringify(options.body);
|
|
229
229
|
}
|
|
230
230
|
if (cookie && !options.headers.cookie) {
|
package/src/index.test.js
CHANGED
|
@@ -75,13 +75,13 @@ describe("simple post works", () => {
|
|
|
75
75
|
const { body, status, headers } = await api.post("/", "New Data");
|
|
76
76
|
expect(status).toBe(201);
|
|
77
77
|
expect(body).toBe("New Data");
|
|
78
|
-
expect(headers["content-type"]).toBe("text/plain
|
|
78
|
+
expect(headers["content-type"]).toBe("text/plain");
|
|
79
79
|
});
|
|
80
80
|
|
|
81
81
|
it("will return JSON", async () => {
|
|
82
82
|
const { body, status, headers } = await api.post("/", { hello: "world" });
|
|
83
83
|
expect(status).toBe(201);
|
|
84
84
|
expect(body).toEqual({ hello: "world" });
|
|
85
|
-
expect(headers["content-type"]).toBe("application/json
|
|
85
|
+
expect(headers["content-type"]).toBe("application/json");
|
|
86
86
|
});
|
|
87
87
|
});
|
package/src/parseResponse.js
CHANGED
|
@@ -42,11 +42,14 @@ export default async function parseResponse(out, ctx) {
|
|
|
42
42
|
// If we have CORS, set it up
|
|
43
43
|
if (ctx.options.cors) {
|
|
44
44
|
// Set the proper CORS headers
|
|
45
|
-
const origin = cors(ctx.options.cors, ctx.headers.origin);
|
|
45
|
+
const origin = cors(ctx.options.cors.origin, ctx.headers.origin);
|
|
46
46
|
if (origin) {
|
|
47
|
-
headers.set("Access-Control-Allow-
|
|
48
|
-
headers.set("Access-Control-Allow-
|
|
49
|
-
headers.set("Access-Control-Allow-
|
|
47
|
+
out.headers.set("Access-Control-Allow-Origin", origin);
|
|
48
|
+
out.headers.set("Access-Control-Allow-Methods", ctx.options.cors.methods);
|
|
49
|
+
out.headers.set("Access-Control-Allow-Headers", ctx.options.cors.headers);
|
|
50
|
+
if (ctx.options.cors.credentials) {
|
|
51
|
+
out.headers.set("Access-Control-Allow-Credentials", "true");
|
|
52
|
+
}
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
|
package/src/reply.js
CHANGED
|
@@ -56,7 +56,7 @@ Reply.prototype.cookies = function (cookies) {
|
|
|
56
56
|
// FINAL
|
|
57
57
|
Reply.prototype.json = function (body) {
|
|
58
58
|
return this.headers({
|
|
59
|
-
"content-type": "application/json
|
|
59
|
+
"content-type": "application/json",
|
|
60
60
|
}).send(JSON.stringify(body));
|
|
61
61
|
};
|
|
62
62
|
|
|
@@ -95,9 +95,7 @@ Reply.prototype.send = function (body = "") {
|
|
|
95
95
|
// Not yet set, so infer the type from type of string
|
|
96
96
|
if (!this.res.headers["content-type"]) {
|
|
97
97
|
const isHtml = body.startsWith("<");
|
|
98
|
-
this.res.headers["content-type"] = isHtml
|
|
99
|
-
? "text/html; charset=utf-8"
|
|
100
|
-
: "text/plain; charset=utf-8";
|
|
98
|
+
this.res.headers["content-type"] = isHtml ? "text/html" : "text/plain";
|
|
101
99
|
}
|
|
102
100
|
|
|
103
101
|
const headers = this.generateHeaders();
|
package/src/url.test.js
CHANGED
|
@@ -9,7 +9,7 @@ describe("can match the url", () => {
|
|
|
9
9
|
|
|
10
10
|
const { body, headers } = await api.get("/hello");
|
|
11
11
|
expect(body).toEqual({ id: "hello" });
|
|
12
|
-
expect(headers["content-type"]).toEqual("application/json
|
|
12
|
+
expect(headers["content-type"]).toEqual("application/json");
|
|
13
13
|
});
|
|
14
14
|
|
|
15
15
|
it("but it doesn't if it's a use", async () => {
|
|
@@ -21,6 +21,6 @@ describe("can match the url", () => {
|
|
|
21
21
|
|
|
22
22
|
const { body, headers, ...rest } = await api.get("/hello");
|
|
23
23
|
expect(body).toEqual({ id: "hello" });
|
|
24
|
-
expect(headers["content-type"]).toEqual("application/json
|
|
24
|
+
expect(headers["content-type"]).toEqual("application/json");
|
|
25
25
|
});
|
|
26
26
|
});
|