@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@server/next",
3
- "version": "0.21.12",
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",
@@ -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 === true) {
16
- options.cors = { origin: options.domain || "*" };
17
- }
18
- if (typeof options.cors === "string") {
19
- options.cors = { origin: options.cors };
20
- }
21
- if (options.cors && typeof options.cors.origin === "string") {
22
- options.cors.origin = options.cors.origin.toLowerCase();
23
- }
24
- if (options.cors && !options.cors.methods) {
25
- options.cors.methods = "GET,HEAD,POST,PUT,PATCH";
26
- }
27
- if (options.cors && !options.cors.headers) {
28
- options.cors.methods = "*";
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
@@ -1,24 +1,24 @@
1
- export default function cors(configOrigin, origin = "") {
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
- // No origin
8
- if (!origin) {
9
- console.warn("CORS: Missing Origin header");
10
- return null;
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 (/^https?:\/\/localhost(:\d+)?$/.test(origin)) {
15
- return origin;
16
- }
17
+ if (localhost.test(origin)) return origin;
17
18
 
18
- if (configOrigin.toLowerCase().split(/\,\s/g).includes(origin)) {
19
- return origin;
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}" is not allowed`);
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; charset=utf-8";
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; charset=utf-8");
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; charset=utf-8");
85
+ expect(headers["content-type"]).toBe("application/json");
86
86
  });
87
87
  });
@@ -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-Methods", options.methods);
48
- headers.set("Access-Control-Allow-Headers", options.headers);
49
- headers.set("Access-Control-Allow-Origin", origin);
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; charset=utf-8",
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; charset=utf-8");
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; charset=utf-8");
24
+ expect(headers["content-type"]).toEqual("application/json");
25
25
  });
26
26
  });