Comparing version 7.2.2 to 7.3.0
#!/usr/bin/env node | ||
// Native | ||
const path = require('path') | ||
const path = require('path'); | ||
// Packages | ||
const updateNotifier = require('update-notifier') | ||
const nodeVersion = require('node-version') | ||
const args = require('args') | ||
const isAsyncSupported = require('is-async-supported') | ||
const updateNotifier = require('update-notifier'); | ||
const nodeVersion = require('node-version'); | ||
const args = require('args'); | ||
const isAsyncSupported = require('is-async-supported'); | ||
// Ours | ||
const pkg = require('../package') | ||
const pkg = require('../package'); | ||
// Throw an error if node version is too low | ||
if (nodeVersion.major < 6) { | ||
console.error(`Error! Micro requires at least version 6 of Node. Please upgrade!`) | ||
process.exit(1) | ||
console.error( | ||
`Error! Micro requires at least version 6 of Node. Please upgrade!` | ||
); | ||
process.exit(1); | ||
} | ||
@@ -24,3 +26,3 @@ | ||
if (!process.env.NOW && pkg.dist) { | ||
updateNotifier({pkg}).notify() | ||
updateNotifier({ pkg }).notify(); | ||
} | ||
@@ -31,3 +33,3 @@ | ||
.option(['H', 'host'], 'Host to listen on', '0.0.0.0') | ||
.option(['s', 'silent'], 'Silent mode') | ||
.option(['s', 'silent'], 'Silent mode'); | ||
@@ -41,12 +43,8 @@ const flags = args.parse(process.argv, { | ||
}, | ||
boolean: [ | ||
'silent' | ||
], | ||
string: [ | ||
'host' | ||
] | ||
boolean: ['silent'], | ||
string: ['host'] | ||
} | ||
}) | ||
}); | ||
let file = args.sub[0] | ||
let file = args.sub[0]; | ||
@@ -56,8 +54,8 @@ if (!file) { | ||
// eslint-disable-next-line import/no-dynamic-require | ||
const packageJson = require(path.resolve(process.cwd(), 'package.json')) | ||
file = packageJson.main || 'index.js' | ||
const packageJson = require(path.resolve(process.cwd(), 'package.json')); | ||
file = packageJson.main || 'index.js'; | ||
} catch (err) { | ||
if (err.code !== 'MODULE_NOT_FOUND') { | ||
console.error(`micro: Could not read \`package.json\`: ${err.message}`) | ||
process.exit(1) | ||
console.error(`micro: Could not read \`package.json\`: ${err.message}`); | ||
process.exit(1); | ||
} | ||
@@ -68,24 +66,26 @@ } | ||
if (!file) { | ||
console.error('micro: Please supply a file.') | ||
args.showHelp() | ||
console.error('micro: Please supply a file.'); | ||
args.showHelp(); | ||
} | ||
if (file[0] !== '/') { | ||
file = path.resolve(process.cwd(), file) | ||
file = path.resolve(process.cwd(), file); | ||
} | ||
if (!isAsyncSupported()) { | ||
const asyncToGen = require('async-to-gen/register') | ||
const asyncToGen = require('async-to-gen/register'); | ||
// Support for keywords "async" and "await" | ||
const pathSep = process.platform === 'win32' ? '\\\\' : '/' | ||
const directoryName = path.parse(path.join(__dirname, '..')).base | ||
const pathSep = process.platform === 'win32' ? '\\\\' : '/'; | ||
const directoryName = path.parse(path.join(__dirname, '..')).base; | ||
// This is required to make transpilation work on Windows | ||
const fileDirectoryPath = path.parse(file).dir.split(path.sep).join(pathSep) | ||
const fileDirectoryPath = path.parse(file).dir.split(path.sep).join(pathSep); | ||
asyncToGen({ | ||
includes: new RegExp(`.*${directoryName}?${pathSep}(lib|bin)|${fileDirectoryPath}.*`), | ||
includes: new RegExp( | ||
`.*${directoryName}?${pathSep}(lib|bin)|${fileDirectoryPath}.*` | ||
), | ||
excludes: null, | ||
sourceMaps: false | ||
}) | ||
}); | ||
} | ||
@@ -95,2 +95,2 @@ | ||
// If needed... Otherwise use the native implementation | ||
require('../lib')(file, flags) | ||
require('../lib')(file, flags); |
// Packages | ||
const detect = require('detect-port') | ||
const detect = require('detect-port'); | ||
// Ours | ||
const serve = require('./server') | ||
const listening = require('./listening') | ||
const getModule = require('./module') | ||
const serve = require('./server'); | ||
const listening = require('./listening'); | ||
const getModule = require('./module'); | ||
module.exports = async (file, flags, module = getModule(file)) => { | ||
const server = serve(module) | ||
const server = serve(module); | ||
let port = flags.port | ||
let host = flags.host | ||
let port = flags.port; | ||
let host = flags.host; | ||
const open = await detect(port) | ||
let inUse = open !== port | ||
const open = await detect(port); | ||
let inUse = open !== port; | ||
if (inUse) { | ||
port = open | ||
port = open; | ||
@@ -24,7 +24,7 @@ inUse = { | ||
open | ||
} | ||
}; | ||
} | ||
if (host === '0.0.0.0') { | ||
host = null | ||
host = null; | ||
} | ||
@@ -34,8 +34,10 @@ | ||
if (err) { | ||
console.error('micro:', err.stack) | ||
process.exit(1) | ||
console.error('micro:', err.stack); | ||
// eslint-disable-next-line unicorn/no-process-exit | ||
process.exit(1); | ||
} | ||
return listening(server, inUse, flags.silent) | ||
}) | ||
} | ||
return listening(server, inUse, flags.silent); | ||
}); | ||
}; |
// Packages | ||
const {write: copy} = require('clipboardy') | ||
const ip = require('ip') | ||
const chalk = require('chalk') | ||
const boxen = require('boxen') | ||
const { write: copy } = require('clipboardy'); | ||
const ip = require('ip'); | ||
const chalk = require('chalk'); | ||
const boxen = require('boxen'); | ||
const copyToClipboard = async text => { | ||
try { | ||
await copy(text) | ||
return true | ||
await copy(text); | ||
return true; | ||
} catch (err) { | ||
return false | ||
return false; | ||
} | ||
} | ||
}; | ||
module.exports = async (server, inUse, silent) => { | ||
const details = server.address() | ||
const ipAddress = ip.address() | ||
const url = `http://${ipAddress}:${details.port}` | ||
const details = server.address(); | ||
const ipAddress = ip.address(); | ||
const url = `http://${ipAddress}:${details.port}`; | ||
const isTTY = process.stdout.isTTY | ||
const isTTY = process.stdout.isTTY; | ||
process.on('SIGINT', () => { | ||
server.close() | ||
process.exit(0) | ||
}) | ||
server.close(); | ||
process.exit(0); | ||
}); | ||
if (!(silent || process.env.NOW)) { | ||
let message = chalk.green('Micro is running!') | ||
let message = chalk.green('Micro is running!'); | ||
if (inUse) { | ||
message += ' ' + chalk.red(`(on port ${inUse.open},` + | ||
` because ${inUse.old} is already in use)`) | ||
message += ' ' + | ||
chalk.red( | ||
`(on port ${inUse.open}, because ${inUse.old} is already in use)` | ||
); | ||
} | ||
message += '\n\n' | ||
message += '\n\n'; | ||
const localURL = `http://localhost:${details.port}` | ||
const localURL = `http://localhost:${details.port}`; | ||
message += `• ${chalk.bold('Local: ')} ${localURL}\n` | ||
message += `• ${chalk.bold('On Your Network: ')} ${url}\n\n` | ||
message += `• ${chalk.bold('Local: ')} ${localURL}\n`; | ||
message += `• ${chalk.bold('On Your Network: ')} ${url}\n\n`; | ||
if (isTTY) { | ||
const copied = await copyToClipboard(localURL) | ||
const copied = await copyToClipboard(localURL); | ||
if (copied) { | ||
message += `${chalk.grey('Copied local address to clipboard!')}` | ||
message += `${chalk.grey('Copied local address to clipboard!')}`; | ||
} | ||
} | ||
console.log(boxen(message, { | ||
padding: 1, | ||
borderColor: 'green', | ||
margin: 1 | ||
})) | ||
console.log( | ||
boxen(message, { | ||
padding: 1, | ||
borderColor: 'green', | ||
margin: 1 | ||
}) | ||
); | ||
} | ||
} | ||
}; |
module.exports = file => { | ||
let mod | ||
let mod; | ||
try { | ||
// eslint-disable-next-line import/no-dynamic-require | ||
mod = require(file) | ||
mod = require(file); | ||
if (mod && typeof mod === 'object') { | ||
mod = mod.default | ||
mod = mod.default; | ||
} | ||
} catch (err) { | ||
console.error(`micro: Error when importing ${file}: ${err.stack}`) | ||
process.exit(1) | ||
console.error(`micro: Error when importing ${file}: ${err.stack}`); | ||
// eslint-disable-next-line unicorn/no-process-exit | ||
process.exit(1); | ||
} | ||
if (typeof mod !== 'function') { | ||
console.error(`micro: "${file}" does not export a function.`) | ||
process.exit(1) | ||
console.error(`micro: "${file}" does not export a function.`); | ||
// eslint-disable-next-line unicorn/no-process-exit | ||
process.exit(1); | ||
} | ||
return mod | ||
} | ||
return mod; | ||
}; |
// Native | ||
const server = require('http').Server | ||
const server = require('http').Server; | ||
// Packages | ||
const getRawBody = require('raw-body') | ||
const typer = require('media-typer') | ||
const isStream = require('isstream') | ||
const Promise = require('bluebird') | ||
const getRawBody = require('raw-body'); | ||
const typer = require('media-typer'); | ||
const isStream = require('isstream'); | ||
const Promise = require('bluebird'); | ||
const DEV = process.env.NODE_ENV === 'development' | ||
const TESTING = process.env.NODE_ENV === 'test' | ||
const DEV = process.env.NODE_ENV === 'development'; | ||
const TESTING = process.env.NODE_ENV === 'test'; | ||
const serve = fn => server((req, res) => exports.run(req, res, fn)) | ||
const serve = fn => server((req, res) => exports.run(req, res, fn)); | ||
module.exports = serve | ||
exports = serve | ||
module.exports = serve; | ||
exports = serve; | ||
exports.send = send | ||
exports.sendError = sendError | ||
exports.createError = createError | ||
exports.send = send; | ||
exports.sendError = sendError; | ||
exports.createError = createError; | ||
@@ -26,56 +26,68 @@ exports.run = (req, res, fn) => | ||
if (val === null) { | ||
send(res, 204, null) | ||
return | ||
send(res, 204, null); | ||
return; | ||
} | ||
// Return a undefined-null value -> send | ||
// Send value if it is not undefined, otherwise assume res.end | ||
// will be called later | ||
if (undefined !== val) { | ||
send(res, res.statusCode || 200, val) | ||
send(res, res.statusCode || 200, val); | ||
} | ||
}) | ||
.catch(err => sendError(req, res, err)) | ||
.catch(err => sendError(req, res, err)); | ||
// Maps requests to buffered raw bodies so that | ||
// multiple calls to `json` work as expected | ||
const rawBodyMap = new WeakMap() | ||
const rawBodyMap = new WeakMap(); | ||
const parseJSON = str => { | ||
try { | ||
return JSON.parse(str) | ||
return JSON.parse(str); | ||
} catch (err) { | ||
throw createError(400, 'Invalid JSON', err) | ||
throw createError(400, 'Invalid JSON', err); | ||
} | ||
} | ||
}; | ||
exports.json = (req, {limit = '1mb'} = {}) => Promise.resolve().then(() => { | ||
const type = req.headers['content-type'] | ||
const length = req.headers['content-length'] | ||
const encoding = typer.parse(type).parameters.charset | ||
exports.buffer = (req, { limit = '1mb', encoding } = {}) => | ||
Promise.resolve().then(() => { | ||
const type = req.headers['content-type'] || 'text/plain'; | ||
const length = req.headers['content-length']; | ||
encoding = encoding === undefined | ||
? typer.parse(type).parameters.charset | ||
: encoding; | ||
let str = rawBodyMap.get(req) | ||
const body = rawBodyMap.get(req); | ||
if (str) { | ||
return parseJSON(str) | ||
} | ||
if (body) { | ||
return body; | ||
} | ||
return getRawBody(req, {limit, length, encoding}).then(buf => { | ||
str = buf | ||
rawBodyMap.set(req, str) | ||
return getRawBody(req, { limit, length, encoding }) | ||
.then(buf => { | ||
rawBodyMap.set(req, buf); | ||
return buf; | ||
}) | ||
.catch(err => { | ||
if (err.type === 'entity.too.large') { | ||
throw createError(413, `Body exceeded ${limit} limit`, err); | ||
} else { | ||
throw createError(400, 'Invalid body', err); | ||
} | ||
}); | ||
}); | ||
return parseJSON(str) | ||
}).catch(err => { | ||
if (err.type === 'entity.too.large') { | ||
throw createError(413, `Body exceeded ${limit} limit`, err) | ||
} else { | ||
throw createError(400, 'Invalid body', err) | ||
} | ||
}) | ||
}) | ||
exports.text = (req, { limit, encoding } = {}) => | ||
exports | ||
.buffer(req, { limit, encoding }) | ||
.then(body => body.toString(encoding)); | ||
exports.json = (req, opts) => | ||
exports.text(req, opts).then(body => parseJSON(body)); | ||
function send(res, code, obj = null) { | ||
res.statusCode = code | ||
res.statusCode = code; | ||
if (obj === null) { | ||
res.end() | ||
return | ||
res.end(); | ||
return; | ||
} | ||
@@ -85,8 +97,8 @@ | ||
if (!res.getHeader('Content-Type')) { | ||
res.setHeader('Content-Type', 'application/octet-stream') | ||
res.setHeader('Content-Type', 'application/octet-stream'); | ||
} | ||
res.setHeader('Content-Length', obj.length) | ||
res.end(obj) | ||
return | ||
res.setHeader('Content-Length', obj.length); | ||
res.end(obj); | ||
return; | ||
} | ||
@@ -96,10 +108,10 @@ | ||
if (!res.getHeader('Content-Type')) { | ||
res.setHeader('Content-Type', 'application/octet-stream') | ||
res.setHeader('Content-Type', 'application/octet-stream'); | ||
} | ||
obj.pipe(res) | ||
return | ||
obj.pipe(res); | ||
return; | ||
} | ||
let str = obj | ||
let str = obj; | ||
@@ -115,27 +127,27 @@ if (typeof obj === 'object' || typeof obj === 'number') { | ||
if (DEV) { | ||
str = JSON.stringify(obj, null, 2) | ||
str = JSON.stringify(obj, null, 2); | ||
} else { | ||
str = JSON.stringify(obj) | ||
str = JSON.stringify(obj); | ||
} | ||
if (!res.getHeader('Content-Type')) { | ||
res.setHeader('Content-Type', 'application/json') | ||
res.setHeader('Content-Type', 'application/json'); | ||
} | ||
} | ||
res.setHeader('Content-Length', Buffer.byteLength(str)) | ||
res.end(str) | ||
res.setHeader('Content-Length', Buffer.byteLength(str)); | ||
res.end(str); | ||
} | ||
function sendError(req, res, {statusCode, status, message, stack}) { | ||
statusCode = statusCode || status | ||
function sendError(req, res, { statusCode, status, message, stack }) { | ||
statusCode = statusCode || status; | ||
if (statusCode) { | ||
send(res, statusCode, DEV ? stack : message) | ||
send(res, statusCode, DEV ? stack : message); | ||
} else { | ||
send(res, 500, DEV ? stack : 'Internal Server Error') | ||
send(res, 500, DEV ? stack : 'Internal Server Error'); | ||
} | ||
if (!TESTING) { | ||
console.error(stack) | ||
console.error(stack); | ||
} | ||
@@ -145,6 +157,6 @@ } | ||
function createError(code, msg, orig) { | ||
const err = new Error(msg) | ||
err.statusCode = code | ||
err.originalError = orig | ||
return err | ||
const err = new Error(msg); | ||
err.statusCode = code; | ||
err.originalError = orig; | ||
return err; | ||
} |
{ | ||
"name": "micro", | ||
"version": "7.2.2", | ||
"version": "7.3.0", | ||
"description": "Asynchronous HTTP microservices", | ||
@@ -11,3 +11,3 @@ "main": "./lib/server.js", | ||
"scripts": { | ||
"precommit": "npm run lint", | ||
"precommit": "lint-staged", | ||
"lint": "xo", | ||
@@ -17,12 +17,14 @@ "test": "npm run lint && NODE_ENV=test nyc ava" | ||
"xo": { | ||
"esnext": true, | ||
"space": true, | ||
"semicolon": false, | ||
"ignores": [ | ||
"examples/**/*" | ||
], | ||
"rules": { | ||
"unicorn/no-process-exit": 0 | ||
} | ||
"extends": "prettier" | ||
}, | ||
"lint-staged": { | ||
"*.js": [ | ||
"npm run lint", | ||
"prettier --single-quote --write", | ||
"git add" | ||
] | ||
}, | ||
"bin": { | ||
@@ -51,4 +53,7 @@ "micro": "./bin/micro.js" | ||
"coveralls": "2.12.0", | ||
"eslint-config-prettier": "1.5.0", | ||
"husky": "0.13.3", | ||
"lint-staged": "3.4.0", | ||
"nyc": "10.1.2", | ||
"prettier": "0.22.0", | ||
"request": "2.81.0", | ||
@@ -59,6 +64,6 @@ "request-promise": "4.2.0", | ||
"then-sleep": "1.0.1", | ||
"xo": "0.18.0" | ||
"xo": "0.18.1" | ||
}, | ||
"dependencies": { | ||
"args": "2.3.0", | ||
"args": "2.4.0", | ||
"async-to-gen": "1.3.2", | ||
@@ -65,0 +70,0 @@ "bluebird": "3.5.0", |
@@ -100,10 +100,16 @@ ![](https://raw.githubusercontent.com/zeit/art/31913be3107827adf10e1f491ec61480f63e19af/micro/logo.png) | ||
For parsing the incoming request body we included an async function `json` | ||
For parsing the incoming request body we included an async functions `buffer`, `text` and `json` | ||
```js | ||
const {json} = require('micro') | ||
const {buffer, text, json} = require('micro') | ||
module.exports = async (req, res) => { | ||
const data = await json(req) | ||
console.log(data.price) | ||
const buf = await buffer(req) | ||
console.log(buf) | ||
// <Buffer 7b 22 70 72 69 63 65 22 3a 20 39 2e 39 39 7d> | ||
const txt = await text(req) | ||
// '{"price": 9.99}' | ||
const js = await json(req) | ||
// { price: 9.99 } | ||
console.log(js.price) | ||
return '' | ||
@@ -115,5 +121,6 @@ } | ||
**`json(req, { limit = '1mb' })`** | ||
##### `buffer(req, { limit = '1mb', encoding = 'utf8' })` | ||
##### `text(req, { limit = '1mb', encoding = 'utf8' })` | ||
##### `json(req, { limit = '1mb', encoding = 'utf8' })` | ||
- Use `require('micro').json`. | ||
- Buffers and parses the incoming body and returns it. | ||
@@ -144,3 +151,3 @@ - Exposes an `async` function that can be run with `await`. | ||
**`send(res, statusCode, data = null)`** | ||
##### `send(res, statusCode, data = null)` | ||
@@ -174,3 +181,3 @@ - Use `require('micro').send`. | ||
**`micro(fn)`** | ||
##### micro(fn) | ||
@@ -255,3 +262,3 @@ - This function is exposed as the `default` export. | ||
**`sendError(req, res, error)`** | ||
##### sendError(req, res, error) | ||
@@ -265,3 +272,3 @@ - Use `require('micro').sendError`. | ||
**`createError(code, msg, orig)`** | ||
##### createError(code, msg, orig) | ||
@@ -268,0 +275,0 @@ - Use `require('micro').createError`. |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
23560
302
372
13
2
+ Addedargs@2.4.0(transitive)
- Removedargs@2.3.0(transitive)
- Removedarray-find-index@1.0.2(transitive)
- Removedloud-rejection@1.3.0(transitive)
- Removedsignal-exit@2.1.2(transitive)
Updatedargs@2.4.0