moved around files
This commit is contained in:
748
user-mgmt_backend/node_modules/router/index.js
generated
vendored
Normal file
748
user-mgmt_backend/node_modules/router/index.js
generated
vendored
Normal file
@@ -0,0 +1,748 @@
|
||||
/*!
|
||||
* router
|
||||
* Copyright(c) 2013 Roman Shtylman
|
||||
* Copyright(c) 2014-2022 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
* @private
|
||||
*/
|
||||
|
||||
const isPromise = require('is-promise')
|
||||
const Layer = require('./lib/layer')
|
||||
const { METHODS } = require('node:http')
|
||||
const parseUrl = require('parseurl')
|
||||
const Route = require('./lib/route')
|
||||
const debug = require('debug')('router')
|
||||
const deprecate = require('depd')('router')
|
||||
|
||||
/**
|
||||
* Module variables.
|
||||
* @private
|
||||
*/
|
||||
|
||||
const slice = Array.prototype.slice
|
||||
const flatten = Array.prototype.flat
|
||||
const methods = METHODS.map((method) => method.toLowerCase())
|
||||
|
||||
/**
|
||||
* Expose `Router`.
|
||||
*/
|
||||
|
||||
module.exports = Router
|
||||
|
||||
/**
|
||||
* Expose `Route`.
|
||||
*/
|
||||
|
||||
module.exports.Route = Route
|
||||
|
||||
/**
|
||||
* Initialize a new `Router` with the given `options`.
|
||||
*
|
||||
* @param {object} [options]
|
||||
* @return {Router} which is a callable function
|
||||
* @public
|
||||
*/
|
||||
|
||||
function Router (options) {
|
||||
if (!(this instanceof Router)) {
|
||||
return new Router(options)
|
||||
}
|
||||
|
||||
const opts = options || {}
|
||||
|
||||
function router (req, res, next) {
|
||||
router.handle(req, res, next)
|
||||
}
|
||||
|
||||
// inherit from the correct prototype
|
||||
Object.setPrototypeOf(router, this)
|
||||
|
||||
router.caseSensitive = opts.caseSensitive
|
||||
router.mergeParams = opts.mergeParams
|
||||
router.params = {}
|
||||
router.strict = opts.strict
|
||||
router.stack = []
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
/**
|
||||
* Router prototype inherits from a Function.
|
||||
*/
|
||||
|
||||
/* istanbul ignore next */
|
||||
Router.prototype = function () {}
|
||||
|
||||
/**
|
||||
* Map the given param placeholder `name`(s) to the given callback.
|
||||
*
|
||||
* Parameter mapping is used to provide pre-conditions to routes
|
||||
* which use normalized placeholders. For example a _:user_id_ parameter
|
||||
* could automatically load a user's information from the database without
|
||||
* any additional code.
|
||||
*
|
||||
* The callback uses the same signature as middleware, the only difference
|
||||
* being that the value of the placeholder is passed, in this case the _id_
|
||||
* of the user. Once the `next()` function is invoked, just like middleware
|
||||
* it will continue on to execute the route, or subsequent parameter functions.
|
||||
*
|
||||
* Just like in middleware, you must either respond to the request or call next
|
||||
* to avoid stalling the request.
|
||||
*
|
||||
* router.param('user_id', function(req, res, next, id){
|
||||
* User.find(id, function(err, user){
|
||||
* if (err) {
|
||||
* return next(err)
|
||||
* } else if (!user) {
|
||||
* return next(new Error('failed to load user'))
|
||||
* }
|
||||
* req.user = user
|
||||
* next()
|
||||
* })
|
||||
* })
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {function} fn
|
||||
* @public
|
||||
*/
|
||||
|
||||
Router.prototype.param = function param (name, fn) {
|
||||
if (!name) {
|
||||
throw new TypeError('argument name is required')
|
||||
}
|
||||
|
||||
if (typeof name !== 'string') {
|
||||
throw new TypeError('argument name must be a string')
|
||||
}
|
||||
|
||||
if (!fn) {
|
||||
throw new TypeError('argument fn is required')
|
||||
}
|
||||
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError('argument fn must be a function')
|
||||
}
|
||||
|
||||
let params = this.params[name]
|
||||
|
||||
if (!params) {
|
||||
params = this.params[name] = []
|
||||
}
|
||||
|
||||
params.push(fn)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a req, res into the router.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
Router.prototype.handle = function handle (req, res, callback) {
|
||||
if (!callback) {
|
||||
throw new TypeError('argument callback is required')
|
||||
}
|
||||
|
||||
debug('dispatching %s %s', req.method, req.url)
|
||||
|
||||
let idx = 0
|
||||
let methods
|
||||
const protohost = getProtohost(req.url) || ''
|
||||
let removed = ''
|
||||
const self = this
|
||||
let slashAdded = false
|
||||
let sync = 0
|
||||
const paramcalled = {}
|
||||
|
||||
// middleware and routes
|
||||
const stack = this.stack
|
||||
|
||||
// manage inter-router variables
|
||||
const parentParams = req.params
|
||||
const parentUrl = req.baseUrl || ''
|
||||
let done = restore(callback, req, 'baseUrl', 'next', 'params')
|
||||
|
||||
// setup next layer
|
||||
req.next = next
|
||||
|
||||
// for options requests, respond with a default if nothing else responds
|
||||
if (req.method === 'OPTIONS') {
|
||||
methods = []
|
||||
done = wrap(done, generateOptionsResponder(res, methods))
|
||||
}
|
||||
|
||||
// setup basic req values
|
||||
req.baseUrl = parentUrl
|
||||
req.originalUrl = req.originalUrl || req.url
|
||||
|
||||
next()
|
||||
|
||||
function next (err) {
|
||||
let layerError = err === 'route'
|
||||
? null
|
||||
: err
|
||||
|
||||
// remove added slash
|
||||
if (slashAdded) {
|
||||
req.url = req.url.slice(1)
|
||||
slashAdded = false
|
||||
}
|
||||
|
||||
// restore altered req.url
|
||||
if (removed.length !== 0) {
|
||||
req.baseUrl = parentUrl
|
||||
req.url = protohost + removed + req.url.slice(protohost.length)
|
||||
removed = ''
|
||||
}
|
||||
|
||||
// signal to exit router
|
||||
if (layerError === 'router') {
|
||||
setImmediate(done, null)
|
||||
return
|
||||
}
|
||||
|
||||
// no more matching layers
|
||||
if (idx >= stack.length) {
|
||||
setImmediate(done, layerError)
|
||||
return
|
||||
}
|
||||
|
||||
// max sync stack
|
||||
if (++sync > 100) {
|
||||
return setImmediate(next, err)
|
||||
}
|
||||
|
||||
// get pathname of request
|
||||
const path = getPathname(req)
|
||||
|
||||
if (path == null) {
|
||||
return done(layerError)
|
||||
}
|
||||
|
||||
// find next matching layer
|
||||
let layer
|
||||
let match
|
||||
let route
|
||||
|
||||
while (match !== true && idx < stack.length) {
|
||||
layer = stack[idx++]
|
||||
match = matchLayer(layer, path)
|
||||
route = layer.route
|
||||
|
||||
if (typeof match !== 'boolean') {
|
||||
// hold on to layerError
|
||||
layerError = layerError || match
|
||||
}
|
||||
|
||||
if (match !== true) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (!route) {
|
||||
// process non-route handlers normally
|
||||
continue
|
||||
}
|
||||
|
||||
if (layerError) {
|
||||
// routes do not match with a pending error
|
||||
match = false
|
||||
continue
|
||||
}
|
||||
|
||||
const method = req.method
|
||||
const hasMethod = route._handlesMethod(method)
|
||||
|
||||
// build up automatic options response
|
||||
if (!hasMethod && method === 'OPTIONS' && methods) {
|
||||
methods.push.apply(methods, route._methods())
|
||||
}
|
||||
|
||||
// don't even bother matching route
|
||||
if (!hasMethod && method !== 'HEAD') {
|
||||
match = false
|
||||
}
|
||||
}
|
||||
|
||||
// no match
|
||||
if (match !== true) {
|
||||
return done(layerError)
|
||||
}
|
||||
|
||||
// store route for dispatch on change
|
||||
if (route) {
|
||||
req.route = route
|
||||
}
|
||||
|
||||
// Capture one-time layer values
|
||||
req.params = self.mergeParams
|
||||
? mergeParams(layer.params, parentParams)
|
||||
: layer.params
|
||||
const layerPath = layer.path
|
||||
|
||||
// this should be done for the layer
|
||||
processParams(self.params, layer, paramcalled, req, res, function (err) {
|
||||
if (err) {
|
||||
next(layerError || err)
|
||||
} else if (route) {
|
||||
layer.handleRequest(req, res, next)
|
||||
} else {
|
||||
trimPrefix(layer, layerError, layerPath, path)
|
||||
}
|
||||
|
||||
sync = 0
|
||||
})
|
||||
}
|
||||
|
||||
function trimPrefix (layer, layerError, layerPath, path) {
|
||||
if (layerPath.length !== 0) {
|
||||
// Validate path is a prefix match
|
||||
if (layerPath !== path.substring(0, layerPath.length)) {
|
||||
next(layerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Validate path breaks on a path separator
|
||||
const c = path[layerPath.length]
|
||||
if (c && c !== '/') {
|
||||
next(layerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Trim off the part of the url that matches the route
|
||||
// middleware (.use stuff) needs to have the path stripped
|
||||
debug('trim prefix (%s) from url %s', layerPath, req.url)
|
||||
removed = layerPath
|
||||
req.url = protohost + req.url.slice(protohost.length + removed.length)
|
||||
|
||||
// Ensure leading slash
|
||||
if (!protohost && req.url[0] !== '/') {
|
||||
req.url = '/' + req.url
|
||||
slashAdded = true
|
||||
}
|
||||
|
||||
// Setup base URL (no trailing slash)
|
||||
req.baseUrl = parentUrl + (removed[removed.length - 1] === '/'
|
||||
? removed.substring(0, removed.length - 1)
|
||||
: removed)
|
||||
}
|
||||
|
||||
debug('%s %s : %s', layer.name, layerPath, req.originalUrl)
|
||||
|
||||
if (layerError) {
|
||||
layer.handleError(layerError, req, res, next)
|
||||
} else {
|
||||
layer.handleRequest(req, res, next)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given middleware function, with optional path, defaulting to "/".
|
||||
*
|
||||
* Use (like `.all`) will run for any http METHOD, but it will not add
|
||||
* handlers for those methods so OPTIONS requests will not consider `.use`
|
||||
* functions even if they could respond.
|
||||
*
|
||||
* The other difference is that _route_ path is stripped and not visible
|
||||
* to the handler function. The main effect of this feature is that mounted
|
||||
* handlers can operate without any code changes regardless of the "prefix"
|
||||
* pathname.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
Router.prototype.use = function use (handler) {
|
||||
let offset = 0
|
||||
let path = '/'
|
||||
|
||||
// default path to '/'
|
||||
// disambiguate router.use([handler])
|
||||
if (typeof handler !== 'function') {
|
||||
let arg = handler
|
||||
|
||||
while (Array.isArray(arg) && arg.length !== 0) {
|
||||
arg = arg[0]
|
||||
}
|
||||
|
||||
// first arg is the path
|
||||
if (typeof arg !== 'function') {
|
||||
offset = 1
|
||||
path = handler
|
||||
}
|
||||
}
|
||||
|
||||
const callbacks = flatten.call(slice.call(arguments, offset), Infinity)
|
||||
|
||||
if (callbacks.length === 0) {
|
||||
throw new TypeError('argument handler is required')
|
||||
}
|
||||
|
||||
for (let i = 0; i < callbacks.length; i++) {
|
||||
const fn = callbacks[i]
|
||||
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError('argument handler must be a function')
|
||||
}
|
||||
|
||||
// add the middleware
|
||||
debug('use %o %s', path, fn.name || '<anonymous>')
|
||||
|
||||
const layer = new Layer(path, {
|
||||
sensitive: this.caseSensitive,
|
||||
strict: false,
|
||||
end: false
|
||||
}, fn)
|
||||
|
||||
layer.route = undefined
|
||||
|
||||
this.stack.push(layer)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Route for the given path.
|
||||
*
|
||||
* Each route contains a separate middleware stack and VERB handlers.
|
||||
*
|
||||
* See the Route api documentation for details on adding handlers
|
||||
* and middleware to routes.
|
||||
*
|
||||
* @param {string} path
|
||||
* @return {Route}
|
||||
* @public
|
||||
*/
|
||||
|
||||
Router.prototype.route = function route (path) {
|
||||
const route = new Route(path)
|
||||
|
||||
const layer = new Layer(path, {
|
||||
sensitive: this.caseSensitive,
|
||||
strict: this.strict,
|
||||
end: true
|
||||
}, handle)
|
||||
|
||||
function handle (req, res, next) {
|
||||
route.dispatch(req, res, next)
|
||||
}
|
||||
|
||||
layer.route = route
|
||||
|
||||
this.stack.push(layer)
|
||||
return route
|
||||
}
|
||||
|
||||
// create Router#VERB functions
|
||||
methods.concat('all').forEach(function (method) {
|
||||
Router.prototype[method] = function (path) {
|
||||
const route = this.route(path)
|
||||
route[method].apply(route, slice.call(arguments, 1))
|
||||
return this
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Generate a callback that will make an OPTIONS response.
|
||||
*
|
||||
* @param {OutgoingMessage} res
|
||||
* @param {array} methods
|
||||
* @private
|
||||
*/
|
||||
|
||||
function generateOptionsResponder (res, methods) {
|
||||
return function onDone (fn, err) {
|
||||
if (err || methods.length === 0) {
|
||||
return fn(err)
|
||||
}
|
||||
|
||||
trySendOptionsResponse(res, methods, fn)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pathname of request.
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @private
|
||||
*/
|
||||
|
||||
function getPathname (req) {
|
||||
try {
|
||||
return parseUrl(req).pathname
|
||||
} catch (err) {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get get protocol + host for a URL.
|
||||
*
|
||||
* @param {string} url
|
||||
* @private
|
||||
*/
|
||||
|
||||
function getProtohost (url) {
|
||||
if (typeof url !== 'string' || url.length === 0 || url[0] === '/') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const searchIndex = url.indexOf('?')
|
||||
const pathLength = searchIndex !== -1
|
||||
? searchIndex
|
||||
: url.length
|
||||
const fqdnIndex = url.substring(0, pathLength).indexOf('://')
|
||||
|
||||
return fqdnIndex !== -1
|
||||
? url.substring(0, url.indexOf('/', 3 + fqdnIndex))
|
||||
: undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Match path to a layer.
|
||||
*
|
||||
* @param {Layer} layer
|
||||
* @param {string} path
|
||||
* @private
|
||||
*/
|
||||
|
||||
function matchLayer (layer, path) {
|
||||
try {
|
||||
return layer.match(path)
|
||||
} catch (err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge params with parent params
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
function mergeParams (params, parent) {
|
||||
if (typeof parent !== 'object' || !parent) {
|
||||
return params
|
||||
}
|
||||
|
||||
// make copy of parent for base
|
||||
const obj = Object.assign({}, parent)
|
||||
|
||||
// simple non-numeric merging
|
||||
if (!(0 in params) || !(0 in parent)) {
|
||||
return Object.assign(obj, params)
|
||||
}
|
||||
|
||||
let i = 0
|
||||
let o = 0
|
||||
|
||||
// determine numeric gap in params
|
||||
while (i in params) {
|
||||
i++
|
||||
}
|
||||
|
||||
// determine numeric gap in parent
|
||||
while (o in parent) {
|
||||
o++
|
||||
}
|
||||
|
||||
// offset numeric indices in params before merge
|
||||
for (i--; i >= 0; i--) {
|
||||
params[i + o] = params[i]
|
||||
|
||||
// create holes for the merge when necessary
|
||||
if (i < o) {
|
||||
delete params[i]
|
||||
}
|
||||
}
|
||||
|
||||
return Object.assign(obj, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* Process any parameters for the layer.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
function processParams (params, layer, called, req, res, done) {
|
||||
// captured parameters from the layer, keys and values
|
||||
const keys = layer.keys
|
||||
|
||||
// fast track
|
||||
if (!keys || keys.length === 0) {
|
||||
return done()
|
||||
}
|
||||
|
||||
let i = 0
|
||||
let paramIndex = 0
|
||||
let key
|
||||
let paramVal
|
||||
let paramCallbacks
|
||||
let paramCalled
|
||||
|
||||
// process params in order
|
||||
// param callbacks can be async
|
||||
function param (err) {
|
||||
if (err) {
|
||||
return done(err)
|
||||
}
|
||||
|
||||
if (i >= keys.length) {
|
||||
return done()
|
||||
}
|
||||
|
||||
paramIndex = 0
|
||||
key = keys[i++]
|
||||
paramVal = req.params[key]
|
||||
paramCallbacks = params[key]
|
||||
paramCalled = called[key]
|
||||
|
||||
if (paramVal === undefined || !paramCallbacks) {
|
||||
return param()
|
||||
}
|
||||
|
||||
// param previously called with same value or error occurred
|
||||
if (paramCalled && (paramCalled.match === paramVal ||
|
||||
(paramCalled.error && paramCalled.error !== 'route'))) {
|
||||
// restore value
|
||||
req.params[key] = paramCalled.value
|
||||
|
||||
// next param
|
||||
return param(paramCalled.error)
|
||||
}
|
||||
|
||||
called[key] = paramCalled = {
|
||||
error: null,
|
||||
match: paramVal,
|
||||
value: paramVal
|
||||
}
|
||||
|
||||
paramCallback()
|
||||
}
|
||||
|
||||
// single param callbacks
|
||||
function paramCallback (err) {
|
||||
const fn = paramCallbacks[paramIndex++]
|
||||
|
||||
// store updated value
|
||||
paramCalled.value = req.params[key]
|
||||
|
||||
if (err) {
|
||||
// store error
|
||||
paramCalled.error = err
|
||||
param(err)
|
||||
return
|
||||
}
|
||||
|
||||
if (!fn) return param()
|
||||
|
||||
try {
|
||||
const ret = fn(req, res, paramCallback, paramVal, key)
|
||||
if (isPromise(ret)) {
|
||||
if (!(ret instanceof Promise)) {
|
||||
deprecate('parameters that are Promise-like are deprecated, use a native Promise instead')
|
||||
}
|
||||
|
||||
ret.then(null, function (error) {
|
||||
paramCallback(error || new Error('Rejected promise'))
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
paramCallback(e)
|
||||
}
|
||||
}
|
||||
|
||||
param()
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore obj props after function
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
function restore (fn, obj) {
|
||||
const props = new Array(arguments.length - 2)
|
||||
const vals = new Array(arguments.length - 2)
|
||||
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
props[i] = arguments[i + 2]
|
||||
vals[i] = obj[props[i]]
|
||||
}
|
||||
|
||||
return function () {
|
||||
// restore vals
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
obj[props[i]] = vals[i]
|
||||
}
|
||||
|
||||
return fn.apply(this, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an OPTIONS response.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
function sendOptionsResponse (res, methods) {
|
||||
const options = Object.create(null)
|
||||
|
||||
// build unique method map
|
||||
for (let i = 0; i < methods.length; i++) {
|
||||
options[methods[i]] = true
|
||||
}
|
||||
|
||||
// construct the allow list
|
||||
const allow = Object.keys(options).sort().join(', ')
|
||||
|
||||
// send response
|
||||
res.setHeader('Allow', allow)
|
||||
res.setHeader('Content-Length', Buffer.byteLength(allow))
|
||||
res.setHeader('Content-Type', 'text/plain')
|
||||
res.setHeader('X-Content-Type-Options', 'nosniff')
|
||||
res.end(allow)
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to send an OPTIONS response.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
function trySendOptionsResponse (res, methods, next) {
|
||||
try {
|
||||
sendOptionsResponse(res, methods)
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a function
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
function wrap (old, fn) {
|
||||
return function proxy () {
|
||||
const args = new Array(arguments.length + 1)
|
||||
|
||||
args[0] = old
|
||||
for (let i = 0, len = arguments.length; i < len; i++) {
|
||||
args[i + 1] = arguments[i]
|
||||
}
|
||||
|
||||
fn.apply(this, args)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user