@jsenv/server 14.1.16 → 15.0.1

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 CHANGED
@@ -6,7 +6,6 @@
6
6
  import { startServer } from "@jsenv/server"
7
7
 
8
8
  await startServer({
9
- protocol: "http",
10
9
  port: 8080,
11
10
  services: [
12
11
  {
@@ -73,9 +72,10 @@ import { readFileSync } from "node:fs"
73
72
  import { startServer } from "@jsenv/server"
74
73
 
75
74
  await startServer({
76
- protocol: "https",
77
- certificate: readFileSync(new URL("./server.crt", import.meta.url), "utf8"),
78
- privateKey: readFileSync(new URL("./server.key", import.meta.url), "utf8"),
75
+ https: {
76
+ certificate: readFileSync(new URL("./server.crt", import.meta.url), "utf8"),
77
+ privateKey: readFileSync(new URL("./server.key", import.meta.url), "utf8"),
78
+ },
79
79
  allowHttpRequestOnHttps: true,
80
80
  services: [
81
81
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/server",
3
- "version": "14.1.16",
3
+ "version": "15.0.1",
4
4
  "description": "Write your Node.js server using pure functions",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -36,7 +36,7 @@
36
36
  "dependencies": {
37
37
  "@jsenv/abort": "4.2.4",
38
38
  "@jsenv/log": "3.3.4",
39
- "@jsenv/url-meta": "7.0.2",
39
+ "@jsenv/url-meta": "8.0.0",
40
40
  "@jsenv/utils": "2.0.1",
41
41
  "ws": "8.13.0"
42
42
  },
@@ -1,5 +1,4 @@
1
1
  import { isIP } from "node:net"
2
- import http from "node:http"
3
2
  import cluster from "node:cluster"
4
3
  import { createDetailedMessage, createLogger } from "@jsenv/log"
5
4
  import {
@@ -50,7 +49,7 @@ export const startServer = async ({
50
49
  startLog = true,
51
50
  serverName = "server",
52
51
 
53
- protocol = "http",
52
+ https = false,
54
53
  http2 = false,
55
54
  http1Allowed = true,
56
55
  redirectHttpToHttps,
@@ -60,8 +59,6 @@ export const startServer = async ({
60
59
  hostname = "localhost",
61
60
  port = 0, // assign a random available port
62
61
  portHint,
63
- privateKey,
64
- certificate,
65
62
 
66
63
  // when inside a worker, we should not try to stop server on SIGINT
67
64
  // otherwise it can create an EPIPE error while primary process tries
@@ -94,50 +91,60 @@ export const startServer = async ({
94
91
  // after this delay the underlying stream is destroyed, attempting to read it would throw
95
92
  // if used the stream stays opened, it's only if the stream is not read at all that it gets destroyed
96
93
  requestBodyLifetime = 60_000 * 2, // 2s
94
+ ...rest
97
95
  } = {}) => {
98
- const logger = createLogger({ logLevel })
99
-
100
- if (protocol !== "http" && protocol !== "https") {
101
- throw new Error(`protocol must be http or https, got ${protocol}`)
102
- }
103
- if (protocol === "https") {
104
- if (!certificate) {
105
- throw new Error(`missing certificate for https server`)
96
+ // param validations
97
+ {
98
+ const unexpectedParamNames = Object.keys(rest)
99
+ if (unexpectedParamNames.length > 0) {
100
+ throw new TypeError(
101
+ `${unexpectedParamNames.join(",")}: there is no such param`,
102
+ )
106
103
  }
107
- if (!privateKey) {
108
- throw new Error(`missing privateKey for https server`)
104
+ if (https) {
105
+ if (typeof https !== "object") {
106
+ throw new TypeError(`https must be an object, got ${https}`)
107
+ }
108
+ const { certificate, privateKey } = https
109
+ if (!certificate || !privateKey) {
110
+ throw new TypeError(
111
+ `https must be an object with { certificate, privateKey }`,
112
+ )
113
+ }
114
+ }
115
+ if (http2 && !https) {
116
+ throw new Error(`http2 needs https`)
109
117
  }
110
118
  }
111
- if (http2 && protocol !== "https") {
112
- throw new Error(`http2 needs "https" but protocol is "${protocol}"`)
113
- }
114
-
115
- if (
116
- redirectHttpToHttps === undefined &&
117
- protocol === "https" &&
118
- !allowHttpRequestOnHttps
119
- ) {
120
- redirectHttpToHttps = true
121
- }
122
- if (redirectHttpToHttps && protocol === "http") {
123
- logger.warn(`redirectHttpToHttps ignored because protocol is http`)
124
- redirectHttpToHttps = false
125
- }
126
- if (allowHttpRequestOnHttps && redirectHttpToHttps) {
127
- logger.warn(
128
- `redirectHttpToHttps ignored because allowHttpRequestOnHttps is enabled`,
129
- )
130
- redirectHttpToHttps = false
131
- }
119
+ const logger = createLogger({ logLevel })
120
+ // param warnings and normalization
121
+ {
122
+ if (
123
+ redirectHttpToHttps === undefined &&
124
+ https &&
125
+ !allowHttpRequestOnHttps
126
+ ) {
127
+ redirectHttpToHttps = true
128
+ }
129
+ if (redirectHttpToHttps && !https) {
130
+ logger.warn(`redirectHttpToHttps ignored because protocol is http`)
131
+ redirectHttpToHttps = false
132
+ }
133
+ if (allowHttpRequestOnHttps && redirectHttpToHttps) {
134
+ logger.warn(
135
+ `redirectHttpToHttps ignored because allowHttpRequestOnHttps is enabled`,
136
+ )
137
+ redirectHttpToHttps = false
138
+ }
132
139
 
133
- if (allowHttpRequestOnHttps && protocol === "http") {
134
- logger.warn(`allowHttpRequestOnHttps ignored because protocol is http`)
135
- allowHttpRequestOnHttps = false
140
+ if (allowHttpRequestOnHttps && !https) {
141
+ logger.warn(`allowHttpRequestOnHttps ignored because protocol is http`)
142
+ allowHttpRequestOnHttps = false
143
+ }
136
144
  }
137
145
 
138
146
  const server = {}
139
147
  const serviceController = createServiceController(services)
140
-
141
148
  const processTeardownEvents = {
142
149
  SIGHUP: stopOnExit,
143
150
  SIGTERM: stopOnExit,
@@ -164,11 +171,9 @@ export const startServer = async ({
164
171
  })
165
172
  startServerOperation.throwIfAborted()
166
173
  nodeServer = await createNodeServer({
167
- protocol,
174
+ https,
168
175
  redirectHttpToHttps,
169
176
  allowHttpRequestOnHttps,
170
- certificate,
171
- privateKey,
172
177
  http2,
173
178
  http1Allowed,
174
179
  })
@@ -180,6 +185,7 @@ export const startServer = async ({
180
185
  }
181
186
 
182
187
  const createOrigin = (hostname) => {
188
+ const protocol = https ? "https" : "http"
183
189
  if (isIP(hostname) === 6) {
184
190
  return `${protocol}://[${hostname}]`
185
191
  }
@@ -940,10 +946,9 @@ export const startServer = async ({
940
946
  const websocketClients = new Set()
941
947
  const { WebSocketServer } = await import("ws")
942
948
  let websocketServer = new WebSocketServer({ noServer: true })
943
- const websocketOrigin =
944
- protocol === "https"
945
- ? `wss://${hostname}:${port}`
946
- : `ws://${hostname}:${port}`
949
+ const websocketOrigin = https
950
+ ? `wss://${hostname}:${port}`
951
+ : `ws://${hostname}:${port}`
947
952
  server.websocketOrigin = websocketOrigin
948
953
  const upgradeCallback = (nodeRequest, socket, head) => {
949
954
  websocketServer.handleUpgrade(
@@ -1020,32 +1025,30 @@ export const startServer = async ({
1020
1025
  }
1021
1026
 
1022
1027
  const createNodeServer = async ({
1023
- protocol,
1028
+ https,
1024
1029
  redirectHttpToHttps,
1025
1030
  allowHttpRequestOnHttps,
1026
- certificate,
1027
- privateKey,
1028
1031
  http2,
1029
1032
  http1Allowed,
1030
1033
  }) => {
1031
- if (protocol === "http") {
1032
- return http.createServer()
1033
- }
1034
-
1035
- if (redirectHttpToHttps || allowHttpRequestOnHttps) {
1036
- return createPolyglotServer({
1037
- certificate,
1038
- privateKey,
1039
- http2,
1040
- http1Allowed,
1034
+ if (https) {
1035
+ const { certificate, privateKey } = https
1036
+ if (redirectHttpToHttps || allowHttpRequestOnHttps) {
1037
+ return createPolyglotServer({
1038
+ certificate,
1039
+ privateKey,
1040
+ http2,
1041
+ http1Allowed,
1042
+ })
1043
+ }
1044
+ const { createServer } = await import("node:https")
1045
+ return createServer({
1046
+ cert: certificate,
1047
+ key: privateKey,
1041
1048
  })
1042
1049
  }
1043
-
1044
- const { createServer } = await import("node:https")
1045
- return createServer({
1046
- cert: certificate,
1047
- key: privateKey,
1048
- })
1050
+ const { createServer } = await import("node:http")
1051
+ return createServer()
1049
1052
  }
1050
1053
 
1051
1054
  const testCanPushStream = (http2Stream) => {