@jsenv/server 15.0.2 → 15.0.3
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/README.md +23 -23
- package/package.json +3 -3
- package/src/content_negotiation/pick_accepted_content.js +13 -13
- package/src/content_negotiation/pick_content_encoding.js +25 -25
- package/src/content_negotiation/pick_content_language.js +35 -34
- package/src/content_negotiation/pick_content_type.js +29 -29
- package/src/fetch_filesystem.js +110 -107
- package/src/from_fetch_response.js +6 -6
- package/src/interfacing_with_node/body.js +22 -22
- package/src/interfacing_with_node/observable.js +80 -80
- package/src/interfacing_with_node/observable_from_node_stream.js +35 -35
- package/src/interfacing_with_node/request_factory.js +26 -26
- package/src/interfacing_with_node/write_node_response.js +82 -82
- package/src/internal/colorizeResponseStatus.js +26 -26
- package/src/internal/convertFileSystemErrorToResponseProperties.js +10 -10
- package/src/internal/dns_resolution.js +7 -7
- package/src/internal/etag.js +11 -11
- package/src/internal/filesystem.js +19 -19
- package/src/internal/headersFromObject.js +8 -8
- package/src/internal/headersFromString.js +11 -11
- package/src/internal/headersToObject.js +5 -5
- package/src/internal/headersToString.js +7 -7
- package/src/internal/headers_composition.js +9 -9
- package/src/internal/hostname_parser.js +9 -9
- package/src/internal/listen.js +47 -47
- package/src/internal/listenClientError.js +10 -10
- package/src/internal/listenEvent.js +5 -5
- package/src/internal/listenRequest.js +8 -8
- package/src/internal/listenServerConnectionError.js +19 -19
- package/src/internal/multiple-header.js +50 -50
- package/src/internal/normalizeHeaderName.js +4 -4
- package/src/internal/normalizeHeaderValue.js +2 -2
- package/src/internal/object_composition.js +41 -39
- package/src/internal/response_composition.js +6 -6
- package/src/internal/server-polyglot.js +42 -42
- package/src/internal/server_ips.js +20 -20
- package/src/internal/trackServerPendingConnections.js +23 -23
- package/src/internal/trackServerPendingRequests.js +28 -28
- package/src/main.js +18 -18
- package/src/readRequestBody.js +15 -15
- package/src/serve_directory.js +16 -16
- package/src/server_timing/timing_header.js +24 -24
- package/src/server_timing/timing_measure.js +14 -14
- package/src/service_composition/path_to_regexp.js +173 -168
- package/src/service_composition/routing.js +12 -12
- package/src/service_controller.js +77 -77
- package/src/services/cors/jsenv_service_cors.js +29 -29
- package/src/services/error_handler/jsenv_service_error_handler.js +18 -18
- package/src/services/request_aliases/jsenv_service_request_aliases.js +20 -20
- package/src/services/response_acceptance_check/jsenv_service_response_acceptance_check.js +16 -16
- package/src/sse/sse_room.js +117 -115
- package/src/start_server.js +328 -328
- package/src/stopReasons.js +9 -9
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
`@jsenv/server` helps to write flexible server code with a declarative API.
|
|
4
4
|
|
|
5
5
|
```js
|
|
6
|
-
import { startServer } from "@jsenv/server"
|
|
6
|
+
import { startServer } from "@jsenv/server";
|
|
7
7
|
|
|
8
8
|
await startServer({
|
|
9
9
|
port: 8080,
|
|
@@ -16,11 +16,11 @@ await startServer({
|
|
|
16
16
|
"content-type": "text/plain",
|
|
17
17
|
},
|
|
18
18
|
body: "Hello world",
|
|
19
|
-
}
|
|
19
|
+
};
|
|
20
20
|
},
|
|
21
21
|
},
|
|
22
22
|
],
|
|
23
|
-
})
|
|
23
|
+
});
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
# Examples
|
|
@@ -35,7 +35,7 @@ _Code starting a server with 2 request handlers:_
|
|
|
35
35
|
* - otherwise
|
|
36
36
|
* -> respond with 404
|
|
37
37
|
*/
|
|
38
|
-
import { startServer, composeServices } from "@jsenv/server"
|
|
38
|
+
import { startServer, composeServices } from "@jsenv/server";
|
|
39
39
|
|
|
40
40
|
const server = await startServer({
|
|
41
41
|
services: [
|
|
@@ -43,33 +43,33 @@ const server = await startServer({
|
|
|
43
43
|
name: "index",
|
|
44
44
|
handleRequest: (request) => {
|
|
45
45
|
if (request.resource === "/") {
|
|
46
|
-
return { status: 200 }
|
|
46
|
+
return { status: 200 };
|
|
47
47
|
}
|
|
48
|
-
return null
|
|
48
|
+
return null;
|
|
49
49
|
},
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
name: "otherwise",
|
|
53
53
|
handleRequest: () => {
|
|
54
|
-
return { status: 404 }
|
|
54
|
+
return { status: 404 };
|
|
55
55
|
},
|
|
56
56
|
},
|
|
57
57
|
],
|
|
58
|
-
})
|
|
58
|
+
});
|
|
59
59
|
|
|
60
|
-
const fetch = await import("node-fetch")
|
|
61
|
-
const responseForOrigin = await fetch(server.origin)
|
|
62
|
-
responseForOrigin.status // 200
|
|
60
|
+
const fetch = await import("node-fetch");
|
|
61
|
+
const responseForOrigin = await fetch(server.origin);
|
|
62
|
+
responseForOrigin.status; // 200
|
|
63
63
|
|
|
64
|
-
const responseForFoo = await fetch(`${server.origin}/foo`)
|
|
65
|
-
responseForFoo.status // 404
|
|
64
|
+
const responseForFoo = await fetch(`${server.origin}/foo`);
|
|
65
|
+
responseForFoo.status; // 404
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
_Code starting a server in https:_
|
|
69
69
|
|
|
70
70
|
```js
|
|
71
|
-
import { readFileSync } from "node:fs"
|
|
72
|
-
import { startServer } from "@jsenv/server"
|
|
71
|
+
import { readFileSync } from "node:fs";
|
|
72
|
+
import { startServer } from "@jsenv/server";
|
|
73
73
|
|
|
74
74
|
await startServer({
|
|
75
75
|
https: {
|
|
@@ -80,7 +80,7 @@ await startServer({
|
|
|
80
80
|
services: [
|
|
81
81
|
{
|
|
82
82
|
handleRequest: (request) => {
|
|
83
|
-
const clientUsesHttp = request.origin.startsWith("http:")
|
|
83
|
+
const clientUsesHttp = request.origin.startsWith("http:");
|
|
84
84
|
|
|
85
85
|
return {
|
|
86
86
|
status: 200,
|
|
@@ -88,29 +88,29 @@ await startServer({
|
|
|
88
88
|
"content-type": "text/plain",
|
|
89
89
|
},
|
|
90
90
|
body: clientUsesHttp ? `Welcome http user` : `Welcome https user`,
|
|
91
|
-
}
|
|
91
|
+
};
|
|
92
92
|
},
|
|
93
93
|
},
|
|
94
94
|
],
|
|
95
|
-
})
|
|
95
|
+
});
|
|
96
96
|
```
|
|
97
97
|
|
|
98
98
|
_Code starting a server for static files:_
|
|
99
99
|
|
|
100
100
|
```js
|
|
101
|
-
import { startServer, fetchFileSystem } from "@jsenv/server"
|
|
101
|
+
import { startServer, fetchFileSystem } from "@jsenv/server";
|
|
102
102
|
|
|
103
103
|
await startServer({
|
|
104
104
|
services: [
|
|
105
105
|
{
|
|
106
106
|
handleRequest: async (request) => {
|
|
107
|
-
const fileUrl = new URL(request.resource.slice(1), import.meta.url)
|
|
108
|
-
const response = await fetchFileSystem(fileUrl, request)
|
|
109
|
-
return response
|
|
107
|
+
const fileUrl = new URL(request.resource.slice(1), import.meta.url);
|
|
108
|
+
const response = await fetchFileSystem(fileUrl, request);
|
|
109
|
+
return response;
|
|
110
110
|
},
|
|
111
111
|
},
|
|
112
112
|
],
|
|
113
|
-
})
|
|
113
|
+
});
|
|
114
114
|
```
|
|
115
115
|
|
|
116
116
|
# Documentation
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/server",
|
|
3
|
-
"version": "15.0.
|
|
3
|
+
"version": "15.0.3",
|
|
4
4
|
"description": "Write your Node.js server using pure functions",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
13
|
-
"url": "https://github.com/jsenv/
|
|
13
|
+
"url": "https://github.com/jsenv/core",
|
|
14
14
|
"directory": "packages/server"
|
|
15
15
|
},
|
|
16
16
|
"engines": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@jsenv/abort": "4.2.4",
|
|
38
|
-
"@jsenv/log": "3.3.
|
|
38
|
+
"@jsenv/log": "3.3.5",
|
|
39
39
|
"@jsenv/url-meta": "8.1.0",
|
|
40
40
|
"@jsenv/utils": "2.0.1",
|
|
41
41
|
"ws": "8.13.0"
|
|
@@ -3,24 +3,24 @@ export const pickAcceptedContent = ({
|
|
|
3
3
|
accepteds,
|
|
4
4
|
getAcceptanceScore,
|
|
5
5
|
}) => {
|
|
6
|
-
let highestScore = -1
|
|
7
|
-
let availableWithHighestScore = null
|
|
8
|
-
let availableIndex = 0
|
|
6
|
+
let highestScore = -1;
|
|
7
|
+
let availableWithHighestScore = null;
|
|
8
|
+
let availableIndex = 0;
|
|
9
9
|
while (availableIndex < availables.length) {
|
|
10
|
-
const available = availables[availableIndex]
|
|
11
|
-
availableIndex
|
|
10
|
+
const available = availables[availableIndex];
|
|
11
|
+
availableIndex++;
|
|
12
12
|
|
|
13
|
-
let acceptedIndex = 0
|
|
13
|
+
let acceptedIndex = 0;
|
|
14
14
|
while (acceptedIndex < accepteds.length) {
|
|
15
|
-
const accepted = accepteds[acceptedIndex]
|
|
16
|
-
acceptedIndex
|
|
15
|
+
const accepted = accepteds[acceptedIndex];
|
|
16
|
+
acceptedIndex++;
|
|
17
17
|
|
|
18
|
-
const score = getAcceptanceScore(accepted, available)
|
|
18
|
+
const score = getAcceptanceScore(accepted, available);
|
|
19
19
|
if (score > highestScore) {
|
|
20
|
-
availableWithHighestScore = available
|
|
21
|
-
highestScore = score
|
|
20
|
+
availableWithHighestScore = available;
|
|
21
|
+
highestScore = score;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
return availableWithHighestScore
|
|
26
|
-
}
|
|
25
|
+
return availableWithHighestScore;
|
|
26
|
+
};
|
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
import { parseMultipleHeader } from "../internal/multiple-header.js"
|
|
2
|
-
import { pickAcceptedContent } from "./pick_accepted_content.js"
|
|
1
|
+
import { parseMultipleHeader } from "../internal/multiple-header.js";
|
|
2
|
+
import { pickAcceptedContent } from "./pick_accepted_content.js";
|
|
3
3
|
|
|
4
4
|
export const pickContentEncoding = (request, availableEncodings) => {
|
|
5
|
-
const { headers = {} } = request
|
|
6
|
-
const requestAcceptEncodingHeader = headers["accept-encoding"]
|
|
5
|
+
const { headers = {} } = request;
|
|
6
|
+
const requestAcceptEncodingHeader = headers["accept-encoding"];
|
|
7
7
|
if (!requestAcceptEncodingHeader) {
|
|
8
|
-
return null
|
|
8
|
+
return null;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
const encodingsAccepted = parseAcceptEncodingHeader(
|
|
12
12
|
requestAcceptEncodingHeader,
|
|
13
|
-
)
|
|
13
|
+
);
|
|
14
14
|
return pickAcceptedContent({
|
|
15
15
|
accepteds: encodingsAccepted,
|
|
16
16
|
availables: availableEncodings,
|
|
17
17
|
getAcceptanceScore: getEncodingAcceptanceScore,
|
|
18
|
-
})
|
|
19
|
-
}
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
20
|
|
|
21
21
|
const parseAcceptEncodingHeader = (acceptEncodingHeaderString) => {
|
|
22
22
|
const acceptEncodingHeader = parseMultipleHeader(acceptEncodingHeaderString, {
|
|
23
23
|
validateProperty: ({ name }) => {
|
|
24
24
|
// read only q, anything else is ignored
|
|
25
|
-
return name === "q"
|
|
25
|
+
return name === "q";
|
|
26
26
|
},
|
|
27
|
-
})
|
|
27
|
+
});
|
|
28
28
|
|
|
29
|
-
const encodingsAccepted = []
|
|
29
|
+
const encodingsAccepted = [];
|
|
30
30
|
Object.keys(acceptEncodingHeader).forEach((key) => {
|
|
31
|
-
const { q = 1 } = acceptEncodingHeader[key]
|
|
32
|
-
const value = key
|
|
31
|
+
const { q = 1 } = acceptEncodingHeader[key];
|
|
32
|
+
const value = key;
|
|
33
33
|
encodingsAccepted.push({
|
|
34
34
|
value,
|
|
35
35
|
quality: q,
|
|
36
|
-
})
|
|
37
|
-
})
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
38
|
encodingsAccepted.sort((a, b) => {
|
|
39
|
-
return b.quality - a.quality
|
|
40
|
-
})
|
|
41
|
-
return encodingsAccepted
|
|
42
|
-
}
|
|
39
|
+
return b.quality - a.quality;
|
|
40
|
+
});
|
|
41
|
+
return encodingsAccepted;
|
|
42
|
+
};
|
|
43
43
|
|
|
44
44
|
const getEncodingAcceptanceScore = ({ value, quality }, availableEncoding) => {
|
|
45
45
|
if (value === "*") {
|
|
46
|
-
return quality
|
|
46
|
+
return quality;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
// normalize br to brotli
|
|
50
|
-
if (value === "br") value = "brotli"
|
|
51
|
-
if (availableEncoding === "br") availableEncoding = "brotli"
|
|
50
|
+
if (value === "br") value = "brotli";
|
|
51
|
+
if (availableEncoding === "br") availableEncoding = "brotli";
|
|
52
52
|
|
|
53
53
|
if (value === availableEncoding) {
|
|
54
|
-
return quality
|
|
54
|
+
return quality;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
return -1
|
|
58
|
-
}
|
|
57
|
+
return -1;
|
|
58
|
+
};
|
|
@@ -1,77 +1,78 @@
|
|
|
1
|
-
import { parseMultipleHeader } from "../internal/multiple-header.js"
|
|
2
|
-
import { pickAcceptedContent } from "./pick_accepted_content.js"
|
|
1
|
+
import { parseMultipleHeader } from "../internal/multiple-header.js";
|
|
2
|
+
import { pickAcceptedContent } from "./pick_accepted_content.js";
|
|
3
3
|
|
|
4
4
|
export const pickContentLanguage = (request, availableLanguages) => {
|
|
5
|
-
const { headers = {} } = request
|
|
6
|
-
const requestAcceptLanguageHeader = headers["accept-language"]
|
|
5
|
+
const { headers = {} } = request;
|
|
6
|
+
const requestAcceptLanguageHeader = headers["accept-language"];
|
|
7
7
|
if (!requestAcceptLanguageHeader) {
|
|
8
|
-
return null
|
|
8
|
+
return null;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
const languagesAccepted = parseAcceptLanguageHeader(
|
|
12
12
|
requestAcceptLanguageHeader,
|
|
13
|
-
)
|
|
13
|
+
);
|
|
14
14
|
return pickAcceptedContent({
|
|
15
15
|
accepteds: languagesAccepted,
|
|
16
16
|
availables: availableLanguages,
|
|
17
17
|
getAcceptanceScore: getLanguageAcceptanceScore,
|
|
18
|
-
})
|
|
19
|
-
}
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
20
|
|
|
21
21
|
const parseAcceptLanguageHeader = (acceptLanguageHeaderString) => {
|
|
22
22
|
const acceptLanguageHeader = parseMultipleHeader(acceptLanguageHeaderString, {
|
|
23
23
|
validateProperty: ({ name }) => {
|
|
24
24
|
// read only q, anything else is ignored
|
|
25
|
-
return name === "q"
|
|
25
|
+
return name === "q";
|
|
26
26
|
},
|
|
27
|
-
})
|
|
27
|
+
});
|
|
28
28
|
|
|
29
|
-
const languagesAccepted = []
|
|
29
|
+
const languagesAccepted = [];
|
|
30
30
|
Object.keys(acceptLanguageHeader).forEach((key) => {
|
|
31
|
-
const { q = 1 } = acceptLanguageHeader[key]
|
|
32
|
-
const value = key
|
|
31
|
+
const { q = 1 } = acceptLanguageHeader[key];
|
|
32
|
+
const value = key;
|
|
33
33
|
languagesAccepted.push({
|
|
34
34
|
value,
|
|
35
35
|
quality: q,
|
|
36
|
-
})
|
|
37
|
-
})
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
38
|
languagesAccepted.sort((a, b) => {
|
|
39
|
-
return b.quality - a.quality
|
|
40
|
-
})
|
|
41
|
-
return languagesAccepted
|
|
42
|
-
}
|
|
39
|
+
return b.quality - a.quality;
|
|
40
|
+
});
|
|
41
|
+
return languagesAccepted;
|
|
42
|
+
};
|
|
43
43
|
|
|
44
44
|
const getLanguageAcceptanceScore = ({ value, quality }, availableLanguage) => {
|
|
45
|
-
const [acceptedPrimary, acceptedVariant] = decomposeLanguage(value)
|
|
45
|
+
const [acceptedPrimary, acceptedVariant] = decomposeLanguage(value);
|
|
46
46
|
const [availablePrimary, availableVariant] =
|
|
47
|
-
decomposeLanguage(availableLanguage)
|
|
47
|
+
decomposeLanguage(availableLanguage);
|
|
48
48
|
|
|
49
49
|
const primaryAccepted =
|
|
50
50
|
acceptedPrimary === "*" ||
|
|
51
|
-
acceptedPrimary.toLowerCase() === availablePrimary.toLowerCase()
|
|
51
|
+
acceptedPrimary.toLowerCase() === availablePrimary.toLowerCase();
|
|
52
52
|
const variantAccepted =
|
|
53
|
-
acceptedVariant === "*" ||
|
|
53
|
+
acceptedVariant === "*" ||
|
|
54
|
+
compareVariant(acceptedVariant, availableVariant);
|
|
54
55
|
|
|
55
56
|
if (primaryAccepted && variantAccepted) {
|
|
56
|
-
return quality + 1
|
|
57
|
+
return quality + 1;
|
|
57
58
|
}
|
|
58
59
|
if (primaryAccepted) {
|
|
59
|
-
return quality
|
|
60
|
+
return quality;
|
|
60
61
|
}
|
|
61
|
-
return -1
|
|
62
|
-
}
|
|
62
|
+
return -1;
|
|
63
|
+
};
|
|
63
64
|
|
|
64
65
|
const decomposeLanguage = (fullType) => {
|
|
65
|
-
const [primary, variant] = fullType.split("-")
|
|
66
|
-
return [primary, variant]
|
|
67
|
-
}
|
|
66
|
+
const [primary, variant] = fullType.split("-");
|
|
67
|
+
return [primary, variant];
|
|
68
|
+
};
|
|
68
69
|
|
|
69
70
|
const compareVariant = (left, right) => {
|
|
70
71
|
if (left === right) {
|
|
71
|
-
return true
|
|
72
|
+
return true;
|
|
72
73
|
}
|
|
73
74
|
if (left && right && left.toLowerCase() === right.toLowerCase()) {
|
|
74
|
-
return true
|
|
75
|
+
return true;
|
|
75
76
|
}
|
|
76
|
-
return false
|
|
77
|
-
}
|
|
77
|
+
return false;
|
|
78
|
+
};
|
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
import { parseMultipleHeader } from "../internal/multiple-header.js"
|
|
2
|
-
import { pickAcceptedContent } from "./pick_accepted_content.js"
|
|
1
|
+
import { parseMultipleHeader } from "../internal/multiple-header.js";
|
|
2
|
+
import { pickAcceptedContent } from "./pick_accepted_content.js";
|
|
3
3
|
|
|
4
4
|
export const pickContentType = (request, availableContentTypes) => {
|
|
5
|
-
const { headers = {} } = request
|
|
6
|
-
const requestAcceptHeader = headers.accept
|
|
5
|
+
const { headers = {} } = request;
|
|
6
|
+
const requestAcceptHeader = headers.accept;
|
|
7
7
|
if (!requestAcceptHeader) {
|
|
8
|
-
return null
|
|
8
|
+
return null;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
const contentTypesAccepted = parseAcceptHeader(requestAcceptHeader)
|
|
11
|
+
const contentTypesAccepted = parseAcceptHeader(requestAcceptHeader);
|
|
12
12
|
return pickAcceptedContent({
|
|
13
13
|
accepteds: contentTypesAccepted,
|
|
14
14
|
availables: availableContentTypes,
|
|
15
15
|
getAcceptanceScore: getContentTypeAcceptanceScore,
|
|
16
|
-
})
|
|
17
|
-
}
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
18
|
|
|
19
19
|
const parseAcceptHeader = (acceptHeader) => {
|
|
20
20
|
const acceptHeaderObject = parseMultipleHeader(acceptHeader, {
|
|
21
21
|
validateProperty: ({ name }) => {
|
|
22
22
|
// read only q, anything else is ignored
|
|
23
|
-
return name === "q"
|
|
23
|
+
return name === "q";
|
|
24
24
|
},
|
|
25
|
-
})
|
|
25
|
+
});
|
|
26
26
|
|
|
27
|
-
const accepts = []
|
|
27
|
+
const accepts = [];
|
|
28
28
|
Object.keys(acceptHeaderObject).forEach((key) => {
|
|
29
|
-
const { q = 1 } = acceptHeaderObject[key]
|
|
30
|
-
const value = key
|
|
29
|
+
const { q = 1 } = acceptHeaderObject[key];
|
|
30
|
+
const value = key;
|
|
31
31
|
accepts.push({
|
|
32
32
|
value,
|
|
33
33
|
quality: q,
|
|
34
|
-
})
|
|
35
|
-
})
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
36
|
accepts.sort((a, b) => {
|
|
37
|
-
return b.quality - a.quality
|
|
38
|
-
})
|
|
39
|
-
return accepts
|
|
40
|
-
}
|
|
37
|
+
return b.quality - a.quality;
|
|
38
|
+
});
|
|
39
|
+
return accepts;
|
|
40
|
+
};
|
|
41
41
|
|
|
42
42
|
const getContentTypeAcceptanceScore = (
|
|
43
43
|
{ value, quality },
|
|
44
44
|
availableContentType,
|
|
45
45
|
) => {
|
|
46
|
-
const [acceptedType, acceptedSubtype] = decomposeContentType(value)
|
|
46
|
+
const [acceptedType, acceptedSubtype] = decomposeContentType(value);
|
|
47
47
|
const [availableType, availableSubtype] =
|
|
48
|
-
decomposeContentType(availableContentType)
|
|
48
|
+
decomposeContentType(availableContentType);
|
|
49
49
|
|
|
50
|
-
const typeAccepted = acceptedType === "*" || acceptedType === availableType
|
|
50
|
+
const typeAccepted = acceptedType === "*" || acceptedType === availableType;
|
|
51
51
|
const subtypeAccepted =
|
|
52
|
-
acceptedSubtype === "*" || acceptedSubtype === availableSubtype
|
|
52
|
+
acceptedSubtype === "*" || acceptedSubtype === availableSubtype;
|
|
53
53
|
|
|
54
54
|
if (typeAccepted && subtypeAccepted) {
|
|
55
|
-
return quality
|
|
55
|
+
return quality;
|
|
56
56
|
}
|
|
57
|
-
return -1
|
|
58
|
-
}
|
|
57
|
+
return -1;
|
|
58
|
+
};
|
|
59
59
|
|
|
60
60
|
const decomposeContentType = (fullType) => {
|
|
61
|
-
const [type, subtype] = fullType.split("/")
|
|
62
|
-
return [type, subtype]
|
|
63
|
-
}
|
|
61
|
+
const [type, subtype] = fullType.split("/");
|
|
62
|
+
return [type, subtype];
|
|
63
|
+
};
|