@jsenv/core 41.5.34 → 41.5.37
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/dist/browserslist_index/browserslist_index.js +22 -4
- package/dist/build/jsenv_core_node_modules.js +23 -13
- package/dist/build/jsenv_core_packages.js +3 -2
- package/dist/{page_picker.js → client/client_monitoring/clients_page.html} +650 -2
- package/dist/client/https_trust/https_trust.html +362 -0
- package/dist/js/page_switcher.js +809 -1
- package/dist/start_build_server/jsenv_core_node_modules.js +20 -10
- package/dist/start_build_server/jsenv_core_packages.js +3 -2
- package/dist/start_dev_server/jsenv_core_node_modules.js +20 -10
- package/dist/start_dev_server/jsenv_core_packages.js +3 -2
- package/dist/start_dev_server/start_dev_server.js +126 -4
- package/package.json +11 -10
- package/src/dev/dev_server_plugins/client/https_trust.html +352 -0
- package/src/dev/dev_server_plugins/dev_server_plugin_https_trust.js +93 -0
- package/src/dev/start_dev_server.js +35 -1
- package/dist/html/clients_page.html +0 -651
- /package/dist/{html → client/client_monitoring}/client_monitor_page.html +0 -0
|
@@ -47,7 +47,11 @@ function envForceColor() {
|
|
|
47
47
|
return 1;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
if (!/^\d+$/v.test(env.FORCE_COLOR)) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const level = Math.min(Number(env.FORCE_COLOR), 3);
|
|
51
55
|
|
|
52
56
|
if (![0, 1, 2, 3].includes(level)) {
|
|
53
57
|
return;
|
|
@@ -69,6 +73,7 @@ function translateLevel(level) {
|
|
|
69
73
|
};
|
|
70
74
|
}
|
|
71
75
|
|
|
76
|
+
// eslint-disable-next-line complexity -- Color support detection necessarily handles multiple environments.
|
|
72
77
|
function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
73
78
|
const noFlagForceColor = envForceColor();
|
|
74
79
|
if (noFlagForceColor !== undefined) {
|
|
@@ -93,6 +98,11 @@ function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
|
93
98
|
}
|
|
94
99
|
}
|
|
95
100
|
|
|
101
|
+
// A numeric `FORCE_COLOR` requests an exact level, while `FORCE_COLOR=true` and `FORCE_COLOR=` only enable color and let the level be detected.
|
|
102
|
+
if (forceColor !== undefined && /^\d+$/v.test(env.FORCE_COLOR)) {
|
|
103
|
+
return forceColor;
|
|
104
|
+
}
|
|
105
|
+
|
|
96
106
|
// Check for Azure DevOps pipelines.
|
|
97
107
|
// Has to be above the `!streamIsTTY` check.
|
|
98
108
|
if ('TF_BUILD' in env && 'AGENT_NAME' in env) {
|
|
@@ -124,11 +134,11 @@ function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
|
124
134
|
}
|
|
125
135
|
|
|
126
136
|
if ('CI' in env) {
|
|
127
|
-
if (['GITHUB_ACTIONS', 'GITEA_ACTIONS', 'CIRCLECI'].some(key => key
|
|
137
|
+
if (['GITHUB_ACTIONS', 'GITEA_ACTIONS', 'CIRCLECI'].some(key => Object.hasOwn(env, key))) {
|
|
128
138
|
return 3;
|
|
129
139
|
}
|
|
130
140
|
|
|
131
|
-
if (['TRAVIS', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign
|
|
141
|
+
if (['TRAVIS', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => Object.hasOwn(env, sign)) || env.CI_NAME === 'codeship') {
|
|
132
142
|
return 1;
|
|
133
143
|
}
|
|
134
144
|
|
|
@@ -136,7 +146,7 @@ function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
|
136
146
|
}
|
|
137
147
|
|
|
138
148
|
if ('TEAMCITY_VERSION' in env) {
|
|
139
|
-
return /^(9\.
|
|
149
|
+
return /^(?:9\.0*[1-9]\d*\.|\d{2,}\.)/v.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
140
150
|
}
|
|
141
151
|
|
|
142
152
|
if (env.COLORTERM === 'truecolor') {
|
|
@@ -156,7 +166,7 @@ function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
|
156
166
|
}
|
|
157
167
|
|
|
158
168
|
if ('TERM_PROGRAM' in env) {
|
|
159
|
-
const version = Number
|
|
169
|
+
const version = Number((env.TERM_PROGRAM_VERSION || '').split('.', 1)[0]);
|
|
160
170
|
|
|
161
171
|
switch (env.TERM_PROGRAM) {
|
|
162
172
|
case 'iTerm.app': {
|
|
@@ -170,11 +180,11 @@ function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
|
170
180
|
}
|
|
171
181
|
}
|
|
172
182
|
|
|
173
|
-
if (/-256(color)?$/
|
|
183
|
+
if (/-256(?:color)?$/iv.test(env.TERM)) {
|
|
174
184
|
return 2;
|
|
175
185
|
}
|
|
176
186
|
|
|
177
|
-
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/
|
|
187
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/iv.test(env.TERM)) {
|
|
178
188
|
return 1;
|
|
179
189
|
}
|
|
180
190
|
|
|
@@ -231,7 +241,7 @@ const fullwidthRanges = [12288, 12288, 65281, 65376, 65504, 65510];
|
|
|
231
241
|
|
|
232
242
|
const wideMinimalCodePoint = 4352;
|
|
233
243
|
const wideMaximumCodePoint = 262141;
|
|
234
|
-
const wideRanges = [4352, 4447, 8986, 8987, 9001, 9002, 9193, 9196, 9200, 9200, 9203, 9203, 9725, 9726, 9748, 9749, 9776, 9783, 9800, 9811, 9855, 9855, 9866, 9871, 9875, 9875, 9889, 9889, 9898, 9899, 9917, 9918, 9924, 9925, 9934, 9934, 9940, 9940, 9962, 9962, 9970, 9971, 9973, 9973, 9978, 9978, 9981, 9981, 9989, 9989, 9994, 9995, 10024, 10024, 10060, 10060, 10062, 10062, 10067, 10069, 10071, 10071, 10133, 10135, 10160, 10160, 10175, 10175, 11035, 11036, 11088, 11088, 11093, 11093, 11904, 11929, 11931, 12019, 12032, 12245, 12272, 12287, 12289, 12350, 12353, 12438, 12441, 12543, 12549, 12591, 12593, 12686, 12688, 12773, 12783, 12830, 12832, 12871, 12880, 42124, 42128, 42182, 43360, 43388, 44032, 55203, 63744, 64255, 65040, 65049, 65072, 65106, 65108, 65126, 65128, 65131, 94176, 94180, 94192, 94198, 94208,
|
|
244
|
+
const wideRanges = [4352, 4447, 8986, 8987, 9001, 9002, 9193, 9196, 9200, 9200, 9203, 9203, 9725, 9726, 9748, 9749, 9776, 9783, 9800, 9811, 9855, 9855, 9866, 9871, 9875, 9875, 9889, 9889, 9898, 9899, 9917, 9918, 9924, 9925, 9934, 9934, 9940, 9940, 9962, 9962, 9970, 9971, 9973, 9973, 9978, 9978, 9981, 9981, 9989, 9989, 9994, 9995, 10024, 10024, 10060, 10060, 10062, 10062, 10067, 10069, 10071, 10071, 10133, 10135, 10160, 10160, 10175, 10175, 11035, 11036, 11088, 11088, 11093, 11093, 11904, 11929, 11931, 12019, 12032, 12245, 12272, 12287, 12289, 12350, 12353, 12438, 12441, 12543, 12549, 12591, 12593, 12686, 12688, 12773, 12783, 12830, 12832, 12871, 12880, 42124, 42128, 42182, 43360, 43388, 44032, 55203, 63744, 64255, 65040, 65049, 65072, 65106, 65108, 65126, 65128, 65131, 94176, 94180, 94192, 94198, 94208, 101594, 101631, 101664, 101760, 101874, 101888, 102801, 102816, 102866, 110576, 110579, 110581, 110587, 110589, 110590, 110592, 110888, 110898, 110898, 110928, 110930, 110933, 110933, 110948, 110952, 110960, 111355, 119552, 119638, 119648, 119670, 126980, 126980, 127183, 127183, 127374, 127374, 127377, 127386, 127406, 127406, 127488, 127490, 127504, 127547, 127552, 127560, 127568, 127569, 127584, 127589, 127744, 127776, 127789, 127797, 127799, 127868, 127870, 127891, 127904, 127946, 127951, 127955, 127968, 127984, 127988, 127988, 127992, 128062, 128064, 128064, 128066, 128252, 128255, 128317, 128331, 128334, 128336, 128359, 128378, 128378, 128405, 128406, 128420, 128420, 128507, 128591, 128640, 128709, 128716, 128716, 128720, 128722, 128725, 128729, 128732, 128735, 128747, 128748, 128756, 128764, 128986, 128986, 128992, 129003, 129008, 129008, 129292, 129338, 129340, 129349, 129351, 129535, 129648, 129660, 129664, 129734, 129736, 129736, 129740, 129757, 129759, 129771, 129775, 129786, 131072, 196605, 196608, 262141];
|
|
235
245
|
|
|
236
246
|
/**
|
|
237
247
|
Binary search on a sorted flat array of [start, end] pairs.
|
|
@@ -299,7 +309,7 @@ const isAmbiguous = codePoint => {
|
|
|
299
309
|
return isInRange(ambiguousRanges, codePoint);
|
|
300
310
|
};
|
|
301
311
|
|
|
302
|
-
const
|
|
312
|
+
const isFullwidth = codePoint => {
|
|
303
313
|
if (
|
|
304
314
|
codePoint < fullwidthMinimalCodePoint
|
|
305
315
|
|| codePoint > fullwidthMaximumCodePoint
|
|
@@ -338,7 +348,7 @@ function eastAsianWidth(codePoint, {ambiguousAsWide = false} = {}) {
|
|
|
338
348
|
validate(codePoint);
|
|
339
349
|
|
|
340
350
|
if (
|
|
341
|
-
|
|
351
|
+
isFullwidth(codePoint)
|
|
342
352
|
|| isWide(codePoint)
|
|
343
353
|
|| (ambiguousAsWide && isAmbiguous(codePoint))
|
|
344
354
|
) {
|
|
@@ -1461,7 +1461,8 @@ const startSpinner = ({
|
|
|
1461
1461
|
|
|
1462
1462
|
const createTaskLog = (
|
|
1463
1463
|
label,
|
|
1464
|
-
|
|
1464
|
+
// animated defaults to what the spinner decides: only when stdout is a terminal
|
|
1465
|
+
{ disabled = false, animated, stopOnWriteFromOutside } = {},
|
|
1465
1466
|
) => {
|
|
1466
1467
|
if (disabled) {
|
|
1467
1468
|
return {
|
|
@@ -1471,7 +1472,7 @@ const createTaskLog = (
|
|
|
1471
1472
|
fail: () => {},
|
|
1472
1473
|
};
|
|
1473
1474
|
}
|
|
1474
|
-
if (
|
|
1475
|
+
if (process.env.CAPTURING_SIDE_EFFECTS) {
|
|
1475
1476
|
animated = false;
|
|
1476
1477
|
}
|
|
1477
1478
|
const startMs = Date.now();
|
|
@@ -47,7 +47,11 @@ function envForceColor() {
|
|
|
47
47
|
return 1;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
if (!/^\d+$/v.test(env.FORCE_COLOR)) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const level = Math.min(Number(env.FORCE_COLOR), 3);
|
|
51
55
|
|
|
52
56
|
if (![0, 1, 2, 3].includes(level)) {
|
|
53
57
|
return;
|
|
@@ -69,6 +73,7 @@ function translateLevel(level) {
|
|
|
69
73
|
};
|
|
70
74
|
}
|
|
71
75
|
|
|
76
|
+
// eslint-disable-next-line complexity -- Color support detection necessarily handles multiple environments.
|
|
72
77
|
function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
73
78
|
const noFlagForceColor = envForceColor();
|
|
74
79
|
if (noFlagForceColor !== undefined) {
|
|
@@ -93,6 +98,11 @@ function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
|
93
98
|
}
|
|
94
99
|
}
|
|
95
100
|
|
|
101
|
+
// A numeric `FORCE_COLOR` requests an exact level, while `FORCE_COLOR=true` and `FORCE_COLOR=` only enable color and let the level be detected.
|
|
102
|
+
if (forceColor !== undefined && /^\d+$/v.test(env.FORCE_COLOR)) {
|
|
103
|
+
return forceColor;
|
|
104
|
+
}
|
|
105
|
+
|
|
96
106
|
// Check for Azure DevOps pipelines.
|
|
97
107
|
// Has to be above the `!streamIsTTY` check.
|
|
98
108
|
if ('TF_BUILD' in env && 'AGENT_NAME' in env) {
|
|
@@ -124,11 +134,11 @@ function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
|
124
134
|
}
|
|
125
135
|
|
|
126
136
|
if ('CI' in env) {
|
|
127
|
-
if (['GITHUB_ACTIONS', 'GITEA_ACTIONS', 'CIRCLECI'].some(key => key
|
|
137
|
+
if (['GITHUB_ACTIONS', 'GITEA_ACTIONS', 'CIRCLECI'].some(key => Object.hasOwn(env, key))) {
|
|
128
138
|
return 3;
|
|
129
139
|
}
|
|
130
140
|
|
|
131
|
-
if (['TRAVIS', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign
|
|
141
|
+
if (['TRAVIS', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => Object.hasOwn(env, sign)) || env.CI_NAME === 'codeship') {
|
|
132
142
|
return 1;
|
|
133
143
|
}
|
|
134
144
|
|
|
@@ -136,7 +146,7 @@ function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
|
136
146
|
}
|
|
137
147
|
|
|
138
148
|
if ('TEAMCITY_VERSION' in env) {
|
|
139
|
-
return /^(9\.
|
|
149
|
+
return /^(?:9\.0*[1-9]\d*\.|\d{2,}\.)/v.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
140
150
|
}
|
|
141
151
|
|
|
142
152
|
if (env.COLORTERM === 'truecolor') {
|
|
@@ -156,7 +166,7 @@ function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
|
156
166
|
}
|
|
157
167
|
|
|
158
168
|
if ('TERM_PROGRAM' in env) {
|
|
159
|
-
const version = Number
|
|
169
|
+
const version = Number((env.TERM_PROGRAM_VERSION || '').split('.', 1)[0]);
|
|
160
170
|
|
|
161
171
|
switch (env.TERM_PROGRAM) {
|
|
162
172
|
case 'iTerm.app': {
|
|
@@ -170,11 +180,11 @@ function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {
|
|
|
170
180
|
}
|
|
171
181
|
}
|
|
172
182
|
|
|
173
|
-
if (/-256(color)?$/
|
|
183
|
+
if (/-256(?:color)?$/iv.test(env.TERM)) {
|
|
174
184
|
return 2;
|
|
175
185
|
}
|
|
176
186
|
|
|
177
|
-
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/
|
|
187
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/iv.test(env.TERM)) {
|
|
178
188
|
return 1;
|
|
179
189
|
}
|
|
180
190
|
|
|
@@ -231,7 +241,7 @@ const fullwidthRanges = [12288, 12288, 65281, 65376, 65504, 65510];
|
|
|
231
241
|
|
|
232
242
|
const wideMinimalCodePoint = 4352;
|
|
233
243
|
const wideMaximumCodePoint = 262141;
|
|
234
|
-
const wideRanges = [4352, 4447, 8986, 8987, 9001, 9002, 9193, 9196, 9200, 9200, 9203, 9203, 9725, 9726, 9748, 9749, 9776, 9783, 9800, 9811, 9855, 9855, 9866, 9871, 9875, 9875, 9889, 9889, 9898, 9899, 9917, 9918, 9924, 9925, 9934, 9934, 9940, 9940, 9962, 9962, 9970, 9971, 9973, 9973, 9978, 9978, 9981, 9981, 9989, 9989, 9994, 9995, 10024, 10024, 10060, 10060, 10062, 10062, 10067, 10069, 10071, 10071, 10133, 10135, 10160, 10160, 10175, 10175, 11035, 11036, 11088, 11088, 11093, 11093, 11904, 11929, 11931, 12019, 12032, 12245, 12272, 12287, 12289, 12350, 12353, 12438, 12441, 12543, 12549, 12591, 12593, 12686, 12688, 12773, 12783, 12830, 12832, 12871, 12880, 42124, 42128, 42182, 43360, 43388, 44032, 55203, 63744, 64255, 65040, 65049, 65072, 65106, 65108, 65126, 65128, 65131, 94176, 94180, 94192, 94198, 94208,
|
|
244
|
+
const wideRanges = [4352, 4447, 8986, 8987, 9001, 9002, 9193, 9196, 9200, 9200, 9203, 9203, 9725, 9726, 9748, 9749, 9776, 9783, 9800, 9811, 9855, 9855, 9866, 9871, 9875, 9875, 9889, 9889, 9898, 9899, 9917, 9918, 9924, 9925, 9934, 9934, 9940, 9940, 9962, 9962, 9970, 9971, 9973, 9973, 9978, 9978, 9981, 9981, 9989, 9989, 9994, 9995, 10024, 10024, 10060, 10060, 10062, 10062, 10067, 10069, 10071, 10071, 10133, 10135, 10160, 10160, 10175, 10175, 11035, 11036, 11088, 11088, 11093, 11093, 11904, 11929, 11931, 12019, 12032, 12245, 12272, 12287, 12289, 12350, 12353, 12438, 12441, 12543, 12549, 12591, 12593, 12686, 12688, 12773, 12783, 12830, 12832, 12871, 12880, 42124, 42128, 42182, 43360, 43388, 44032, 55203, 63744, 64255, 65040, 65049, 65072, 65106, 65108, 65126, 65128, 65131, 94176, 94180, 94192, 94198, 94208, 101594, 101631, 101664, 101760, 101874, 101888, 102801, 102816, 102866, 110576, 110579, 110581, 110587, 110589, 110590, 110592, 110888, 110898, 110898, 110928, 110930, 110933, 110933, 110948, 110952, 110960, 111355, 119552, 119638, 119648, 119670, 126980, 126980, 127183, 127183, 127374, 127374, 127377, 127386, 127406, 127406, 127488, 127490, 127504, 127547, 127552, 127560, 127568, 127569, 127584, 127589, 127744, 127776, 127789, 127797, 127799, 127868, 127870, 127891, 127904, 127946, 127951, 127955, 127968, 127984, 127988, 127988, 127992, 128062, 128064, 128064, 128066, 128252, 128255, 128317, 128331, 128334, 128336, 128359, 128378, 128378, 128405, 128406, 128420, 128420, 128507, 128591, 128640, 128709, 128716, 128716, 128720, 128722, 128725, 128729, 128732, 128735, 128747, 128748, 128756, 128764, 128986, 128986, 128992, 129003, 129008, 129008, 129292, 129338, 129340, 129349, 129351, 129535, 129648, 129660, 129664, 129734, 129736, 129736, 129740, 129757, 129759, 129771, 129775, 129786, 131072, 196605, 196608, 262141];
|
|
235
245
|
|
|
236
246
|
/**
|
|
237
247
|
Binary search on a sorted flat array of [start, end] pairs.
|
|
@@ -299,7 +309,7 @@ const isAmbiguous = codePoint => {
|
|
|
299
309
|
return isInRange(ambiguousRanges, codePoint);
|
|
300
310
|
};
|
|
301
311
|
|
|
302
|
-
const
|
|
312
|
+
const isFullwidth = codePoint => {
|
|
303
313
|
if (
|
|
304
314
|
codePoint < fullwidthMinimalCodePoint
|
|
305
315
|
|| codePoint > fullwidthMaximumCodePoint
|
|
@@ -338,7 +348,7 @@ function eastAsianWidth(codePoint, {ambiguousAsWide = false} = {}) {
|
|
|
338
348
|
validate(codePoint);
|
|
339
349
|
|
|
340
350
|
if (
|
|
341
|
-
|
|
351
|
+
isFullwidth(codePoint)
|
|
342
352
|
|| isWide(codePoint)
|
|
343
353
|
|| (ambiguousAsWide && isAmbiguous(codePoint))
|
|
344
354
|
) {
|
|
@@ -1264,7 +1264,8 @@ const startSpinner = ({
|
|
|
1264
1264
|
|
|
1265
1265
|
const createTaskLog = (
|
|
1266
1266
|
label,
|
|
1267
|
-
|
|
1267
|
+
// animated defaults to what the spinner decides: only when stdout is a terminal
|
|
1268
|
+
{ disabled = false, animated, stopOnWriteFromOutside } = {},
|
|
1268
1269
|
) => {
|
|
1269
1270
|
if (disabled) {
|
|
1270
1271
|
return {
|
|
@@ -1274,7 +1275,7 @@ const createTaskLog = (
|
|
|
1274
1275
|
fail: () => {},
|
|
1275
1276
|
};
|
|
1276
1277
|
}
|
|
1277
|
-
if (
|
|
1278
|
+
if (process.env.CAPTURING_SIDE_EFFECTS) {
|
|
1278
1279
|
animated = false;
|
|
1279
1280
|
}
|
|
1280
1281
|
const startMs = Date.now();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { WebSocketResponse, pickContentType, ServerEvents, serverPluginErrorHandler, fetchDirectory, composeTwoResponses, serverPluginCORS, jsenvAccessControlAllowedHeaders, startServer } from "@jsenv/server";
|
|
2
|
+
import { randomUUID, X509Certificate } from "node:crypto";
|
|
2
3
|
import { existsSync, statSync, readFileSync, realpathSync, readdirSync, lstatSync } from "node:fs";
|
|
3
4
|
import { pathToFileURL } from "node:url";
|
|
4
5
|
import { urlToRelativeUrl, registerFileLifecycle, lookupPackageDirectory, readPackageAtOrNull, generateContentFrame, errorToHTML, URL_META, asUrlWithoutSearch, DATA_URL, CONTENT_TYPE, normalizeImportMap, composeTwoImportMaps, resolveImport, createDetailedMessage, UNICODE, JS_QUOTES, urlToExtension, urlToBasename, applyNodeEsmResolution, readCustomConditionsFromProcessArgs, urlIsOrIsInsideOf, collectFiles, registerDirectoryLifecycle, readEntryStatSync, applyFileSystemMagicResolution, getExtensionsToTry, urlToFilename, ensurePathnameTrailingSlash, compareFileUrls, setUrlExtension, stringifyUrlSite, injectQueryParamsIntoSpecifier, isSpecifierForNodeBuiltin, injectQueryParams, urlToFileSystemPath, writeFileSync, moveUrl, ensureWindowsDriveLetter, validateResponseIntegrity, setUrlFilename, getCallerPosition, asSpecifierWithoutSearch, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, createLogger, normalizeUrl, ANSI, RUNTIME_COMPAT, formatError, assertAndNormalizeDirectoryUrl, browserDefaultRuntimeCompat, inferRuntimeCompatFromClosestPackage, createTaskLog } from "./jsenv_core_packages.js";
|
|
@@ -8,7 +9,6 @@ import { createMagicSource, composeTwoSourcemaps, generateSourcemapFileUrl, gene
|
|
|
8
9
|
import { jsenvPluginSupervisor } from "@jsenv/plugin-supervisor";
|
|
9
10
|
import { jsenvPluginTranspilation } from "@jsenv/plugin-transpilation";
|
|
10
11
|
import { bundleJsModules } from "@jsenv/plugin-bundling";
|
|
11
|
-
import { randomUUID } from "node:crypto";
|
|
12
12
|
import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/plugins/filesystem/filesystem_error_to_response.js";
|
|
13
13
|
import "./jsenv_core_node_modules.js";
|
|
14
14
|
import "node:process";
|
|
@@ -986,11 +986,11 @@ const clientReporterFileUrl = new URL(
|
|
|
986
986
|
import.meta.url,
|
|
987
987
|
).href;
|
|
988
988
|
const clientsPageFileUrl = new URL(
|
|
989
|
-
"../
|
|
989
|
+
"../client/client_monitoring/clients_page.html",
|
|
990
990
|
import.meta.url,
|
|
991
991
|
).href;
|
|
992
992
|
const clientMonitorPageFileUrl = new URL(
|
|
993
|
-
"../
|
|
993
|
+
"../client/client_monitoring/client_monitor_page.html",
|
|
994
994
|
import.meta.url,
|
|
995
995
|
).href;
|
|
996
996
|
|
|
@@ -8602,6 +8602,99 @@ const devServerPluginChromeDevToolsJson = ({ sourceDirectoryUrl }) => {
|
|
|
8602
8602
|
};
|
|
8603
8603
|
};
|
|
8604
8604
|
|
|
8605
|
+
/*
|
|
8606
|
+
* Lets another device (a phone) trust the root certificate that signs the dev
|
|
8607
|
+
* server certificate, so it opens the dev server over https without a warning.
|
|
8608
|
+
*
|
|
8609
|
+
* Everything under HTTPS_TRUST_PATHNAME is served over plain http too (see the
|
|
8610
|
+
* redirectHttpToHttps passed by startDevServer): it is the one page that must
|
|
8611
|
+
* load before the certificate is trusted, over https it would show the very
|
|
8612
|
+
* warning it exists to remove. Only the certificate is served, never its key.
|
|
8613
|
+
*
|
|
8614
|
+
* The page is sent as written, not cooked like the project pages: it needs
|
|
8615
|
+
* nothing cooking injects, and a project plugin rewriting html must not be able
|
|
8616
|
+
* to break the one page reached before trust.
|
|
8617
|
+
*
|
|
8618
|
+
* What it means for the device, and why the fingerprint must be compared with
|
|
8619
|
+
* the terminal: docs/users/b_dev/b_dev.md, "Trusting it on a phone".
|
|
8620
|
+
*/
|
|
8621
|
+
|
|
8622
|
+
|
|
8623
|
+
const HTTPS_TRUST_PATHNAME = "/.internal/https/";
|
|
8624
|
+
|
|
8625
|
+
const httpsTrustPageFileUrl = new URL(
|
|
8626
|
+
"../client/https_trust/https_trust.html",
|
|
8627
|
+
import.meta.url,
|
|
8628
|
+
);
|
|
8629
|
+
|
|
8630
|
+
// rootCertificate is a node:crypto X509Certificate
|
|
8631
|
+
const devServerPluginHttpsTrust = ({ rootCertificate }) => {
|
|
8632
|
+
const commonName = readCommonName(rootCertificate.subject);
|
|
8633
|
+
const rootCertificateInfo = {
|
|
8634
|
+
fingerprint256: rootCertificate.fingerprint256,
|
|
8635
|
+
commonName,
|
|
8636
|
+
};
|
|
8637
|
+
// "https local root certificate" -> "https_local_root_certificate.crt"
|
|
8638
|
+
const rootCertificateFilename = `${commonName.replace(/[^\w.-]+/g, "_")}.crt`;
|
|
8639
|
+
|
|
8640
|
+
return {
|
|
8641
|
+
name: "jsenv:https_trust",
|
|
8642
|
+
routes: [
|
|
8643
|
+
{
|
|
8644
|
+
endpoint: `GET ${HTTPS_TRUST_PATHNAME}`,
|
|
8645
|
+
description:
|
|
8646
|
+
"Page to trust the dev server https on another device (a phone). Served over http.",
|
|
8647
|
+
declarationSource: import.meta.url,
|
|
8648
|
+
fetch: () => {
|
|
8649
|
+
return new Response(readFileSync(httpsTrustPageFileUrl), {
|
|
8650
|
+
headers: { "content-type": "text/html" },
|
|
8651
|
+
});
|
|
8652
|
+
},
|
|
8653
|
+
},
|
|
8654
|
+
{
|
|
8655
|
+
endpoint: `GET ${HTTPS_TRUST_PATHNAME}root.crt`,
|
|
8656
|
+
description: "The root certificate signing the dev server certificate.",
|
|
8657
|
+
declarationSource: import.meta.url,
|
|
8658
|
+
fetch: () => {
|
|
8659
|
+
return new Response(rootCertificate.toString(), {
|
|
8660
|
+
headers: {
|
|
8661
|
+
"content-type": "application/x-x509-ca-cert",
|
|
8662
|
+
"content-disposition": `attachment; filename="${rootCertificateFilename}"`,
|
|
8663
|
+
},
|
|
8664
|
+
});
|
|
8665
|
+
},
|
|
8666
|
+
},
|
|
8667
|
+
{
|
|
8668
|
+
endpoint: `GET ${HTTPS_TRUST_PATHNAME}root.json`,
|
|
8669
|
+
description: "Fingerprint and name of the root certificate.",
|
|
8670
|
+
declarationSource: import.meta.url,
|
|
8671
|
+
fetch: () => {
|
|
8672
|
+
return Response.json(rootCertificateInfo);
|
|
8673
|
+
},
|
|
8674
|
+
},
|
|
8675
|
+
{
|
|
8676
|
+
endpoint: `GET ${HTTPS_TRUST_PATHNAME}ping`,
|
|
8677
|
+
description:
|
|
8678
|
+
"Fetched over https by the page: it fails as long as the device does not trust the certificate.",
|
|
8679
|
+
declarationSource: import.meta.url,
|
|
8680
|
+
fetch: () => {
|
|
8681
|
+
return new Response(null, { status: 204 });
|
|
8682
|
+
},
|
|
8683
|
+
},
|
|
8684
|
+
],
|
|
8685
|
+
};
|
|
8686
|
+
};
|
|
8687
|
+
|
|
8688
|
+
// "CN=https local root certificate\nO=..." -> "https local root certificate"
|
|
8689
|
+
const readCommonName = (subject) => {
|
|
8690
|
+
for (const line of subject.split("\n")) {
|
|
8691
|
+
if (line.startsWith("CN=")) {
|
|
8692
|
+
return line.slice("CN=".length);
|
|
8693
|
+
}
|
|
8694
|
+
}
|
|
8695
|
+
return subject;
|
|
8696
|
+
};
|
|
8697
|
+
|
|
8605
8698
|
const devServerPluginInjectServerResponseHeader = ({
|
|
8606
8699
|
sourceDirectoryUrl,
|
|
8607
8700
|
}) => {
|
|
@@ -12527,7 +12620,7 @@ const EXECUTED_BY_TEST_PLAN = process.argv.includes("--jsenv-test");
|
|
|
12527
12620
|
* @param {number} [params.port=3456] - Port to listen on (0 = a free port).
|
|
12528
12621
|
* @param {string} [params.hostname] - Hostname to bind to.
|
|
12529
12622
|
* @param {boolean} [params.acceptAnyIp=false] - Also accept connections on the machine's IPs (so other devices on the network — a phone — can reach the server). Off by default: exposing the dev server beyond localhost is an explicit choice, not something a dev tool decides.
|
|
12530
|
-
* @param {
|
|
12623
|
+
* @param {object} [params.https] - HTTPS as `{ certificate, privateKey }` (PEM strings). With `rootCertificate` (the PEM of the authority that signed `certificate`) and `acceptAnyIp`, the dev server also serves `http://<ip>:<port>/.internal/https/`, a page to trust that authority on a phone (see docs/users/b_dev/b_dev.md, "Trusting it on a phone").
|
|
12531
12624
|
* @param {boolean} [params.http2=false] - HTTP/2 (requires https).
|
|
12532
12625
|
* @param {Array} [params.plugins=[]] - jsenv plugins (transformUrlContent, serverRoutes, serverEvents, effect, …).
|
|
12533
12626
|
* @param {Array} [params.serverPlugins=[]] - `@jsenv/server`-level plugins.
|
|
@@ -12659,6 +12752,7 @@ const startDevServer = async ({
|
|
|
12659
12752
|
);
|
|
12660
12753
|
}
|
|
12661
12754
|
}
|
|
12755
|
+
let httpsTrust = null;
|
|
12662
12756
|
// params normalization
|
|
12663
12757
|
{
|
|
12664
12758
|
if (runtimeCompat === undefined) {
|
|
@@ -12673,6 +12767,16 @@ const startDevServer = async ({
|
|
|
12673
12767
|
if (clientAutoreload === false) {
|
|
12674
12768
|
clientAutoreload = { enabled: false };
|
|
12675
12769
|
}
|
|
12770
|
+
if (https) {
|
|
12771
|
+
const { certificate, privateKey, rootCertificate } = https;
|
|
12772
|
+
https = { certificate, privateKey };
|
|
12773
|
+
// a localhost-only server has no phone to serve
|
|
12774
|
+
if (rootCertificate && acceptAnyIp) {
|
|
12775
|
+
httpsTrust = {
|
|
12776
|
+
rootCertificate: new X509Certificate(rootCertificate),
|
|
12777
|
+
};
|
|
12778
|
+
}
|
|
12779
|
+
}
|
|
12676
12780
|
}
|
|
12677
12781
|
|
|
12678
12782
|
const logger = createLogger({ logLevel });
|
|
@@ -12830,6 +12934,7 @@ const startDevServer = async ({
|
|
|
12830
12934
|
}),
|
|
12831
12935
|
// chrome devtools
|
|
12832
12936
|
devServerPluginChromeDevToolsJson({ sourceDirectoryUrl }),
|
|
12937
|
+
...(httpsTrust ? [devServerPluginHttpsTrust(httpsTrust)] : []),
|
|
12833
12938
|
...serverPlugins,
|
|
12834
12939
|
devServerPluginServeSourceFiles({
|
|
12835
12940
|
packageDirectory,
|
|
@@ -12868,6 +12973,12 @@ const startDevServer = async ({
|
|
|
12868
12973
|
startLog: false,
|
|
12869
12974
|
|
|
12870
12975
|
https,
|
|
12976
|
+
...(httpsTrust
|
|
12977
|
+
? {
|
|
12978
|
+
redirectHttpToHttps: ({ resource }) =>
|
|
12979
|
+
!resource.startsWith(HTTPS_TRUST_PATHNAME),
|
|
12980
|
+
}
|
|
12981
|
+
: {}),
|
|
12871
12982
|
http2,
|
|
12872
12983
|
acceptAnyIp,
|
|
12873
12984
|
hostname,
|
|
@@ -12893,6 +13004,17 @@ const startDevServer = async ({
|
|
|
12893
13004
|
logger.info(``);
|
|
12894
13005
|
Object.keys(server.origins).forEach((key) => {
|
|
12895
13006
|
logger.info(`- ${server.origins[key]}`);
|
|
13007
|
+
if (httpsTrust && key === "externalip") {
|
|
13008
|
+
const externalHostname = new URL(server.origins.externalip).hostname;
|
|
13009
|
+
const httpsTrustPageUrl = new URL(
|
|
13010
|
+
HTTPS_TRUST_PATHNAME,
|
|
13011
|
+
`http://${externalHostname}:${server.port}`,
|
|
13012
|
+
);
|
|
13013
|
+
logger.info(` trust it on a phone: ${httpsTrustPageUrl}`);
|
|
13014
|
+
logger.info(
|
|
13015
|
+
` root certificate SHA-256: ${httpsTrust.rootCertificate.fingerprint256}`,
|
|
13016
|
+
);
|
|
13017
|
+
}
|
|
12896
13018
|
});
|
|
12897
13019
|
logger.info(``);
|
|
12898
13020
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "41.5.
|
|
3
|
+
"version": "41.5.37",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Tool to develop, test and build js projects",
|
|
6
6
|
"repository": {
|
|
@@ -57,9 +57,10 @@
|
|
|
57
57
|
"https:setup": "npx @jsenv/https-local setup",
|
|
58
58
|
"md:build": "node ./docs/build.js",
|
|
59
59
|
"monorepo:node_modules_clear": "npx @jsenv/filesystem clear **/node_modules/",
|
|
60
|
-
"monorepo:publish": "node ./scripts/monorepo/
|
|
60
|
+
"monorepo:publish": "node ./scripts/monorepo/prepare_publish.mjs",
|
|
61
61
|
"monorepo:sync_versions": "node ./scripts/monorepo/sync_packages_versions.mjs",
|
|
62
62
|
"monorepo:upgrade_versions": "node ./scripts/monorepo/upgrade_external_versions.mjs",
|
|
63
|
+
"monorepo:wait_publish": "node ./scripts/monorepo/wait_publish.mjs",
|
|
63
64
|
"oto:start": "npm run start -w oto",
|
|
64
65
|
"performances": "node --expose-gc ./scripts/performance/generate_performance_report.mjs --log --once",
|
|
65
66
|
"playwright:install": "npx playwright install-deps && npx playwright install",
|
|
@@ -73,14 +74,14 @@
|
|
|
73
74
|
"test:snapshot_clear": "npx @jsenv/filesystem clear **/tests/**/side_effects/"
|
|
74
75
|
},
|
|
75
76
|
"dependencies": {
|
|
76
|
-
"@jsenv/ast": "6.10.
|
|
77
|
-
"@jsenv/js-module-fallback": "1.6.
|
|
78
|
-
"@jsenv/plugin-bundling": "2.10.
|
|
79
|
-
"@jsenv/plugin-minification": "1.7.
|
|
80
|
-
"@jsenv/plugin-supervisor": "1.8.
|
|
81
|
-
"@jsenv/plugin-transpilation": "1.7.
|
|
82
|
-
"@jsenv/server": "17.6.
|
|
83
|
-
"@jsenv/sourcemap": "1.4.
|
|
77
|
+
"@jsenv/ast": "6.10.10",
|
|
78
|
+
"@jsenv/js-module-fallback": "1.6.14",
|
|
79
|
+
"@jsenv/plugin-bundling": "2.10.32",
|
|
80
|
+
"@jsenv/plugin-minification": "1.7.27",
|
|
81
|
+
"@jsenv/plugin-supervisor": "1.8.29",
|
|
82
|
+
"@jsenv/plugin-transpilation": "1.7.14",
|
|
83
|
+
"@jsenv/server": "17.6.9",
|
|
84
|
+
"@jsenv/sourcemap": "1.4.13",
|
|
84
85
|
"react-table": "7.8.0"
|
|
85
86
|
},
|
|
86
87
|
"devDependencies": {
|