Update app and tooling
This commit is contained in:
parent
3046531bdd
commit
e620ec7349
4950 changed files with 2975120 additions and 10 deletions
21
node_modules/micro/LICENSE
generated
vendored
Normal file
21
node_modules/micro/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 ZEIT, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
369
node_modules/micro/README.md
generated
vendored
Normal file
369
node_modules/micro/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
<img src="https://raw.githubusercontent.com/zeit/art/6451bc300e00312d970527274f316f9b2c07a27e/micro/logo.png" width="50"/>
|
||||
|
||||
_**Micro** — Asynchronous HTTP microservices_
|
||||
|
||||
[](https://circleci.com/gh/zeit/micro/tree/master)
|
||||
[](https://packagephobia.now.sh/result?p=micro)
|
||||
[](https://spectrum.chat/zeit)
|
||||
|
||||
## Features
|
||||
|
||||
* **Easy**: Designed for usage with `async` and `await` ([more](https://zeit.co/blog/async-and-await))
|
||||
* **Fast**: Ultra-high performance (even JSON parsing is opt-in)
|
||||
* **Micro**: The whole project is ~260 lines of code
|
||||
* **Agile**: Super easy deployment and containerization
|
||||
* **Simple**: Oriented for single purpose modules (function)
|
||||
* **Standard**: Just HTTP!
|
||||
* **Explicit**: No middleware - modules declare all [dependencies](https://github.com/amio/awesome-micro)
|
||||
* **Lightweight**: With all dependencies, the package weighs less than a megabyte
|
||||
|
||||
## Installation
|
||||
|
||||
**Important:** Micro is only meant to be used in production. In development, you should use [micro-dev](https://github.com/zeit/micro-dev), which provides you with a tool belt specifically tailored for developing microservices.
|
||||
|
||||
To prepare your microservice for running in the production environment, firstly install `micro`:
|
||||
|
||||
```bash
|
||||
npm install --save micro
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Create an `index.js` file and export a function that accepts the standard [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage) and [http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse) objects:
|
||||
|
||||
```js
|
||||
module.exports = (req, res) => {
|
||||
res.end('Welcome to Micro')
|
||||
}
|
||||
```
|
||||
|
||||
Micro provides [useful helpers](https://github.com/zeit/micro#body-parsing) but also handles return values – so you can write it even shorter!
|
||||
|
||||
```js
|
||||
module.exports = () => 'Welcome to Micro'
|
||||
```
|
||||
|
||||
Next, ensure that the `main` property inside `package.json` points to your microservice (which is inside `index.js` in this example case) and add a `start` script:
|
||||
|
||||
```json
|
||||
{
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "micro"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Once all of that is done, the server can be started like this:
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
And go to this URL: `http://localhost:3000` - 🎉
|
||||
|
||||
### Command line
|
||||
|
||||
```
|
||||
micro - Asynchronous HTTP microservices
|
||||
|
||||
USAGE
|
||||
|
||||
$ micro --help
|
||||
$ micro --version
|
||||
$ micro [-l listen_uri [-l ...]] [entry_point.js]
|
||||
|
||||
By default micro will listen on 0.0.0.0:3000 and will look first
|
||||
for the "main" property in package.json and subsequently for index.js
|
||||
as the default entry_point.
|
||||
|
||||
Specifying a single --listen argument will overwrite the default, not supplement it.
|
||||
|
||||
OPTIONS
|
||||
|
||||
--help shows this help message
|
||||
|
||||
-v, --version displays the current version of micro
|
||||
|
||||
-l, --listen listen_uri specify a URI endpoint on which to listen (see below) -
|
||||
more than one may be specified to listen in multiple places
|
||||
|
||||
ENDPOINTS
|
||||
|
||||
Listen endpoints (specified by the --listen or -l options above) instruct micro
|
||||
to listen on one or more interfaces/ports, UNIX domain sockets, or Windows named pipes.
|
||||
|
||||
For TCP (traditional host/port) endpoints:
|
||||
|
||||
$ micro -l tcp://hostname:1234
|
||||
|
||||
For UNIX domain socket endpoints:
|
||||
|
||||
$ micro -l unix:/path/to/socket.sock
|
||||
|
||||
For Windows named pipe endpoints:
|
||||
|
||||
$ micro -l pipe:\\.\pipe\PipeName
|
||||
```
|
||||
|
||||
### `async` & `await`
|
||||
|
||||
<p><details>
|
||||
<summary><b>Examples</b></summary>
|
||||
<ul><li><a href="./examples/external-api-call">Fetch external api</a></li></ul>
|
||||
</details></p>
|
||||
|
||||
Micro is built for usage with async/await. You can read more about async / await [here](https://zeit.co/blog/async-and-await)
|
||||
|
||||
```js
|
||||
const sleep = require('then-sleep')
|
||||
|
||||
module.exports = async (req, res) => {
|
||||
await sleep(500)
|
||||
return 'Ready!'
|
||||
}
|
||||
```
|
||||
|
||||
### Port Based on Environment Variable
|
||||
|
||||
When you want to set the port using an environment variable you can use:
|
||||
|
||||
```
|
||||
micro -l tcp://0.0.0.0:$PORT
|
||||
```
|
||||
|
||||
Optionally you can add a default if it suits your use case:
|
||||
|
||||
```
|
||||
micro -l tcp://0.0.0.0:${PORT-3000}
|
||||
```
|
||||
|
||||
`${PORT-3000}` will allow a fallback to port `3000` when `$PORT` is not defined.
|
||||
|
||||
Note that this only works in Bash.
|
||||
|
||||
### Body parsing
|
||||
|
||||
<p id="body-parsing-examples"><details>
|
||||
<summary><b>Examples</b></summary>
|
||||
<ul>
|
||||
<li><a href="./examples/json-body-parsing">Parse JSON</a></li>
|
||||
<li><a href="./examples/urlencoded-body-parsing">Parse urlencoded form (html `form` tag)</a></li>
|
||||
</ul>
|
||||
</details></p>
|
||||
|
||||
For parsing the incoming request body we included an async functions `buffer`, `text` and `json`
|
||||
|
||||
```js
|
||||
const {buffer, text, json} = require('micro')
|
||||
|
||||
module.exports = async (req, res) => {
|
||||
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)
|
||||
console.log(txt)
|
||||
// '{"price": 9.99}'
|
||||
const js = await json(req)
|
||||
console.log(js.price)
|
||||
// 9.99
|
||||
return ''
|
||||
}
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
##### `buffer(req, { limit = '1mb', encoding = 'utf8' })`
|
||||
##### `text(req, { limit = '1mb', encoding = 'utf8' })`
|
||||
##### `json(req, { limit = '1mb', encoding = 'utf8' })`
|
||||
|
||||
- Buffers and parses the incoming body and returns it.
|
||||
- Exposes an `async` function that can be run with `await`.
|
||||
- Can be called multiple times, as it caches the raw request body the first time.
|
||||
- `limit` is how much data is aggregated before parsing at max. Otherwise, an `Error` is thrown with `statusCode` set to `413` (see [Error Handling](#error-handling)). It can be a `Number` of bytes or [a string](https://www.npmjs.com/package/bytes) like `'1mb'`.
|
||||
- If JSON parsing fails, an `Error` is thrown with `statusCode` set to `400` (see [Error Handling](#error-handling))
|
||||
|
||||
For other types of data check the [examples](#body-parsing-examples)
|
||||
|
||||
### Sending a different status code
|
||||
|
||||
So far we have used `return` to send data to the client. `return 'Hello World'` is the equivalent of `send(res, 200, 'Hello World')`.
|
||||
|
||||
```js
|
||||
const {send} = require('micro')
|
||||
|
||||
module.exports = async (req, res) => {
|
||||
const statusCode = 400
|
||||
const data = { error: 'Custom error message' }
|
||||
|
||||
send(res, statusCode, data)
|
||||
}
|
||||
```
|
||||
|
||||
##### `send(res, statusCode, data = null)`
|
||||
|
||||
- Use `require('micro').send`.
|
||||
- `statusCode` is a `Number` with the HTTP status code, and must always be supplied.
|
||||
- If `data` is supplied it is sent in the response. Different input types are processed appropriately, and `Content-Type` and `Content-Length` are automatically set.
|
||||
- `Stream`: `data` is piped as an `octet-stream`. Note: it is _your_ responsibility to handle the `error` event in this case (usually, simply logging the error and aborting the response is enough).
|
||||
- `Buffer`: `data` is written as an `octet-stream`.
|
||||
- `object`: `data` is serialized as JSON.
|
||||
- `string`: `data` is written as-is.
|
||||
- If JSON serialization fails (for example, if a cyclical reference is found), a `400` error is thrown. See [Error Handling](#error-handling).
|
||||
|
||||
### Programmatic use
|
||||
|
||||
You can use Micro programmatically by requiring Micro directly:
|
||||
|
||||
```js
|
||||
const http = require('http')
|
||||
const micro = require('micro')
|
||||
const sleep = require('then-sleep')
|
||||
|
||||
const server = new http.Server(micro(async (req, res) => {
|
||||
await sleep(500)
|
||||
return 'Hello world'
|
||||
}))
|
||||
|
||||
server.listen(3000)
|
||||
```
|
||||
|
||||
##### micro(fn)
|
||||
|
||||
- This function is exposed as the `default` export.
|
||||
- Use `require('micro')`.
|
||||
- Returns a function with the `(req, res) => void` signature. That uses the provided `function` as the request handler.
|
||||
- The supplied function is run with `await`. So it can be `async`
|
||||
|
||||
##### sendError(req, res, error)
|
||||
|
||||
- Use `require('micro').sendError`.
|
||||
- Used as the default handler for errors thrown.
|
||||
- Automatically sets the status code of the response based on `error.statusCode`.
|
||||
- Sends the `error.message` as the body.
|
||||
- Stacks are printed out with `console.error` and during development (when `NODE_ENV` is set to `'development'`) also sent in responses.
|
||||
- Usually, you don't need to invoke this method yourself, as you can use the [built-in error handling](#error-handling) flow with `throw`.
|
||||
|
||||
##### createError(code, msg, orig)
|
||||
|
||||
- Use `require('micro').createError`.
|
||||
- Creates an error object with a `statusCode`.
|
||||
- Useful for easily throwing errors with HTTP status codes, which are interpreted by the [built-in error handling](#error-handling).
|
||||
- `orig` sets `error.originalError` which identifies the original error (if any).
|
||||
|
||||
## Error Handling
|
||||
|
||||
Micro allows you to write robust microservices. This is accomplished primarily by bringing sanity back to error handling and avoiding callback soup.
|
||||
|
||||
If an error is thrown and not caught by you, the response will automatically be `500`. **Important:** Error stacks will be printed as `console.error` and during development mode (if the env variable `NODE_ENV` is `'development'`), they will also be included in the responses.
|
||||
|
||||
If the `Error` object that's thrown contains a `statusCode` property, that's used as the HTTP code to be sent. Let's say you want to write a rate limiting module:
|
||||
|
||||
```js
|
||||
const rateLimit = require('my-rate-limit')
|
||||
|
||||
module.exports = async (req, res) => {
|
||||
await rateLimit(req)
|
||||
// ... your code
|
||||
}
|
||||
```
|
||||
|
||||
If the API endpoint is abused, it can throw an error with ``createError`` like so:
|
||||
|
||||
```js
|
||||
if (tooMany) {
|
||||
throw createError(429, 'Rate limit exceeded')
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively you can create the `Error` object yourself
|
||||
|
||||
```js
|
||||
if (tooMany) {
|
||||
const err = new Error('Rate limit exceeded')
|
||||
err.statusCode = 429
|
||||
throw err
|
||||
}
|
||||
```
|
||||
|
||||
The nice thing about this model is that the `statusCode` is merely a suggestion. The user can override it:
|
||||
|
||||
```js
|
||||
try {
|
||||
await rateLimit(req)
|
||||
} catch (err) {
|
||||
if (429 == err.statusCode) {
|
||||
// perhaps send 500 instead?
|
||||
send(res, 500)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If the error is based on another error that **Micro** caught, like a `JSON.parse` exception, then `originalError` will point to it. If a generic error is caught, the status will be set to `500`.
|
||||
|
||||
In order to set up your own error handling mechanism, you can use composition in your handler:
|
||||
|
||||
```js
|
||||
const {send} = require('micro')
|
||||
|
||||
const handleErrors = fn => async (req, res) => {
|
||||
try {
|
||||
return await fn(req, res)
|
||||
} catch (err) {
|
||||
console.log(err.stack)
|
||||
send(res, 500, 'My custom error!')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = handleErrors(async (req, res) => {
|
||||
throw new Error('What happened here?')
|
||||
})
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Micro makes tests compact and a pleasure to read and write.
|
||||
We recommend [ava](https://github.com/sindresorhus/ava), a highly parallel Micro test framework with built-in support for async tests:
|
||||
|
||||
```js
|
||||
const http = require('http')
|
||||
const micro = require('micro')
|
||||
const test = require('ava')
|
||||
const listen = require('test-listen')
|
||||
const request = require('request-promise')
|
||||
|
||||
test('my endpoint', async t => {
|
||||
const service = new http.Server(micro(async (req, res) => {
|
||||
micro.send(res, 200, {
|
||||
test: 'woot'
|
||||
})
|
||||
}))
|
||||
|
||||
const url = await listen(service)
|
||||
const body = await request(url)
|
||||
|
||||
t.deepEqual(JSON.parse(body).test, 'woot')
|
||||
service.close()
|
||||
})
|
||||
```
|
||||
|
||||
Look at [test-listen](https://github.com/zeit/test-listen) for a
|
||||
function that returns a URL with an ephemeral port every time it's called.
|
||||
|
||||
## Contributing
|
||||
|
||||
1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device
|
||||
2. Link the package to the global module directory: `npm link`
|
||||
3. Within the module you want to test your local development instance of Micro, just link it to the dependencies: `npm link micro`. Instead of the default one from npm, node will now use your clone of Micro!
|
||||
|
||||
As always, you can run the [AVA](https://github.com/sindresorhus/ava) and [ESLint](http://eslint.org) tests using: `npm test`
|
||||
|
||||
## Credits
|
||||
|
||||
Thanks to Tom Yandell and Richard Hodgson for donating the name "micro" on [npm](https://www.npmjs.com)!
|
||||
|
||||
## Authors
|
||||
|
||||
- Guillermo Rauch ([@rauchg](https://twitter.com/rauchg)) - [ZEIT](https://zeit.co)
|
||||
- Leo Lamprecht ([@notquiteleo](https://twitter.com/notquiteleo)) - [ZEIT](https://zeit.co)
|
||||
- Tim Neutkens ([@timneutkens](https://twitter.com/timneutkens)) - [ZEIT](https://zeit.co)
|
||||
232
node_modules/micro/bin/micro.js
generated
vendored
Executable file
232
node_modules/micro/bin/micro.js
generated
vendored
Executable file
|
|
@ -0,0 +1,232 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
// Native
|
||||
const http = require('http');
|
||||
const path = require('path');
|
||||
const {existsSync} = require('fs');
|
||||
|
||||
// Packages
|
||||
const arg = require('arg');
|
||||
|
||||
// Utilities
|
||||
const serve = require('../lib');
|
||||
const handle = require('../lib/handler');
|
||||
const {version} = require('../package');
|
||||
const logError = require('../lib/error');
|
||||
const parseEndpoint = require('../lib/parse-endpoint.js');
|
||||
|
||||
// Check if the user defined any options
|
||||
const args = arg({
|
||||
'--listen': [parseEndpoint],
|
||||
'-l': '--listen',
|
||||
|
||||
'--help': Boolean,
|
||||
|
||||
'--version': Boolean,
|
||||
'-v': '--version',
|
||||
|
||||
// Deprecated options
|
||||
'--port': Number,
|
||||
'-p': '--port',
|
||||
'--host': String,
|
||||
'-h': '--host',
|
||||
'--unix-socket': String,
|
||||
'-s': '--unix-socket'
|
||||
});
|
||||
|
||||
// When `-h` or `--help` are used, print out
|
||||
// the usage information
|
||||
if (args['--help']) {
|
||||
console.error(`
|
||||
micro - Asynchronous HTTP microservices
|
||||
|
||||
USAGE
|
||||
|
||||
$ micro --help
|
||||
$ micro --version
|
||||
$ micro [-l listen_uri [-l ...]] [entry_point.js]
|
||||
|
||||
By default micro will listen on 0.0.0.0:3000 and will look first
|
||||
for the "main" property in package.json and subsequently for index.js
|
||||
as the default entry_point.
|
||||
|
||||
Specifying a single --listen argument will overwrite the default, not supplement it.
|
||||
|
||||
OPTIONS
|
||||
|
||||
--help shows this help message
|
||||
|
||||
-v, --version displays the current version of micro
|
||||
|
||||
-l, --listen listen_uri specify a URI endpoint on which to listen (see below) -
|
||||
more than one may be specified to listen in multiple places
|
||||
|
||||
ENDPOINTS
|
||||
|
||||
Listen endpoints (specified by the --listen or -l options above) instruct micro
|
||||
to listen on one or more interfaces/ports, UNIX domain sockets, or Windows named pipes.
|
||||
|
||||
For TCP (traditional host/port) endpoints:
|
||||
|
||||
$ micro -l tcp://hostname:1234
|
||||
|
||||
For UNIX domain socket endpoints:
|
||||
|
||||
$ micro -l unix:/path/to/socket.sock
|
||||
|
||||
For Windows named pipe endpoints:
|
||||
|
||||
$ micro -l pipe:\\\\.\\pipe\\PipeName
|
||||
`);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
// Print out the package's version when
|
||||
// `--version` or `-v` are used
|
||||
if (args['--version']) {
|
||||
console.log(version);
|
||||
process.exit();
|
||||
}
|
||||
|
||||
if ((args['--port'] || args['--host']) && args['--unix-socket']) {
|
||||
logError(
|
||||
`Both host/port and socket provided. You can only use one.`,
|
||||
'invalid-port-socket'
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let deprecatedEndpoint = null;
|
||||
|
||||
args['--listen'] = args['--listen'] || [];
|
||||
|
||||
if (args['--port']) {
|
||||
const {isNaN} = Number;
|
||||
const port = Number(args['--port']);
|
||||
if (isNaN(port) || (!isNaN(port) && (port < 1 || port >= Math.pow(2, 16)))) {
|
||||
logError(
|
||||
`Port option must be a number. Supplied: ${args['--port']}`,
|
||||
'invalid-server-port'
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
deprecatedEndpoint = [args['--port']];
|
||||
}
|
||||
|
||||
if (args['--host']) {
|
||||
deprecatedEndpoint = deprecatedEndpoint || [];
|
||||
deprecatedEndpoint.push(args['--host']);
|
||||
}
|
||||
|
||||
if (deprecatedEndpoint) {
|
||||
args['--listen'].push(deprecatedEndpoint);
|
||||
}
|
||||
|
||||
if (args['--unix-socket']) {
|
||||
if (typeof args['--unix-socket'] === 'boolean') {
|
||||
logError(
|
||||
`Socket must be a string. A boolean was provided.`,
|
||||
'invalid-socket'
|
||||
);
|
||||
}
|
||||
args['--listen'].push(args['--unix-socket']);
|
||||
}
|
||||
|
||||
if (args['--port'] || args['--host'] || args['--unix-socket']) {
|
||||
logError(
|
||||
'--port, --host, and --unix-socket are deprecated - see --help for information on the --listen flag',
|
||||
'deprecated-endpoint-flags'
|
||||
);
|
||||
}
|
||||
|
||||
if (args['--listen'].length === 0) {
|
||||
// default endpoint
|
||||
args['--listen'].push([3000]);
|
||||
}
|
||||
|
||||
let file = args._[0];
|
||||
|
||||
if (!file) {
|
||||
try {
|
||||
const packageJson = require(path.resolve(process.cwd(), 'package.json'));
|
||||
file = packageJson.main || 'index.js';
|
||||
} catch (err) {
|
||||
if (err.code !== 'MODULE_NOT_FOUND') {
|
||||
logError(
|
||||
`Could not read \`package.json\`: ${err.message}`,
|
||||
'invalid-package-json'
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
logError('Please supply a file!', 'path-missing');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (file[0] !== '/') {
|
||||
file = path.resolve(process.cwd(), file);
|
||||
}
|
||||
|
||||
if (!existsSync(file)) {
|
||||
logError(
|
||||
`The file or directory "${path.basename(file)}" doesn't exist!`,
|
||||
'path-not-existent'
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function registerShutdown(fn) {
|
||||
let run = false;
|
||||
|
||||
const wrapper = () => {
|
||||
if (!run) {
|
||||
run = true;
|
||||
fn();
|
||||
}
|
||||
};
|
||||
|
||||
process.on('SIGINT', wrapper);
|
||||
process.on('SIGTERM', wrapper);
|
||||
process.on('exit', wrapper);
|
||||
}
|
||||
|
||||
function startEndpoint(module, endpoint) {
|
||||
const server = new http.Server(serve(module));
|
||||
|
||||
server.on('error', err => {
|
||||
console.error('micro:', err.stack);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
server.listen(...endpoint, () => {
|
||||
const details = server.address();
|
||||
|
||||
registerShutdown(() => server.close());
|
||||
|
||||
// `micro` is designed to run only in production, so
|
||||
// this message is perfectly for prod
|
||||
if (typeof details === 'string') {
|
||||
console.log(`micro: Accepting connections on ${details}`);
|
||||
} else if (typeof details === 'object' && details.port) {
|
||||
console.log(`micro: Accepting connections on port ${details.port}`);
|
||||
} else {
|
||||
console.log('micro: Accepting connections');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function start() {
|
||||
const loadedModule = await handle(file);
|
||||
|
||||
for (const endpoint of args['--listen']) {
|
||||
startEndpoint(loadedModule, endpoint);
|
||||
}
|
||||
|
||||
registerShutdown(() => console.log('micro: Gracefully shutting down. Please wait...'));
|
||||
}
|
||||
|
||||
start();
|
||||
4
node_modules/micro/lib/error.js
generated
vendored
Normal file
4
node_modules/micro/lib/error.js
generated
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = (message, errorCode) => {
|
||||
console.error(`micro: ${message}`);
|
||||
console.error(`micro: https://err.sh/micro/${errorCode}`);
|
||||
};
|
||||
24
node_modules/micro/lib/handler.js
generated
vendored
Normal file
24
node_modules/micro/lib/handler.js
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Utilities
|
||||
const logError = require('./error');
|
||||
|
||||
module.exports = async file => {
|
||||
let mod;
|
||||
|
||||
try {
|
||||
mod = await require(file); // Await to support exporting Promises
|
||||
|
||||
if (mod && typeof mod === 'object') {
|
||||
mod = await mod.default; // Await to support es6 module's default export
|
||||
}
|
||||
} catch (err) {
|
||||
logError(`Error when importing ${file}: ${err.stack}`, 'invalid-entry');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (typeof mod !== 'function') {
|
||||
logError(`The file "${file}" does not export a function.`, 'no-export');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return mod;
|
||||
};
|
||||
170
node_modules/micro/lib/index.js
generated
vendored
Normal file
170
node_modules/micro/lib/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
// Native
|
||||
const {Stream} = require('stream');
|
||||
|
||||
// Packages
|
||||
const contentType = require('content-type');
|
||||
const getRawBody = require('raw-body');
|
||||
|
||||
// based on is-stream https://github.com/sindresorhus/is-stream/blob/c918e3795ea2451b5265f331a00fb6a8aaa27816/license
|
||||
function isStream(stream) {
|
||||
return stream !== null &&
|
||||
typeof stream === 'object' &&
|
||||
typeof stream.pipe === 'function';
|
||||
}
|
||||
|
||||
function readable(stream) {
|
||||
return isStream(stream) &&
|
||||
stream.readable !== false &&
|
||||
typeof stream._read === 'function' &&
|
||||
typeof stream._readableState === 'object';
|
||||
}
|
||||
|
||||
const {NODE_ENV} = process.env;
|
||||
const DEV = NODE_ENV === 'development';
|
||||
|
||||
const serve = fn => (req, res) => exports.run(req, res, fn);
|
||||
|
||||
module.exports = serve;
|
||||
exports = serve;
|
||||
exports.default = serve;
|
||||
|
||||
const createError = (code, message, original) => {
|
||||
const err = new Error(message);
|
||||
|
||||
err.statusCode = code;
|
||||
err.originalError = original;
|
||||
|
||||
return err;
|
||||
};
|
||||
|
||||
const send = (res, code, obj = null) => {
|
||||
res.statusCode = code;
|
||||
|
||||
if (obj === null) {
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(obj)) {
|
||||
if (!res.getHeader('Content-Type')) {
|
||||
res.setHeader('Content-Type', 'application/octet-stream');
|
||||
}
|
||||
|
||||
res.setHeader('Content-Length', obj.length);
|
||||
res.end(obj);
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj instanceof Stream || readable(obj)) {
|
||||
if (!res.getHeader('Content-Type')) {
|
||||
res.setHeader('Content-Type', 'application/octet-stream');
|
||||
}
|
||||
|
||||
obj.pipe(res);
|
||||
return;
|
||||
}
|
||||
|
||||
let str = obj;
|
||||
|
||||
if (typeof obj === 'object' || typeof obj === 'number') {
|
||||
// We stringify before setting the header
|
||||
// in case `JSON.stringify` throws and a
|
||||
// 500 has to be sent instead
|
||||
|
||||
// the `JSON.stringify` call is split into
|
||||
// two cases as `JSON.stringify` is optimized
|
||||
// in V8 if called with only one argument
|
||||
if (DEV) {
|
||||
str = JSON.stringify(obj, null, 2);
|
||||
} else {
|
||||
str = JSON.stringify(obj);
|
||||
}
|
||||
|
||||
if (!res.getHeader('Content-Type')) {
|
||||
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
||||
}
|
||||
}
|
||||
|
||||
res.setHeader('Content-Length', Buffer.byteLength(str));
|
||||
res.end(str);
|
||||
};
|
||||
|
||||
const sendError = (req, res, errorObj) => {
|
||||
const statusCode = errorObj.statusCode || errorObj.status;
|
||||
const message = statusCode ? errorObj.message : 'Internal Server Error';
|
||||
send(res, statusCode || 500, DEV ? errorObj.stack : message);
|
||||
if (errorObj instanceof Error) {
|
||||
console.error(errorObj.stack);
|
||||
} else {
|
||||
console.warn('thrown error must be an instance Error');
|
||||
}
|
||||
};
|
||||
|
||||
exports.send = send;
|
||||
exports.sendError = sendError;
|
||||
exports.createError = createError;
|
||||
|
||||
exports.run = (req, res, fn) =>
|
||||
new Promise(resolve => resolve(fn(req, res)))
|
||||
.then(val => {
|
||||
if (val === null) {
|
||||
send(res, 204, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send value if it is not undefined, otherwise assume res.end
|
||||
// will be called later
|
||||
// eslint-disable-next-line no-undefined
|
||||
if (val !== undefined) {
|
||||
send(res, res.statusCode || 200, val);
|
||||
}
|
||||
})
|
||||
.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 parseJSON = str => {
|
||||
try {
|
||||
return JSON.parse(str);
|
||||
} catch (err) {
|
||||
throw createError(400, 'Invalid JSON', err);
|
||||
}
|
||||
};
|
||||
|
||||
exports.buffer = (req, {limit = '1mb', encoding} = {}) =>
|
||||
Promise.resolve().then(() => {
|
||||
const type = req.headers['content-type'] || 'text/plain';
|
||||
const length = req.headers['content-length'];
|
||||
|
||||
// eslint-disable-next-line no-undefined
|
||||
if (encoding === undefined) {
|
||||
encoding = contentType.parse(type).parameters.charset;
|
||||
}
|
||||
|
||||
const body = rawBodyMap.get(req);
|
||||
|
||||
if (body) {
|
||||
return body;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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));
|
||||
26
node_modules/micro/lib/parse-endpoint.js
generated
vendored
Normal file
26
node_modules/micro/lib/parse-endpoint.js
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
const {URL} = require('url');
|
||||
|
||||
module.exports = function parseEndpoint(str) {
|
||||
const url = new URL(str);
|
||||
|
||||
switch (url.protocol) {
|
||||
case 'pipe:': {
|
||||
// some special handling
|
||||
const cutStr = str.replace(/^pipe:/, '');
|
||||
if (cutStr.slice(0, 4) !== '\\\\.\\') {
|
||||
throw new Error(`Invalid Windows named pipe endpoint: ${str}`);
|
||||
}
|
||||
return [cutStr];
|
||||
}
|
||||
case 'unix:':
|
||||
if (!url.pathname) {
|
||||
throw new Error(`Invalid UNIX domain socket endpoint: ${str}`);
|
||||
}
|
||||
return [url.pathname];
|
||||
case 'tcp:':
|
||||
url.port = url.port || '3000';
|
||||
return [parseInt(url.port, 10), url.hostname];
|
||||
default:
|
||||
throw new Error(`Unknown --listen endpoint scheme (protocol): ${url.protocol}`);
|
||||
}
|
||||
};
|
||||
15
node_modules/micro/micro.d.ts
generated
vendored
Normal file
15
node_modules/micro/micro.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/// <reference types="node" />
|
||||
|
||||
import { RequestListener, IncomingMessage, ServerResponse } from 'http'
|
||||
|
||||
export type RequestHandler = (req: IncomingMessage, res: ServerResponse) => any
|
||||
declare function serve(fn: RequestHandler): RequestListener
|
||||
|
||||
export function run(req: IncomingMessage, res: ServerResponse, fn: RequestHandler): Promise<void>
|
||||
export function json(req: IncomingMessage, info?: { limit?: string | number, encoding?: string }): Promise<any>
|
||||
export function text(req: IncomingMessage, info?: { limit?: string | number, encoding?: string }): Promise<string>
|
||||
export function buffer(req: IncomingMessage, info?: { limit?: string | number, encoding?: string }): Promise<Buffer | string>
|
||||
export function send(res: ServerResponse, code: number, data?: any): Promise<void>
|
||||
export function createError(code: number, msg: string, orig?: Error): Error & { statusCode: number, originalError?: Error }
|
||||
export function sendError(req: IncomingMessage, res: ServerResponse, info: { statusCode?: number, status?: number, message?: string, stack?: string }): Promise<void>
|
||||
export default serve
|
||||
33
node_modules/micro/package.json
generated
vendored
Normal file
33
node_modules/micro/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "micro",
|
||||
"version": "9.3.5-canary.3",
|
||||
"description": "Asynchronous HTTP microservices",
|
||||
"license": "MIT",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./micro.d.ts",
|
||||
"files": [
|
||||
"bin",
|
||||
"lib",
|
||||
"micro.d.ts"
|
||||
],
|
||||
"bin": {
|
||||
"micro": "./bin/micro.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
},
|
||||
"repository": "zeit/micro",
|
||||
"keywords": [
|
||||
"micro",
|
||||
"service",
|
||||
"microservice",
|
||||
"serverless",
|
||||
"API"
|
||||
],
|
||||
"dependencies": {
|
||||
"arg": "4.1.0",
|
||||
"content-type": "1.0.4",
|
||||
"raw-body": "2.4.1"
|
||||
},
|
||||
"gitHead": "5d4b6748fa6e005579423a1d12cc838340117bc4"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue