@srfnstack/spliffy 1.2.5 → 1.2.6
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/LICENSE.txt +20 -20
- package/README.md +43 -43
- package/package.json +47 -44
- package/src/content.mjs +97 -97
- package/src/decorator.mjs +209 -209
- package/src/handler.mjs +256 -256
- package/src/index.mjs +30 -30
- package/src/log.mjs +59 -59
- package/src/middleware.mjs +89 -89
- package/src/nodeModuleHandler.mjs +75 -75
- package/src/routes.mjs +205 -205
- package/src/server.mjs +141 -141
- package/src/serverConfig.mjs +100 -100
- package/src/start.mjs +25 -25
- package/src/staticHandler.mjs +74 -74
- package/src/url.mjs +24 -24
package/src/log.mjs
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
import util from 'util'
|
|
2
|
-
|
|
3
|
-
const inspect = util.inspect
|
|
4
|
-
const levelOrder = { TRACE: 10, DEBUG: 20, INFO: 30, ACCESS: 30, 'GOOD NEWS EVERYONE!': 30, WARN: 40, ERROR: 50, FATAL: 60, NONE: 100 }
|
|
5
|
-
let logLevel = levelOrder.INFO
|
|
6
|
-
|
|
7
|
-
const ifLevelEnabled = (fn, level, args) => {
|
|
8
|
-
const configLevel = levelOrder[logLevel] || levelOrder.INFO
|
|
9
|
-
if (levelOrder[level] >= configLevel) {
|
|
10
|
-
fn(`[${new Date().toISOString()}] [${level}] ${args.map(a => typeof a === 'string' ? a : inspect(a, { depth: null })).join(' ')}`)
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const callLog = (level, logImplFn, defaultFn, args) => {
|
|
15
|
-
if (logImpl && typeof logImpl[logImplFn] === 'function') {
|
|
16
|
-
logImpl[logImplFn](...args)
|
|
17
|
-
} else {
|
|
18
|
-
ifLevelEnabled(defaultFn, level, args)
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
let logImpl = null
|
|
23
|
-
|
|
24
|
-
export default {
|
|
25
|
-
setLogLevel (level) {
|
|
26
|
-
level = level.toUpperCase()
|
|
27
|
-
if (!(level in levelOrder)) {
|
|
28
|
-
throw new Error(`Invalid level: ${level}`)
|
|
29
|
-
}
|
|
30
|
-
logLevel = level
|
|
31
|
-
},
|
|
32
|
-
setLogger (logger) {
|
|
33
|
-
logImpl = logger
|
|
34
|
-
},
|
|
35
|
-
trace () {
|
|
36
|
-
callLog('TRACE', 'trace', console.trace, [...arguments])
|
|
37
|
-
},
|
|
38
|
-
debug () {
|
|
39
|
-
callLog('DEBUG', 'debug', console.debug, [...arguments])
|
|
40
|
-
},
|
|
41
|
-
info () {
|
|
42
|
-
callLog('INFO', 'info', console.info, [...arguments])
|
|
43
|
-
},
|
|
44
|
-
gne () {
|
|
45
|
-
callLog('GOOD NEWS EVERYONE!', 'info', console.info, [...arguments])
|
|
46
|
-
},
|
|
47
|
-
access () {
|
|
48
|
-
callLog('ACCESS', 'info', console.info, [...arguments])
|
|
49
|
-
},
|
|
50
|
-
warn () {
|
|
51
|
-
callLog('WARN', 'warn', console.warn, [...arguments])
|
|
52
|
-
},
|
|
53
|
-
error () {
|
|
54
|
-
callLog('ERROR', 'error', console.error, [...arguments].map(arg => arg.stack ? arg.stack : arg))
|
|
55
|
-
},
|
|
56
|
-
fatal () {
|
|
57
|
-
callLog('ERROR', 'error', console.error, [...arguments].map(arg => arg.stack ? arg.stack : arg))
|
|
58
|
-
}
|
|
59
|
-
}
|
|
1
|
+
import util from 'util'
|
|
2
|
+
|
|
3
|
+
const inspect = util.inspect
|
|
4
|
+
const levelOrder = { TRACE: 10, DEBUG: 20, INFO: 30, ACCESS: 30, 'GOOD NEWS EVERYONE!': 30, WARN: 40, ERROR: 50, FATAL: 60, NONE: 100 }
|
|
5
|
+
let logLevel = levelOrder.INFO
|
|
6
|
+
|
|
7
|
+
const ifLevelEnabled = (fn, level, args) => {
|
|
8
|
+
const configLevel = levelOrder[logLevel] || levelOrder.INFO
|
|
9
|
+
if (levelOrder[level] >= configLevel) {
|
|
10
|
+
fn(`[${new Date().toISOString()}] [${level}] ${args.map(a => typeof a === 'string' ? a : inspect(a, { depth: null })).join(' ')}`)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const callLog = (level, logImplFn, defaultFn, args) => {
|
|
15
|
+
if (logImpl && typeof logImpl[logImplFn] === 'function') {
|
|
16
|
+
logImpl[logImplFn](...args)
|
|
17
|
+
} else {
|
|
18
|
+
ifLevelEnabled(defaultFn, level, args)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let logImpl = null
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
setLogLevel (level) {
|
|
26
|
+
level = level.toUpperCase()
|
|
27
|
+
if (!(level in levelOrder)) {
|
|
28
|
+
throw new Error(`Invalid level: ${level}`)
|
|
29
|
+
}
|
|
30
|
+
logLevel = level
|
|
31
|
+
},
|
|
32
|
+
setLogger (logger) {
|
|
33
|
+
logImpl = logger
|
|
34
|
+
},
|
|
35
|
+
trace () {
|
|
36
|
+
callLog('TRACE', 'trace', console.trace, [...arguments])
|
|
37
|
+
},
|
|
38
|
+
debug () {
|
|
39
|
+
callLog('DEBUG', 'debug', console.debug, [...arguments])
|
|
40
|
+
},
|
|
41
|
+
info () {
|
|
42
|
+
callLog('INFO', 'info', console.info, [...arguments])
|
|
43
|
+
},
|
|
44
|
+
gne () {
|
|
45
|
+
callLog('GOOD NEWS EVERYONE!', 'info', console.info, [...arguments])
|
|
46
|
+
},
|
|
47
|
+
access () {
|
|
48
|
+
callLog('ACCESS', 'info', console.info, [...arguments])
|
|
49
|
+
},
|
|
50
|
+
warn () {
|
|
51
|
+
callLog('WARN', 'warn', console.warn, [...arguments])
|
|
52
|
+
},
|
|
53
|
+
error () {
|
|
54
|
+
callLog('ERROR', 'error', console.error, [...arguments].map(arg => arg.stack ? arg.stack : arg))
|
|
55
|
+
},
|
|
56
|
+
fatal () {
|
|
57
|
+
callLog('ERROR', 'error', console.error, [...arguments].map(arg => arg.stack ? arg.stack : arg))
|
|
58
|
+
}
|
|
59
|
+
}
|
package/src/middleware.mjs
CHANGED
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
import log from './log.mjs'
|
|
2
|
-
/**
|
|
3
|
-
* middleware is stored as an object where the properties are request methods the middleware applies to
|
|
4
|
-
* if a middleware applies to all methods, the property ALL is used
|
|
5
|
-
* example:
|
|
6
|
-
* {
|
|
7
|
-
* GET: [(req,res,next)=>console.log('ice cream man')]
|
|
8
|
-
* POST: [(req,res,next)=>console.log('gelato')]
|
|
9
|
-
* ALL: [(req,res,next)=>console.log('bruce banner')]
|
|
10
|
-
* }
|
|
11
|
-
*/
|
|
12
|
-
export const mergeMiddleware = (incoming, existing) => {
|
|
13
|
-
const mergeInto = cloneMiddleware(existing)
|
|
14
|
-
|
|
15
|
-
validateMiddleware(incoming)
|
|
16
|
-
if (Array.isArray(incoming)) {
|
|
17
|
-
mergeInto.ALL = (existing.ALL || []).concat(incoming)
|
|
18
|
-
} else if (typeof incoming === 'object') {
|
|
19
|
-
for (const method in incoming) {
|
|
20
|
-
const upMethod = method.toUpperCase()
|
|
21
|
-
mergeInto[upMethod] = (mergeInto[method] || []).concat(incoming[upMethod] || [])
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return mergeInto
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const cloneMiddleware = (middleware) => {
|
|
28
|
-
const clone = { ...middleware }
|
|
29
|
-
for (const method in middleware) {
|
|
30
|
-
clone[method] = [...(middleware[method] || [])]
|
|
31
|
-
}
|
|
32
|
-
return clone
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Ensure the given middleware is valid
|
|
37
|
-
* @param middleware
|
|
38
|
-
*/
|
|
39
|
-
export const validateMiddleware = (middleware) => {
|
|
40
|
-
if (!Array.isArray(middleware) && typeof middleware === 'object') {
|
|
41
|
-
for (const method in middleware) {
|
|
42
|
-
// ensure methods are always available as uppercase
|
|
43
|
-
const upMethod = method.toUpperCase()
|
|
44
|
-
middleware[upMethod] = middleware[method]
|
|
45
|
-
validateMiddlewareArray(middleware[upMethod])
|
|
46
|
-
}
|
|
47
|
-
} else {
|
|
48
|
-
validateMiddlewareArray(middleware)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export const validateMiddlewareArray = (arr) => {
|
|
53
|
-
if (!arr) return
|
|
54
|
-
if (!Array.isArray(arr)) {
|
|
55
|
-
throw new Error('middleware must be an array of functions')
|
|
56
|
-
}
|
|
57
|
-
for (const f of arr) {
|
|
58
|
-
if (typeof f !== 'function') {
|
|
59
|
-
throw new Error('Each element in the array of middleware must be a function')
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export async function invokeMiddleware (middleware, req, res, reqErr) {
|
|
65
|
-
await new Promise((resolve, reject) => {
|
|
66
|
-
let current = -1
|
|
67
|
-
const next = (err) => {
|
|
68
|
-
if (err) reject(err)
|
|
69
|
-
if (res.writableEnded) {
|
|
70
|
-
resolve()
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
current++
|
|
74
|
-
if (current === middleware.length) {
|
|
75
|
-
resolve()
|
|
76
|
-
} else {
|
|
77
|
-
try {
|
|
78
|
-
if (reqErr) middleware[current](reqErr, req, res, next)
|
|
79
|
-
else middleware[current](req, res, next)
|
|
80
|
-
} catch (e) {
|
|
81
|
-
log.error('Middleware threw exception', e)
|
|
82
|
-
reject(e)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
next()
|
|
88
|
-
})
|
|
89
|
-
}
|
|
1
|
+
import log from './log.mjs'
|
|
2
|
+
/**
|
|
3
|
+
* middleware is stored as an object where the properties are request methods the middleware applies to
|
|
4
|
+
* if a middleware applies to all methods, the property ALL is used
|
|
5
|
+
* example:
|
|
6
|
+
* {
|
|
7
|
+
* GET: [(req,res,next)=>console.log('ice cream man')]
|
|
8
|
+
* POST: [(req,res,next)=>console.log('gelato')]
|
|
9
|
+
* ALL: [(req,res,next)=>console.log('bruce banner')]
|
|
10
|
+
* }
|
|
11
|
+
*/
|
|
12
|
+
export const mergeMiddleware = (incoming, existing) => {
|
|
13
|
+
const mergeInto = cloneMiddleware(existing)
|
|
14
|
+
|
|
15
|
+
validateMiddleware(incoming)
|
|
16
|
+
if (Array.isArray(incoming)) {
|
|
17
|
+
mergeInto.ALL = (existing.ALL || []).concat(incoming)
|
|
18
|
+
} else if (typeof incoming === 'object') {
|
|
19
|
+
for (const method in incoming) {
|
|
20
|
+
const upMethod = method.toUpperCase()
|
|
21
|
+
mergeInto[upMethod] = (mergeInto[method] || []).concat(incoming[upMethod] || [])
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return mergeInto
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const cloneMiddleware = (middleware) => {
|
|
28
|
+
const clone = { ...middleware }
|
|
29
|
+
for (const method in middleware) {
|
|
30
|
+
clone[method] = [...(middleware[method] || [])]
|
|
31
|
+
}
|
|
32
|
+
return clone
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Ensure the given middleware is valid
|
|
37
|
+
* @param middleware
|
|
38
|
+
*/
|
|
39
|
+
export const validateMiddleware = (middleware) => {
|
|
40
|
+
if (!Array.isArray(middleware) && typeof middleware === 'object') {
|
|
41
|
+
for (const method in middleware) {
|
|
42
|
+
// ensure methods are always available as uppercase
|
|
43
|
+
const upMethod = method.toUpperCase()
|
|
44
|
+
middleware[upMethod] = middleware[method]
|
|
45
|
+
validateMiddlewareArray(middleware[upMethod])
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
validateMiddlewareArray(middleware)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const validateMiddlewareArray = (arr) => {
|
|
53
|
+
if (!arr) return
|
|
54
|
+
if (!Array.isArray(arr)) {
|
|
55
|
+
throw new Error('middleware must be an array of functions')
|
|
56
|
+
}
|
|
57
|
+
for (const f of arr) {
|
|
58
|
+
if (typeof f !== 'function') {
|
|
59
|
+
throw new Error('Each element in the array of middleware must be a function')
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function invokeMiddleware (middleware, req, res, reqErr) {
|
|
65
|
+
await new Promise((resolve, reject) => {
|
|
66
|
+
let current = -1
|
|
67
|
+
const next = (err) => {
|
|
68
|
+
if (err) reject(err)
|
|
69
|
+
if (res.writableEnded) {
|
|
70
|
+
resolve()
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
current++
|
|
74
|
+
if (current === middleware.length) {
|
|
75
|
+
resolve()
|
|
76
|
+
} else {
|
|
77
|
+
try {
|
|
78
|
+
if (reqErr) middleware[current](reqErr, req, res, next)
|
|
79
|
+
else middleware[current](req, res, next)
|
|
80
|
+
} catch (e) {
|
|
81
|
+
log.error('Middleware threw exception', e)
|
|
82
|
+
reject(e)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
next()
|
|
88
|
+
})
|
|
89
|
+
}
|
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import { mergeMiddleware } from './middleware.mjs'
|
|
4
|
-
import { createStaticHandler } from './staticHandler.mjs'
|
|
5
|
-
import { getContentTypeByExtension } from './content.mjs'
|
|
6
|
-
|
|
7
|
-
const stripLeadingSlash = p => p.startsWith('/') ? p.substr(1) : p
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
This helper will add all the configured node_module files to the given routes.
|
|
11
|
-
The configured node moduleRoutes must be explicit files, no pattern matching is supported.
|
|
12
|
-
Generating the list of files using pattern matching yourself is highly discouraged.
|
|
13
|
-
It is much safer to explicitly list every file you wish to be served so you don't inadvertently serve additional files.
|
|
14
|
-
|
|
15
|
-
The default method is to read and serve directly from the node_modules directory without copying.
|
|
16
|
-
if method is set to "copy", files are copied from node_modules to their final location within the routes dir folder.
|
|
17
|
-
|
|
18
|
-
The primary benefit of using this in copy mode is that the files will be automatically updated when the package version
|
|
19
|
-
is updated, and it improves IDE integration by making the file really available after first run.
|
|
20
|
-
|
|
21
|
-
This could be destructive if not configured correctly, hence the default of read only
|
|
22
|
-
*/
|
|
23
|
-
export function getNodeModuleRoutes (config) {
|
|
24
|
-
const nodeModuleRoutes = config.nodeModuleRoutes
|
|
25
|
-
const routes = []
|
|
26
|
-
if (nodeModuleRoutes && typeof nodeModuleRoutes === 'object') {
|
|
27
|
-
const nodeModulesDir = nodeModuleRoutes.nodeModulesPath ? path.resolve(nodeModuleRoutes.nodeModulesPath) : path.resolve(config.routeDir, '..', 'node_modules')
|
|
28
|
-
if (!fs.existsSync(nodeModulesDir)) {
|
|
29
|
-
throw new Error(`Unable to find node_modules dir at ${nodeModulesDir}`)
|
|
30
|
-
}
|
|
31
|
-
const prefix = stripLeadingSlash(nodeModuleRoutes.routePrefix || 'lib/ext')
|
|
32
|
-
if (!Array.isArray(nodeModuleRoutes.files)) {
|
|
33
|
-
nodeModuleRoutes.files = [nodeModuleRoutes.files]
|
|
34
|
-
}
|
|
35
|
-
for (const file of nodeModuleRoutes.files) {
|
|
36
|
-
let filePath, urlPath
|
|
37
|
-
if (file && typeof file === 'object') {
|
|
38
|
-
filePath = path.join(nodeModulesDir, file.modulePath)
|
|
39
|
-
urlPath = `/${prefix}/${stripLeadingSlash(file.urlPath || file.modulePath)}`
|
|
40
|
-
} else if (file && typeof file === 'string') {
|
|
41
|
-
filePath = path.join(nodeModulesDir, file)
|
|
42
|
-
urlPath = `/${prefix}/${stripLeadingSlash(file)}`
|
|
43
|
-
} else {
|
|
44
|
-
throw new Error('Invalid node_module file: ' + file)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (fs.existsSync(filePath)) {
|
|
48
|
-
if (nodeModuleRoutes.method === 'copy') {
|
|
49
|
-
const dest = path.join(config.routeDir, urlPath)
|
|
50
|
-
fs.mkdirSync(path.dirname(dest), { recursive: true })
|
|
51
|
-
fs.copyFileSync(filePath, dest)
|
|
52
|
-
} else {
|
|
53
|
-
const parts = urlPath.split('/')
|
|
54
|
-
const lastPart = parts.pop()
|
|
55
|
-
const mw = {}
|
|
56
|
-
mergeMiddleware(config.middleware, mw)
|
|
57
|
-
mergeMiddleware(nodeModuleRoutes.middleware || {}, mw)
|
|
58
|
-
routes.push({
|
|
59
|
-
pathParameters: [],
|
|
60
|
-
urlPath,
|
|
61
|
-
filePath,
|
|
62
|
-
handlers: createStaticHandler(
|
|
63
|
-
filePath, getContentTypeByExtension(lastPart, config.staticContentTypes),
|
|
64
|
-
config.cacheStatic, config.staticCacheControl
|
|
65
|
-
),
|
|
66
|
-
middleware: mw
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
} else {
|
|
70
|
-
console.warn(`The specified node_modules file: ${file} does not exist and will not be served.`)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return routes
|
|
75
|
-
}
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import { mergeMiddleware } from './middleware.mjs'
|
|
4
|
+
import { createStaticHandler } from './staticHandler.mjs'
|
|
5
|
+
import { getContentTypeByExtension } from './content.mjs'
|
|
6
|
+
|
|
7
|
+
const stripLeadingSlash = p => p.startsWith('/') ? p.substr(1) : p
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
This helper will add all the configured node_module files to the given routes.
|
|
11
|
+
The configured node moduleRoutes must be explicit files, no pattern matching is supported.
|
|
12
|
+
Generating the list of files using pattern matching yourself is highly discouraged.
|
|
13
|
+
It is much safer to explicitly list every file you wish to be served so you don't inadvertently serve additional files.
|
|
14
|
+
|
|
15
|
+
The default method is to read and serve directly from the node_modules directory without copying.
|
|
16
|
+
if method is set to "copy", files are copied from node_modules to their final location within the routes dir folder.
|
|
17
|
+
|
|
18
|
+
The primary benefit of using this in copy mode is that the files will be automatically updated when the package version
|
|
19
|
+
is updated, and it improves IDE integration by making the file really available after first run.
|
|
20
|
+
|
|
21
|
+
This could be destructive if not configured correctly, hence the default of read only
|
|
22
|
+
*/
|
|
23
|
+
export function getNodeModuleRoutes (config) {
|
|
24
|
+
const nodeModuleRoutes = config.nodeModuleRoutes
|
|
25
|
+
const routes = []
|
|
26
|
+
if (nodeModuleRoutes && typeof nodeModuleRoutes === 'object') {
|
|
27
|
+
const nodeModulesDir = nodeModuleRoutes.nodeModulesPath ? path.resolve(nodeModuleRoutes.nodeModulesPath) : path.resolve(config.routeDir, '..', 'node_modules')
|
|
28
|
+
if (!fs.existsSync(nodeModulesDir)) {
|
|
29
|
+
throw new Error(`Unable to find node_modules dir at ${nodeModulesDir}`)
|
|
30
|
+
}
|
|
31
|
+
const prefix = stripLeadingSlash(nodeModuleRoutes.routePrefix || 'lib/ext')
|
|
32
|
+
if (!Array.isArray(nodeModuleRoutes.files)) {
|
|
33
|
+
nodeModuleRoutes.files = [nodeModuleRoutes.files]
|
|
34
|
+
}
|
|
35
|
+
for (const file of nodeModuleRoutes.files) {
|
|
36
|
+
let filePath, urlPath
|
|
37
|
+
if (file && typeof file === 'object') {
|
|
38
|
+
filePath = path.join(nodeModulesDir, file.modulePath)
|
|
39
|
+
urlPath = `/${prefix}/${stripLeadingSlash(file.urlPath || file.modulePath)}`
|
|
40
|
+
} else if (file && typeof file === 'string') {
|
|
41
|
+
filePath = path.join(nodeModulesDir, file)
|
|
42
|
+
urlPath = `/${prefix}/${stripLeadingSlash(file)}`
|
|
43
|
+
} else {
|
|
44
|
+
throw new Error('Invalid node_module file: ' + file)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (fs.existsSync(filePath)) {
|
|
48
|
+
if (nodeModuleRoutes.method === 'copy') {
|
|
49
|
+
const dest = path.join(config.routeDir, urlPath)
|
|
50
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true })
|
|
51
|
+
fs.copyFileSync(filePath, dest)
|
|
52
|
+
} else {
|
|
53
|
+
const parts = urlPath.split('/')
|
|
54
|
+
const lastPart = parts.pop()
|
|
55
|
+
const mw = {}
|
|
56
|
+
mergeMiddleware(config.middleware, mw)
|
|
57
|
+
mergeMiddleware(nodeModuleRoutes.middleware || {}, mw)
|
|
58
|
+
routes.push({
|
|
59
|
+
pathParameters: [],
|
|
60
|
+
urlPath,
|
|
61
|
+
filePath,
|
|
62
|
+
handlers: createStaticHandler(
|
|
63
|
+
filePath, getContentTypeByExtension(lastPart, config.staticContentTypes),
|
|
64
|
+
config.cacheStatic, config.staticCacheControl
|
|
65
|
+
),
|
|
66
|
+
middleware: mw
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
console.warn(`The specified node_modules file: ${file} does not exist and will not be served.`)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return routes
|
|
75
|
+
}
|