@jsenv/server 12.6.0 → 12.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/server",
3
- "version": "12.6.0",
3
+ "version": "12.6.3",
4
4
  "description": "Write your Node.js server using pure functions",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -43,7 +43,7 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@jsenv/abort": "4.1.2",
46
- "@jsenv/logger": "4.0.1",
46
+ "@jsenv/logger": "4.1.1",
47
47
  "@jsenv/url-meta": "6.2.0",
48
48
  "node-fetch": "2.6.7",
49
49
  "path-to-regexp": "6.2.0"
@@ -39,20 +39,37 @@ export const fetchFileSystem = async (
39
39
  ? "private,max-age=0,must-revalidate"
40
40
  : "no-store",
41
41
  canReadDirectory = false,
42
- rootDirectoryUrl,
42
+ rootDirectoryUrl, // = `${pathToFileURL(process.cwd())}/`,
43
43
  } = {},
44
44
  ) => {
45
45
  const urlString = asUrlString(filesystemUrl)
46
46
  if (!urlString) {
47
- return send500DueToFilesystemUrlParameter(
47
+ return create500Response(
48
48
  `fetchFileSystem first parameter must be a file url, got ${filesystemUrl}`,
49
49
  )
50
50
  }
51
51
  if (!urlString.startsWith("file://")) {
52
- return send500DueToFilesystemUrlParameter(
52
+ return create500Response(
53
53
  `fetchFileSystem url must use "file://" scheme, got ${filesystemUrl}`,
54
54
  )
55
55
  }
56
+ if (rootDirectoryUrl) {
57
+ let rootDirectoryUrlString = asUrlString(rootDirectoryUrl)
58
+ if (!rootDirectoryUrlString) {
59
+ return create500Response(
60
+ `rootDirectoryUrl must be a string or an url, got ${rootDirectoryUrl}`,
61
+ )
62
+ }
63
+ if (!rootDirectoryUrlString.endsWith("/")) {
64
+ rootDirectoryUrlString = `${rootDirectoryUrlString}/`
65
+ }
66
+ if (!urlString.startsWith(rootDirectoryUrlString)) {
67
+ return create500Response(
68
+ `fetchFileSystem url must be inside root directory, got ${urlString}`,
69
+ )
70
+ }
71
+ rootDirectoryUrl = rootDirectoryUrlString
72
+ }
56
73
 
57
74
  // here you might be tempted to add || cacheControl === 'no-cache'
58
75
  // but no-cache means ressource can be cache but must be revalidated (yeah naming is strange)
@@ -180,7 +197,7 @@ export const fetchFileSystem = async (
180
197
  }
181
198
  }
182
199
 
183
- const send500DueToFilesystemUrlParameter = (message) => {
200
+ const create500Response = (message) => {
184
201
  return {
185
202
  status: 500,
186
203
  headers: {
@@ -419,12 +436,10 @@ const asUrlString = (value) => {
419
436
  if (value instanceof URL) {
420
437
  return value.href
421
438
  }
422
-
423
439
  if (typeof value === "string") {
424
440
  if (isFileSystemPath(value)) {
425
441
  return fileSystemPathToUrl(value)
426
442
  }
427
-
428
443
  try {
429
444
  const urlObject = new URL(value)
430
445
  return String(urlObject)
@@ -432,6 +447,5 @@ const asUrlString = (value) => {
432
447
  return null
433
448
  }
434
449
  }
435
-
436
450
  return null
437
451
  }
package/src/fetch_url.js CHANGED
@@ -28,12 +28,11 @@ export const fetchUrl = async (
28
28
  }
29
29
 
30
30
  if (url.startsWith("file://")) {
31
- const origin = new URL(url).origin
32
31
  const responseProperties = await fetchFileSystem(url, {
33
32
  signal,
34
33
  method,
35
34
  headers,
36
- rootDirectoryUrl: origin,
35
+ rootDirectoryUrl: "file://",
37
36
  cacheStrategy,
38
37
  canReadDirectory,
39
38
  contentTypeMap,
@@ -1,11 +1,10 @@
1
1
  import { readdirSync } from "node:fs"
2
- import { pathToFileURL } from "node:url"
3
2
 
4
3
  import { negotiateContentType } from "./content_negotiation/negotiateContentType.js"
5
4
 
6
5
  export const serveDirectory = (
7
6
  url,
8
- { headers = {}, rootDirectoryUrl = `${pathToFileURL(process.cwd())}/` } = {},
7
+ { headers = {}, rootDirectoryUrl } = {},
9
8
  ) => {
10
9
  url = String(url)
11
10
  url = url[url.length - 1] === "/" ? url : `${url}/`
@@ -299,25 +299,47 @@ export const startServer = async ({
299
299
  const prefixLines = (string, prefix) => {
300
300
  return string.replace(/^(?!\s*$)/gm, prefix)
301
301
  }
302
- const writeLog = ({ type, value }, depth) => {
302
+ const writeLog = (
303
+ { type, value },
304
+ { someLogIsError, someLogIsWarn, depth },
305
+ ) => {
303
306
  if (depth > 0) {
304
307
  value = prefixLines(value, " ".repeat(depth))
305
308
  }
309
+ if (type === "info") {
310
+ if (someLogIsError) {
311
+ type = "error"
312
+ } else if (someLogIsWarn) {
313
+ type = "warn"
314
+ }
315
+ }
306
316
  logger[type](value)
307
317
  }
308
318
  const visitRequestNodeToLog = (requestNode, depth) => {
319
+ let someLogIsError = false
320
+ let someLogIsWarn = false
321
+ requestNode.logs.forEach((log) => {
322
+ if (log.type === "error") {
323
+ someLogIsError = true
324
+ }
325
+ if (log.type === "warn") {
326
+ someLogIsWarn = true
327
+ }
328
+ })
329
+
309
330
  const firstLog = requestNode.logs.shift()
310
331
  const lastLog = requestNode.logs.pop()
311
332
  const middleLogs = requestNode.logs
312
- writeLog(firstLog, depth)
333
+
334
+ writeLog(firstLog, { someLogIsError, someLogIsWarn, depth })
313
335
  middleLogs.forEach((log) => {
314
- writeLog(log, depth)
336
+ writeLog(log, { someLogIsError, someLogIsWarn, depth })
315
337
  })
316
338
  requestNode.children.forEach((child) => {
317
339
  visitRequestNodeToLog(child, depth + 1)
318
340
  })
319
341
  if (lastLog) {
320
- writeLog(lastLog, depth + 1)
342
+ writeLog(lastLog, { someLogIsError, someLogIsWarn, depth: depth + 1 })
321
343
  }
322
344
  }
323
345
  visitRequestNodeToLog(rootRequestNode, 0)