Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Forget about maintaining routes files, use dynamic routes created from files in a folder
Forget about maintaining routes files, use dynamic routes created from files in a folder
npm install lift-it
// Lift the 'api' folder
let api = require('lift-it')('./api').lift()
// Execute the file ./api/item/create.js
api.run('item/create', {
name: 'Water',
value: 17
}, function (err, response) {
// Always async
})
Lift-it scans recursively a folder for *.js
files. Those files should export a handler
function, executed when someones 'run' them. The only ignored file is errors.js
.
An example of 'item/create':
// `body` is the argument passed by 'run' (in this case, `{name:'Water',value:17}`)
// `success` and `error` are callback functions, learn about it here:
// https://github.com/clubedaentrega/run-it
module.exports.handler = function (body, success, error) {
// Item.create represents an async job
Item.create(body, error(function (item) {
// Answer with {id: '54bd55fc13e53ce1077415a2'}
success({
id: item.id
})
}))
}
This module can be easily used with express (or any other route-based web framework).
An example of simple JSON-based POST api:
// Express
let app = require('express')()
app.use(require('body-parser').json())
// Lift
let api = require('lift-it')('./api').lift()
// Set routes
api.actions.forEach(function (action) {
// `action` is an object. See the docs bellow
app.post(action.name, function (req, res) {
// action.run(...) is the same as api.run(action.name, ...)
action.run(req.body, function (err, response) {
res.json(err ? {error: String(err)} : response)
})
})
})
The base module will scan a folder and look for exported handler in *.js
files. This base behaviour can be expanded with plugins.
The available bundled plugins are:
A function with one parameter, the folder path to scan: require('lift-it')(folder)
.
Returns a lifter
object.
Do a lean lift. See lifter.lean()
. Returns a lifted instance
Add the given plugin to the lift process. Read more about available and custom plugins bellow
Whether the folder should be scanned recursively or not. The default value is true
.
A callback to handle requiring a file. This allows one to completly change the semantics of a required file. The default value is function (require, path) { return require(path) }
.
Change settings of run-it. Must be changed only before lifter.lift()
is called.
Run the lift process (sync), throws if any error happens. For each *.js
file in the target folder, all plugins will be executed in the order they were 'use'd.
This returns a lifted
object.
Run the lean lift process, that is, only look for file names. This will not require files, nor apply plugins.
This returns a lifted
object with the lean
flag on. No action can be executed on it.
This is useful if you just want to check action names, not execute them.
Return an action by name. Return an action
object (or null
if not found).
Run the action with the given arguments. callback(err,...output)
is executed when done. The action is executed in its own domain, see run-it for more info about that.
Throws if no action with the given name is found.
If profile is enabled, the last argument for callback
is the profile data.
Return a run-it runner for the given action. Call runner.exec(...args, callback)
to actually execute the action. See action.getRunner()
.
Throws if no action with the given name is found.
An array of action
objects
A boolean. If true
, this is a lean lift (see lifter.leanLift()
), so no action can be executed.
File path, like '/api/item/create.js'
Action name, like 'item/create'
. This is the relative path to the target folder, without the trailing '.js'
.
An array of filters, executed before the action handler. This is used by plugins.
An array of post filters, executed after the action handler. This is used by plugins.
The result of require
-ing the file. action.module.handler
is the handler for this action.
A boolean that flags whether profiling is enabled for this action.
Run this action. This is the same as lifted.run(action.name, ...args, callback)
.
Return the run-it runner for the action. Call runner.exec(...args, callback)
to actually execute the action.
This is useful to make some adhoc changes to the runner, like runner.runInfo(info).profile(true).exec(...args, callback)
. See docs on run-it.
If the require
-d file exports profile
(a boolean), this value will overwrite the global lift.profile
. Get this plugin with require('lift-it').profile()
.
For example, this file will have profiling always on:
module.exports.profile = true
module.exports.handler = function (body, success, error) {
// ...
}
Use:
let liftIt = require('lift-it'),
lift = liftIt('./api')
lift.use(liftIt.profile())
let api = lift.lift()
api.run('item/create', item, function (err, response, profileData) {
// ...
})
Add input validation with validate-fields. Get it with require('lift-it').validate(options)
.
options
is an optional object with the properties displayed bellow (default values indicated):
options = {
// The export property name
exportName: 'fields',
// Whether to error out if the file does not export it
optional: false,
// Check input or output
direction: 'input',
// Which argument to validate
// The default will check the first
position: 0,
// A function to return a value if the desired input/output is not present
getDefaultValue: function () {
throw new Error('Insufficient number of arguments')
},
// If lifter.enableErrorCode is true, which code to use in error(code, msg)
code: 101,
// If lifter.enableErrorCode is true, which code to use in error(HTTPStatusCode, code, msg)
HTTPStatusCode: 500,
// A function to handle error cases
errorHandler: function (action, value, err) {
// `action` is an Action instance
// `value` is the offending value
// `err` is a lifter.errorClass instance
// `err.code` is `options.code`
throw err
},
// Let you define your own custom types
// See doc on validate-fields module for that
defineTypes: function (validate) {},
// Options passed to schema.validate() of validate-fields
options: {}
}
Example of a file using it:
module.exports.fields = {
name: String,
value: 'uint'
}
module.exports.handler = function (body, success, error) {
// ...
}
let liftIt = require('lift-it'),
lift = liftIt('./api')
lift.use(liftIt.validate())
let api = lift.lift()
api.run('item/create', {}, function (err) {
// err is new Error('I was expecting a value in name')
})
This plugin will set action.module[exportName+'-schema']
to validate.parse(action.module[exportName])
.
Add support for filters. Filters are functions executed sequentially before the handler. One example of their use is implementing authentication. Get it with require('lift-it').filters(folder)
.
Filter handlers are implemented and exported by files in the filters folder. Each of those files may export as many filters as you want.
See an example of a file implementing two filters:
module.exports = function (body, success, error) {
// Check auth, read the DB, etc
success('Some data I got elsewhere')
}
module.exports.double = function (body, success, error) {
// Simply change the body input
body.value *= 2
success()
}
The 'item/create'
action may use those filters this way:
module.exports.filters = ['myFilter', 'myFilter.double']
module.exports.handler = function (body, moreData, success, error) {
// body.value will be doubled
// moreData will be the string create by the first filter
// ...
}
If this filter file path is 'filters/myFilter.js'
, the main file (the one that lifts everything) may be:
let liftIt = require('lift-it'),
lift = liftIt('./api')
lift.use(liftIt.filters('./filters'))
let api = lift.lift()
api.run('item/create', {value: 10}, function (err, response) {
// ...
})
A plugin is a function like function (action, lifter) {}
. That function is called once for every file that is found in the lifted folder. Creating your own plugin is that simple:
let myPlugin = function (action, lifter) {
// Do something with the action, like checking something
if (action.name.indexOf('drop')) {
throw new Error('Sorry, we do not put up with dropping things...')
}
// Add a filter to every action to delay them by 1s
action.filters.push(function (body, success) {
setTimeout(success, 1e3)
})
// Add a post filter to check something
action.postFilters.push(function (response, success) {
if (typeof response.status !== 'string') {
throw new Error('Response should have the status field')
}
success(response)
})
}
Warn: the lifter
object should not be modified. It should be treated as read-only.
FAQs
Forget about maintaining routes files, use dynamic routes created from files in a folder
The npm package lift-it receives a total of 1 weekly downloads. As such, lift-it popularity was classified as not popular.
We found that lift-it demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.