Socket
Socket
Sign inDemoInstall

koa

Package Overview
Dependencies
Maintainers
11
Versions
104
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

koa - npm Package Compare versions

Comparing version 2.14.1 to 3.0.0-alpha.0

274

lib/application.js
'use strict';
'use strict'

@@ -8,20 +8,31 @@ /**

const isGeneratorFunction = require('is-generator-function');
const debug = require('debug')('koa:application');
const onFinished = require('on-finished');
const assert = require('assert');
const response = require('./response');
const compose = require('koa-compose');
const context = require('./context');
const request = require('./request');
const statuses = require('statuses');
const Emitter = require('events');
const util = require('util');
const Stream = require('stream');
const http = require('http');
const only = require('only');
const convert = require('koa-convert');
const deprecate = require('depd')('koa');
const { HttpError } = require('http-errors');
const debug = require('debug')('koa:application')
const assert = require('assert')
const onFinished = require('on-finished')
const response = require('./response')
const compose = require('koa-compose')
const context = require('./context')
const request = require('./request')
const statuses = require('statuses')
const Emitter = require('events')
const util = require('util')
const Stream = require('stream')
const http = require('http')
const only = require('only')
const { HttpError } = require('http-errors')
/** @typedef {typeof import ('./context') & {
* app: Application
* req: import('http').IncomingMessage
* res: import('http').ServerResponse
* request: KoaRequest
* response: KoaResponse
* state: any
* originalUrl: string
* }} Context */
/** @typedef {typeof import('./request')} KoaRequest */
/** @typedef {typeof import('./response')} KoaResponse */
/**

@@ -51,25 +62,26 @@ * Expose `Application` class.

constructor(options) {
super();
options = options || {};
this.proxy = options.proxy || false;
this.subdomainOffset = options.subdomainOffset || 2;
this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For';
this.maxIpsCount = options.maxIpsCount || 0;
this.env = options.env || process.env.NODE_ENV || 'development';
if (options.keys) this.keys = options.keys;
this.middleware = [];
this.context = Object.create(context);
this.request = Object.create(request);
this.response = Object.create(response);
constructor (options) {
super()
options = options || {}
this.proxy = options.proxy || false
this.subdomainOffset = options.subdomainOffset || 2
this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For'
this.maxIpsCount = options.maxIpsCount || 0
this.env = options.env || process.env.NODE_ENV || 'development'
this.compose = options.compose || compose
if (options.keys) this.keys = options.keys
this.middleware = []
this.context = Object.create(context)
this.request = Object.create(request)
this.response = Object.create(response)
// util.inspect.custom support for node 6+
/* istanbul ignore else */
if (util.inspect.custom) {
this[util.inspect.custom] = this.inspect;
this[util.inspect.custom] = this.inspect
}
if (options.asyncLocalStorage) {
const { AsyncLocalStorage } = require('async_hooks');
assert(AsyncLocalStorage, 'Requires node 12.17.0 or higher to enable asyncLocalStorage');
this.ctxStorage = new AsyncLocalStorage();
this.use(this.createAsyncCtxStorageMiddleware());
const { AsyncLocalStorage } = require('async_hooks')
assert(AsyncLocalStorage, 'Requires node 12.17.0 or higher to enable asyncLocalStorage')
this.ctxStorage = new AsyncLocalStorage()
this.use(this.createAsyncCtxStorageMiddleware())
}

@@ -84,10 +96,10 @@ }

* @param {Mixed} ...
* @return {Server}
* @return {import('http').Server}
* @api public
*/
listen(...args) {
debug('listen');
const server = http.createServer(this.callback());
return server.listen(...args);
listen (...args) {
debug('listen')
const server = http.createServer(this.callback())
return server.listen(...args)
}

@@ -103,3 +115,3 @@

toJSON() {
toJSON () {
return only(this, [

@@ -109,3 +121,3 @@ 'subdomainOffset',

'env'
]);
])
}

@@ -120,4 +132,4 @@

inspect() {
return this.toJSON();
inspect () {
return this.toJSON()
}

@@ -130,3 +142,3 @@

*
* @param {Function} fn
* @param {(context: Context) => Promise<any | void>} fn
* @return {Application} self

@@ -136,13 +148,7 @@ * @api public

use(fn) {
if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');
if (isGeneratorFunction(fn)) {
deprecate('Support for generators will be removed in v3. ' +
'See the documentation for examples of how to convert old middleware ' +
'https://github.com/koajs/koa/blob/master/docs/migration.md');
fn = convert(fn);
}
debug('use %s', fn._name || fn.name || '-');
this.middleware.push(fn);
return this;
use (fn) {
if (typeof fn !== 'function') throw new TypeError('middleware must be a function!')
debug('use %s', fn._name || fn.name || '-')
this.middleware.push(fn)
return this
}

@@ -158,20 +164,20 @@

callback() {
const fn = compose(this.middleware);
callback () {
const fn = this.compose(this.middleware)
if (!this.listenerCount('error')) this.on('error', this.onerror);
if (!this.listenerCount('error')) this.on('error', this.onerror)
const handleRequest = (req, res) => {
const ctx = this.createContext(req, res);
return this.handleRequest(ctx, fn);
};
const ctx = this.createContext(req, res)
return this.handleRequest(ctx, fn)
}
return handleRequest;
return handleRequest
}
/**
* return currnect contenxt from async local storage
* return current context from async local storage
*/
get currentContext() {
if (this.ctxStorage) return this.ctxStorage.getStore();
get currentContext () {
if (this.ctxStorage) return this.ctxStorage.getStore()
}

@@ -185,9 +191,9 @@

handleRequest(ctx, fnMiddleware) {
const res = ctx.res;
res.statusCode = 404;
const onerror = err => ctx.onerror(err);
const handleResponse = () => respond(ctx);
onFinished(res, onerror);
return fnMiddleware(ctx).then(handleResponse).catch(onerror);
handleRequest (ctx, fnMiddleware) {
const res = ctx.res
res.statusCode = 404
const onerror = err => ctx.onerror(err)
const handleResponse = () => respond(ctx)
onFinished(res, onerror)
return fnMiddleware(ctx).then(handleResponse).catch(onerror)
}

@@ -201,15 +207,18 @@

createContext(req, res) {
const context = Object.create(this.context);
const request = context.request = Object.create(this.request);
const response = context.response = Object.create(this.response);
context.app = request.app = response.app = this;
context.req = request.req = response.req = req;
context.res = request.res = response.res = res;
request.ctx = response.ctx = context;
request.response = response;
response.request = request;
context.originalUrl = request.originalUrl = req.url;
context.state = {};
return context;
createContext (req, res) {
/** @type {Context} */
const context = Object.create(this.context)
/** @type {KoaRequest} */
const request = context.request = Object.create(this.request)
/** @type {KoaResponse} */
const response = context.response = Object.create(this.response)
context.app = request.app = response.app = this
context.req = request.req = response.req = req
context.res = request.res = response.res = res
request.ctx = response.ctx = context
request.response = response
response.request = request
context.originalUrl = request.originalUrl = req.url
context.state = {}
return context
}

@@ -224,3 +233,3 @@

onerror(err) {
onerror (err) {
// When dealing with cross-globals a normal `instanceof` check doesn't work properly.

@@ -231,10 +240,10 @@ // See https://github.com/koajs/koa/issues/1466

Object.prototype.toString.call(err) === '[object Error]' ||
err instanceof Error;
if (!isNativeError) throw new TypeError(util.format('non-error thrown: %j', err));
err instanceof Error
if (!isNativeError) throw new TypeError(util.format('non-error thrown: %j', err))
if (404 === err.status || err.expose) return;
if (this.silent) return;
if (err.status === 404 || err.expose) return
if (this.silent) return
const msg = err.stack || err.toString();
console.error(`\n${msg.replace(/^/gm, ' ')}\n`);
const msg = err.stack || err.toString()
console.error(`\n${msg.replace(/^/gm, ' ')}\n`)
}

@@ -247,15 +256,15 @@

static get default() {
return Application;
static get default () {
return Application
}
createAsyncCtxStorageMiddleware() {
const app = this;
return async function asyncCtxStorage(ctx, next) {
await app.ctxStorage.run(ctx, async() => {
return await next();
});
};
createAsyncCtxStorageMiddleware () {
const app = this
return async function asyncCtxStorage (ctx, next) {
await app.ctxStorage.run(ctx, async () => {
return await next()
})
}
}
};
}

@@ -266,11 +275,11 @@ /**

function respond(ctx) {
function respond (ctx) {
// allow bypassing koa
if (false === ctx.respond) return;
if (ctx.respond === false) return
if (!ctx.writable) return;
if (!ctx.writable) return
const res = ctx.res;
let body = ctx.body;
const code = ctx.status;
const res = ctx.res
let body = ctx.body
const code = ctx.status

@@ -280,44 +289,45 @@ // ignore body

// strip headers
ctx.body = null;
return res.end();
ctx.body = null
return res.end()
}
if ('HEAD' === ctx.method) {
if (ctx.method === 'HEAD') {
if (!res.headersSent && !ctx.response.has('Content-Length')) {
const { length } = ctx.response;
if (Number.isInteger(length)) ctx.length = length;
const { length } = ctx.response
if (Number.isInteger(length)) ctx.length = length
}
return res.end();
return res.end()
}
// status body
if (null == body) {
if (body == null) {
if (ctx.response._explicitNullBody) {
ctx.response.remove('Content-Type');
ctx.response.remove('Transfer-Encoding');
return res.end();
ctx.response.remove('Content-Type')
ctx.response.remove('Transfer-Encoding')
ctx.length = 0
return res.end()
}
if (ctx.req.httpVersionMajor >= 2) {
body = String(code);
body = String(code)
} else {
body = ctx.message || String(code);
body = ctx.message || String(code)
}
if (!res.headersSent) {
ctx.type = 'text';
ctx.length = Buffer.byteLength(body);
ctx.type = 'text'
ctx.length = Buffer.byteLength(body)
}
return res.end(body);
return res.end(body)
}
// responses
if (Buffer.isBuffer(body)) return res.end(body);
if ('string' === typeof body) return res.end(body);
if (body instanceof Stream) return body.pipe(res);
if (Buffer.isBuffer(body)) return res.end(body)
if (typeof body === 'string') return res.end(body)
if (body instanceof Stream) return body.pipe(res)
// body: json
body = JSON.stringify(body);
body = JSON.stringify(body)
if (!res.headersSent) {
ctx.length = Buffer.byteLength(body);
ctx.length = Buffer.byteLength(body)
}
res.end(body);
res.end(body)
}

@@ -330,2 +340,2 @@

module.exports.HttpError = HttpError;
module.exports.HttpError = HttpError
'use strict';
'use strict'

@@ -8,10 +8,10 @@ /**

const util = require('util');
const createError = require('http-errors');
const httpAssert = require('http-assert');
const delegate = require('delegates');
const statuses = require('statuses');
const Cookies = require('cookies');
const util = require('util')
const createError = require('http-errors')
const httpAssert = require('http-assert')
const delegate = require('delegates')
const statuses = require('statuses')
const Cookies = require('cookies')
const COOKIES = Symbol('context#cookies');
const COOKIES = Symbol('context#cookies')

@@ -32,5 +32,5 @@ /**

inspect() {
if (this === proto) return this;
return this.toJSON();
inspect () {
if (this === proto) return this
return this.toJSON()
},

@@ -50,3 +50,3 @@

toJSON() {
toJSON () {
return {

@@ -60,3 +60,3 @@ request: this.request.toJSON(),

socket: '<original node socket>'
};
}
},

@@ -100,4 +100,4 @@

throw(...args) {
throw createError(...args);
throw (...args) {
throw createError(...args)
},

@@ -112,7 +112,7 @@

onerror(err) {
onerror (err) {
// don't do anything if there is no error.
// this allows you to pass `this.onerror`
// to node-style callbacks.
if (null == err) return;
if (err == null) return

@@ -124,12 +124,12 @@ // When dealing with cross-globals a normal `instanceof` check doesn't work properly.

Object.prototype.toString.call(err) === '[object Error]' ||
err instanceof Error;
if (!isNativeError) err = new Error(util.format('non-error thrown: %j', err));
err instanceof Error
if (!isNativeError) err = new Error(util.format('non-error thrown: %j', err))
let headerSent = false;
let headerSent = false
if (this.headerSent || !this.writable) {
headerSent = err.headerSent = true;
headerSent = err.headerSent = true
}
// delegate
this.app.emit('error', err, this);
this.app.emit('error', err, this)

@@ -140,6 +140,6 @@ // nothing we can do here other

if (headerSent) {
return;
return
}
const { res } = this;
const { res } = this

@@ -149,30 +149,30 @@ // first unset all headers

if (typeof res.getHeaderNames === 'function') {
res.getHeaderNames().forEach(name => res.removeHeader(name));
res.getHeaderNames().forEach(name => res.removeHeader(name))
} else {
res._headers = {}; // Node < 7.7
res._headers = {} // Node < 7.7
}
// then set those specified
this.set(err.headers);
this.set(err.headers)
// force text/plain
this.type = 'text';
this.type = 'text'
let statusCode = err.status || err.statusCode;
let statusCode = err.status || err.statusCode
// ENOENT support
if ('ENOENT' === err.code) statusCode = 404;
if (err.code === 'ENOENT') statusCode = 404
// default to 500
if ('number' !== typeof statusCode || !statuses[statusCode]) statusCode = 500;
if (typeof statusCode !== 'number' || !statuses[statusCode]) statusCode = 500
// respond
const code = statuses[statusCode];
const msg = err.expose ? err.message : code;
this.status = err.status = statusCode;
this.length = Buffer.byteLength(msg);
res.end(msg);
const code = statuses[statusCode]
const msg = err.expose ? err.message : code
this.status = err.status = statusCode
this.length = Buffer.byteLength(msg)
res.end(msg)
},
get cookies() {
get cookies () {
if (!this[COOKIES]) {

@@ -182,11 +182,11 @@ this[COOKIES] = new Cookies(this.req, this.res, {

secure: this.request.secure
});
})
}
return this[COOKIES];
return this[COOKIES]
},
set cookies(_cookies) {
this[COOKIES] = _cookies;
set cookies (_cookies) {
this[COOKIES] = _cookies
}
};
}

@@ -202,3 +202,3 @@ /**

if (util.inspect.custom) {
module.exports[util.inspect.custom] = module.exports.inspect;
module.exports[util.inspect.custom] = module.exports.inspect
}

@@ -227,3 +227,3 @@

.getter('headerSent')
.getter('writable');
.getter('writable')

@@ -263,2 +263,2 @@ /**

.getter('ips')
.getter('ip');
.getter('ip')
'use strict';
'use strict'

@@ -8,15 +8,15 @@ /**

const URL = require('url').URL;
const net = require('net');
const accepts = require('accepts');
const contentType = require('content-type');
const stringify = require('url').format;
const parse = require('parseurl');
const qs = require('querystring');
const typeis = require('type-is');
const fresh = require('fresh');
const only = require('only');
const util = require('util');
const URL = require('url').URL
const net = require('net')
const accepts = require('accepts')
const contentType = require('content-type')
const stringify = require('url').format
const parse = require('parseurl')
const qs = require('querystring')
const typeis = require('type-is')
const fresh = require('fresh')
const only = require('only')
const util = require('util')
const IP = Symbol('context#ip');
const IP = Symbol('context#ip')

@@ -36,4 +36,4 @@ /**

get header() {
return this.req.headers;
get header () {
return this.req.headers
},

@@ -47,4 +47,4 @@

set header(val) {
this.req.headers = val;
set header (val) {
this.req.headers = val
},

@@ -59,4 +59,4 @@

get headers() {
return this.req.headers;
get headers () {
return this.req.headers
},

@@ -70,4 +70,4 @@

set headers(val) {
this.req.headers = val;
set headers (val) {
this.req.headers = val
},

@@ -82,4 +82,4 @@

get url() {
return this.req.url;
get url () {
return this.req.url
},

@@ -93,4 +93,4 @@

set url(val) {
this.req.url = val;
set url (val) {
this.req.url = val
},

@@ -105,4 +105,4 @@

get origin() {
return `${this.protocol}://${this.host}`;
get origin () {
return `${this.protocol}://${this.host}`
},

@@ -117,6 +117,6 @@

get href() {
get href () {
// support: `GET http://example.com/foo`
if (/^https?:\/\//i.test(this.originalUrl)) return this.originalUrl;
return this.origin + this.originalUrl;
if (/^https?:\/\//i.test(this.originalUrl)) return this.originalUrl
return this.origin + this.originalUrl
},

@@ -131,4 +131,4 @@

get method() {
return this.req.method;
get method () {
return this.req.method
},

@@ -143,4 +143,4 @@

set method(val) {
this.req.method = val;
set method (val) {
this.req.method = val
},

@@ -155,4 +155,4 @@

get path() {
return parse(this.req).pathname;
get path () {
return parse(this.req).pathname
},

@@ -167,10 +167,10 @@

set path(path) {
const url = parse(this.req);
if (url.pathname === path) return;
set path (path) {
const url = parse(this.req)
if (url.pathname === path) return
url.pathname = path;
url.path = null;
url.pathname = path
url.path = null
this.url = stringify(url);
this.url = stringify(url)
},

@@ -185,6 +185,6 @@

get query() {
const str = this.querystring;
const c = this._querycache = this._querycache || {};
return c[str] || (c[str] = qs.parse(str));
get query () {
const str = this.querystring
const c = this._querycache = this._querycache || {}
return c[str] || (c[str] = qs.parse(str))
},

@@ -199,4 +199,4 @@

set query(obj) {
this.querystring = qs.stringify(obj);
set query (obj) {
this.querystring = qs.stringify(obj)
},

@@ -211,5 +211,5 @@

get querystring() {
if (!this.req) return '';
return parse(this.req).query || '';
get querystring () {
if (!this.req) return ''
return parse(this.req).query || ''
},

@@ -224,10 +224,10 @@

set querystring(str) {
const url = parse(this.req);
if (url.search === `?${str}`) return;
set querystring (str) {
const url = parse(this.req)
if (url.search === `?${str}`) return
url.search = str;
url.path = null;
url.search = str
url.path = null
this.url = stringify(url);
this.url = stringify(url)
},

@@ -243,5 +243,5 @@

get search() {
if (!this.querystring) return '';
return `?${this.querystring}`;
get search () {
if (!this.querystring) return ''
return `?${this.querystring}`
},

@@ -257,4 +257,4 @@

set search(str) {
this.querystring = str;
set search (str) {
this.querystring = str
},

@@ -271,11 +271,11 @@

get host() {
const proxy = this.app.proxy;
let host = proxy && this.get('X-Forwarded-Host');
get host () {
const proxy = this.app.proxy
let host = proxy && this.get('X-Forwarded-Host')
if (!host) {
if (this.req.httpVersionMajor >= 2) host = this.get(':authority');
if (!host) host = this.get('Host');
if (this.req.httpVersionMajor >= 2) host = this.get(':authority')
if (!host) host = this.get('Host')
}
if (!host) return '';
return host.split(/\s*,\s*/, 1)[0];
if (!host) return ''
return host.split(/\s*,\s*/, 1)[0]
},

@@ -292,7 +292,7 @@

get hostname() {
const host = this.host;
if (!host) return '';
if ('[' === host[0]) return this.URL.hostname || ''; // IPv6
return host.split(':', 1)[0];
get hostname () {
const host = this.host
if (!host) return ''
if (host[0] === '[') return this.URL.hostname || '' // IPv6
return host.split(':', 1)[0]
},

@@ -308,13 +308,13 @@

get URL() {
get URL () {
/* istanbul ignore else */
if (!this.memoizedURL) {
const originalUrl = this.originalUrl || ''; // avoid undefined in template string
const originalUrl = this.originalUrl || '' // avoid undefined in template string
try {
this.memoizedURL = new URL(`${this.origin}${originalUrl}`);
this.memoizedURL = new URL(`${this.origin}${originalUrl}`)
} catch (err) {
this.memoizedURL = Object.create(null);
this.memoizedURL = Object.create(null)
}
}
return this.memoizedURL;
return this.memoizedURL
},

@@ -331,15 +331,15 @@

get fresh() {
const method = this.method;
const s = this.ctx.status;
get fresh () {
const method = this.method
const s = this.ctx.status
// GET or HEAD for weak freshness validation only
if ('GET' !== method && 'HEAD' !== method) return false;
if (method !== 'GET' && method !== 'HEAD') return false
// 2xx or 304 as per rfc2616 14.26
if ((s >= 200 && s < 300) || 304 === s) {
return fresh(this.header, this.response.header);
if ((s >= 200 && s < 300) || s === 304) {
return fresh(this.header, this.response.header)
}
return false;
return false
},

@@ -356,4 +356,4 @@

get stale() {
return !this.fresh;
get stale () {
return !this.fresh
},

@@ -368,5 +368,5 @@

get idempotent() {
const methods = ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'];
return !!~methods.indexOf(this.method);
get idempotent () {
const methods = ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']
return !!~methods.indexOf(this.method)
},

@@ -381,4 +381,4 @@

get socket() {
return this.req.socket;
get socket () {
return this.req.socket
},

@@ -393,8 +393,8 @@

get charset() {
get charset () {
try {
const { parameters } = contentType.parse(this.req);
return parameters.charset || '';
const { parameters } = contentType.parse(this.req)
return parameters.charset || ''
} catch (e) {
return '';
return ''
}

@@ -410,6 +410,6 @@ },

get length() {
const len = this.get('Content-Length');
if (len === '') return;
return ~~len;
get length () {
const len = this.get('Content-Length')
if (len === '') return
return ~~len
},

@@ -429,7 +429,7 @@

get protocol() {
if (this.socket.encrypted) return 'https';
if (!this.app.proxy) return 'http';
const proto = this.get('X-Forwarded-Proto');
return proto ? proto.split(/\s*,\s*/, 1)[0] : 'http';
get protocol () {
if (this.socket.encrypted) return 'https'
if (!this.app.proxy) return 'http'
const proto = this.get('X-Forwarded-Proto')
return proto ? proto.split(/\s*,\s*/, 1)[0] : 'http'
},

@@ -446,4 +446,4 @@

get secure() {
return 'https' === this.protocol;
get secure () {
return this.protocol === 'https'
},

@@ -463,12 +463,12 @@

get ips() {
const proxy = this.app.proxy;
const val = this.get(this.app.proxyIpHeader);
get ips () {
const proxy = this.app.proxy
const val = this.get(this.app.proxyIpHeader)
let ips = proxy && val
? val.split(/\s*,\s*/)
: [];
: []
if (this.app.maxIpsCount > 0) {
ips = ips.slice(-this.app.maxIpsCount);
ips = ips.slice(-this.app.maxIpsCount)
}
return ips;
return ips
},

@@ -485,11 +485,11 @@

get ip() {
get ip () {
if (!this[IP]) {
this[IP] = this.ips[0] || this.socket.remoteAddress || '';
this[IP] = this.ips[0] || this.socket.remoteAddress || ''
}
return this[IP];
return this[IP]
},
set ip(_ip) {
this[IP] = _ip;
set ip (_ip) {
this[IP] = _ip
},

@@ -513,10 +513,10 @@

get subdomains() {
const offset = this.app.subdomainOffset;
const hostname = this.hostname;
if (net.isIP(hostname)) return [];
get subdomains () {
const offset = this.app.subdomainOffset
const hostname = this.hostname
if (net.isIP(hostname)) return []
return hostname
.split('.')
.reverse()
.slice(offset);
.slice(offset)
},

@@ -532,4 +532,4 @@

get accept() {
return this._accept || (this._accept = accepts(this.req));
get accept () {
return this._accept || (this._accept = accepts(this.req))
},

@@ -544,4 +544,4 @@

set accept(obj) {
this._accept = obj;
set accept (obj) {
this._accept = obj
},

@@ -590,4 +590,4 @@

accepts(...args) {
return this.accept.types(...args);
accepts (...args) {
return this.accept.types(...args)
},

@@ -608,4 +608,4 @@

acceptsEncodings(...args) {
return this.accept.encodings(...args);
acceptsEncodings (...args) {
return this.accept.encodings(...args)
},

@@ -626,4 +626,4 @@

acceptsCharsets(...args) {
return this.accept.charsets(...args);
acceptsCharsets (...args) {
return this.accept.charsets(...args)
},

@@ -644,4 +644,4 @@

acceptsLanguages(...args) {
return this.accept.languages(...args);
acceptsLanguages (...args) {
return this.accept.languages(...args)
},

@@ -676,4 +676,4 @@

is(type, ...types) {
return typeis(this.req, type, ...types);
is (type, ...types) {
return typeis(this.req, type, ...types)
},

@@ -689,6 +689,6 @@

get type() {
const type = this.get('Content-Type');
if (!type) return '';
return type.split(';')[0];
get type () {
const type = this.get('Content-Type')
if (!type) return ''
return type.split(';')[0]
},

@@ -718,10 +718,10 @@

get(field) {
const req = this.req;
get (field) {
const req = this.req
switch (field = field.toLowerCase()) {
case 'referer':
case 'referrer':
return req.headers.referrer || req.headers.referer || '';
return req.headers.referrer || req.headers.referer || ''
default:
return req.headers[field] || '';
return req.headers[field] || ''
}

@@ -737,5 +737,5 @@ },

inspect() {
if (!this.req) return;
return this.toJSON();
inspect () {
if (!this.req) return
return this.toJSON()
},

@@ -750,3 +750,3 @@

toJSON() {
toJSON () {
return only(this, [

@@ -756,5 +756,5 @@ 'method',

'header'
]);
])
}
};
}

@@ -770,3 +770,3 @@ /**

if (util.inspect.custom) {
module.exports[util.inspect.custom] = module.exports.inspect;
module.exports[util.inspect.custom] = module.exports.inspect
}
'use strict';
'use strict'

@@ -8,16 +8,16 @@ /**

const contentDisposition = require('content-disposition');
const getType = require('cache-content-type');
const onFinish = require('on-finished');
const escape = require('escape-html');
const typeis = require('type-is').is;
const statuses = require('statuses');
const destroy = require('destroy');
const assert = require('assert');
const extname = require('path').extname;
const vary = require('vary');
const only = require('only');
const util = require('util');
const encodeUrl = require('encodeurl');
const Stream = require('stream');
const contentDisposition = require('content-disposition')
const getType = require('cache-content-type')
const onFinish = require('on-finished')
const escape = require('escape-html')
const typeis = require('type-is').is
const statuses = require('statuses')
const destroy = require('destroy')
const assert = require('assert')
const extname = require('path').extname
const vary = require('vary')
const only = require('only')
const util = require('util')
const encodeUrl = require('encodeurl')
const Stream = require('stream')

@@ -37,4 +37,4 @@ /**

get socket() {
return this.res.socket;
get socket () {
return this.res.socket
},

@@ -49,7 +49,7 @@

get header() {
const { res } = this;
get header () {
const { res } = this
return typeof res.getHeaders === 'function'
? res.getHeaders()
: res._headers || {}; // Node < 7.7
: res._headers || {} // Node < 7.7
},

@@ -64,4 +64,4 @@

get headers() {
return this.header;
get headers () {
return this.header
},

@@ -76,4 +76,4 @@

get status() {
return this.res.statusCode;
get status () {
return this.res.statusCode
},

@@ -88,11 +88,11 @@

set status(code) {
if (this.headerSent) return;
set status (code) {
if (this.headerSent) return
assert(Number.isInteger(code), 'status code must be a number');
assert(code >= 100 && code <= 999, `invalid status code: ${code}`);
this._explicitStatus = true;
this.res.statusCode = code;
if (this.req.httpVersionMajor < 2) this.res.statusMessage = statuses[code];
if (this.body && statuses.empty[code]) this.body = null;
assert(Number.isInteger(code), 'status code must be a number')
assert(code >= 100 && code <= 999, `invalid status code: ${code}`)
this._explicitStatus = true
this.res.statusCode = code
if (this.req.httpVersionMajor < 2) this.res.statusMessage = statuses[code]
if (this.body && statuses.empty[code]) this.body = null
},

@@ -107,4 +107,4 @@

get message() {
return this.res.statusMessage || statuses[this.status];
get message () {
return this.res.statusMessage || statuses[this.status]
},

@@ -119,4 +119,4 @@

set message(msg) {
this.res.statusMessage = msg;
set message (msg) {
this.res.statusMessage = msg
},

@@ -131,4 +131,4 @@

get body() {
return this._body;
get body () {
return this._body
},

@@ -143,27 +143,33 @@

set body(val) {
const original = this._body;
this._body = val;
set body (val) {
const original = this._body
this._body = val
// no content
if (null == val) {
if (!statuses.empty[this.status]) this.status = 204;
if (val === null) this._explicitNullBody = true;
this.remove('Content-Type');
this.remove('Content-Length');
this.remove('Transfer-Encoding');
return;
if (val == null) {
if (!statuses.empty[this.status]) {
if (this.type === 'application/json') {
this._body = 'null'
return
}
this.status = 204
}
if (val === null) this._explicitNullBody = true
this.remove('Content-Type')
this.remove('Content-Length')
this.remove('Transfer-Encoding')
return
}
// set the status
if (!this._explicitStatus) this.status = 200;
if (!this._explicitStatus) this.status = 200
// set the content-type only if not yet set
const setType = !this.has('Content-Type');
const setType = !this.has('Content-Type')
// string
if ('string' === typeof val) {
if (setType) this.type = /^\s*</.test(val) ? 'html' : 'text';
this.length = Buffer.byteLength(val);
return;
if (typeof val === 'string') {
if (setType) this.type = /^\s*</.test(val) ? 'html' : 'text'
this.length = Buffer.byteLength(val)
return
}

@@ -173,5 +179,5 @@

if (Buffer.isBuffer(val)) {
if (setType) this.type = 'bin';
this.length = val.length;
return;
if (setType) this.type = 'bin'
this.length = val.length
return
}

@@ -181,16 +187,16 @@

if (val instanceof Stream) {
onFinish(this.res, destroy.bind(null, val));
if (original != val) {
val.once('error', err => this.ctx.onerror(err));
onFinish(this.res, destroy.bind(null, val))
if (original !== val) {
val.once('error', err => this.ctx.onerror(err))
// overwriting
if (null != original) this.remove('Content-Length');
if (original != null) this.remove('Content-Length')
}
if (setType) this.type = 'bin';
return;
if (setType) this.type = 'bin'
return
}
// json
this.remove('Content-Length');
this.type = 'json';
this.remove('Content-Length')
this.type = 'json'
},

@@ -205,5 +211,5 @@

set length(n) {
set length (n) {
if (!this.has('Transfer-Encoding')) {
this.set('Content-Length', n);
this.set('Content-Length', n)
}

@@ -219,12 +225,12 @@ },

get length() {
get length () {
if (this.has('Content-Length')) {
return parseInt(this.get('Content-Length'), 10) || 0;
return parseInt(this.get('Content-Length'), 10) || 0
}
const { body } = this;
if (!body || body instanceof Stream) return undefined;
if ('string' === typeof body) return Buffer.byteLength(body);
if (Buffer.isBuffer(body)) return body.length;
return Buffer.byteLength(JSON.stringify(body));
const { body } = this
if (!body || body instanceof Stream) return undefined
if (typeof body === 'string') return Buffer.byteLength(body)
if (Buffer.isBuffer(body)) return body.length
return Buffer.byteLength(JSON.stringify(body))
},

@@ -239,4 +245,4 @@

get headerSent() {
return this.res.headersSent;
get headerSent () {
return this.res.headersSent
},

@@ -251,6 +257,6 @@

vary(field) {
if (this.headerSent) return;
vary (field) {
if (this.headerSent) return
vary(this.res, field);
vary(this.res, field)
},

@@ -277,21 +283,21 @@

redirect(url, alt) {
redirect (url, alt) {
// location
if ('back' === url) url = this.ctx.get('Referrer') || alt || '/';
this.set('Location', encodeUrl(url));
if (url === 'back') url = this.ctx.get('Referrer') || alt || '/'
this.set('Location', encodeUrl(url))
// status
if (!statuses.redirect[this.status]) this.status = 302;
if (!statuses.redirect[this.status]) this.status = 302
// html
if (this.ctx.accepts('html')) {
url = escape(url);
this.type = 'text/html; charset=utf-8';
this.body = `Redirecting to <a href="${url}">${url}</a>.`;
return;
url = escape(url)
this.type = 'text/html; charset=utf-8'
this.body = `Redirecting to <a href="${url}">${url}</a>.`
return
}
// text
this.type = 'text/plain; charset=utf-8';
this.body = `Redirecting to ${url}.`;
this.type = 'text/plain; charset=utf-8'
this.body = `Redirecting to ${url}.`
},

@@ -306,5 +312,5 @@

attachment(filename, options) {
if (filename) this.type = extname(filename);
this.set('Content-Disposition', contentDisposition(filename, options));
attachment (filename, options) {
if (filename) this.type = extname(filename)
this.set('Content-Disposition', contentDisposition(filename, options))
},

@@ -328,8 +334,8 @@

set type(type) {
type = getType(type);
set type (type) {
type = getType(type)
if (type) {
this.set('Content-Type', type);
this.set('Content-Type', type)
} else {
this.remove('Content-Type');
this.remove('Content-Type')
}

@@ -348,5 +354,5 @@ },

set lastModified(val) {
if ('string' === typeof val) val = new Date(val);
this.set('Last-Modified', val.toUTCString());
set lastModified (val) {
if (typeof val === 'string') val = new Date(val)
this.set('Last-Modified', val.toUTCString())
},

@@ -361,5 +367,5 @@

get lastModified() {
const date = this.get('last-modified');
if (date) return new Date(date);
get lastModified () {
const date = this.get('last-modified')
if (date) return new Date(date)
},

@@ -379,5 +385,5 @@

set etag(val) {
if (!/^(W\/)?"/.test(val)) val = `"${val}"`;
this.set('ETag', val);
set etag (val) {
if (!/^(W\/)?"/.test(val)) val = `"${val}"`
this.set('ETag', val)
},

@@ -392,4 +398,4 @@

get etag() {
return this.get('ETag');
get etag () {
return this.get('ETag')
},

@@ -405,6 +411,6 @@

get type() {
const type = this.get('Content-Type');
if (!type) return '';
return type.split(';', 1)[0];
get type () {
const type = this.get('Content-Type')
if (!type) return ''
return type.split(';', 1)[0]
},

@@ -422,4 +428,4 @@

is(type, ...types) {
return typeis(this.type, type, ...types);
is (type, ...types) {
return typeis(this.type, type, ...types)
},

@@ -439,8 +445,8 @@

* @param {String} field
* @return {String}
* @return {any}
* @api public
*/
get(field) {
return this.header[field.toLowerCase()] || '';
get (field) {
return this.res.getHeader(field)
},

@@ -465,7 +471,7 @@

has(field) {
has (field) {
return typeof this.res.hasHeader === 'function'
? this.res.hasHeader(field)
// Node < 7.7
: field.toLowerCase() in this.headers;
: field.toLowerCase() in this.headers
},

@@ -488,12 +494,12 @@

set(field, val) {
if (this.headerSent) return;
set (field, val) {
if (this.headerSent) return
if (2 === arguments.length) {
if (Array.isArray(val)) val = val.map(v => typeof v === 'string' ? v : String(v));
else if (typeof val !== 'string') val = String(val);
this.res.setHeader(field, val);
if (arguments.length === 2) {
if (Array.isArray(val)) val = val.map(v => typeof v === 'string' ? v : String(v))
else if (typeof val !== 'string') val = String(val)
this.res.setHeader(field, val)
} else {
for (const key in field) {
this.set(key, field[key]);
this.set(key, field[key])
}

@@ -519,4 +525,4 @@ }

append(field, val) {
const prev = this.get(field);
append (field, val) {
const prev = this.get(field)

@@ -526,6 +532,6 @@ if (prev) {

? prev.concat(val)
: [prev].concat(val);
: [prev].concat(val)
}
return this.set(field, val);
return this.set(field, val)
},

@@ -540,6 +546,6 @@

remove(field) {
if (this.headerSent) return;
remove (field) {
if (this.headerSent) return
this.res.removeHeader(field);
this.res.removeHeader(field)
},

@@ -556,3 +562,3 @@

get writable() {
get writable () {
// can't write any more after response finished

@@ -563,9 +569,9 @@ // response.writableEnded is available since Node > 12.9

// https://stackoverflow.com/questions/16254385/undocumented-response-finished-in-node-js
if (this.res.writableEnded || this.res.finished) return false;
if (this.res.writableEnded || this.res.finished) return false
const socket = this.res.socket;
const socket = this.res.socket
// There are already pending outgoing res, but still writable
// https://github.com/nodejs/node/blob/v4.4.7/lib/_http_server.js#L486
if (!socket) return true;
return socket.writable;
if (!socket) return true
return socket.writable
},

@@ -580,7 +586,7 @@

inspect() {
if (!this.res) return;
const o = this.toJSON();
o.body = this.body;
return o;
inspect () {
if (!this.res) return
const o = this.toJSON()
o.body = this.body
return o
},

@@ -595,3 +601,3 @@

toJSON() {
toJSON () {
return only(this, [

@@ -601,3 +607,3 @@ 'status',

'header'
]);
])
},

@@ -609,6 +615,6 @@

flushHeaders() {
this.res.flushHeaders();
flushHeaders () {
this.res.flushHeaders()
}
};
}

@@ -624,3 +630,3 @@ /**

if (util.inspect.custom) {
module.exports[util.inspect.custom] = module.exports.inspect;
module.exports[util.inspect.custom] = module.exports.inspect
}
{
"name": "koa",
"version": "2.14.1",
"version": "3.0.0-alpha.0",
"publishConfig": {
"tag": "experimental"
},
"description": "Koa web app framework",

@@ -11,10 +14,2 @@ "main": "lib/application.js",

},
"./lib/request": "./lib/request.js",
"./lib/request.js": "./lib/request.js",
"./lib/response": "./lib/response.js",
"./lib/response.js": "./lib/response.js",
"./lib/application": "./lib/application.js",
"./lib/application.js": "./lib/application.js",
"./lib/context": "./lib/context.js",
"./lib/context.js": "./lib/context.js",
"./*": "./*.js",

@@ -51,3 +46,2 @@ "./*.js": "./*.js",

"delegates": "^1.0.0",
"depd": "^2.0.0",
"destroy": "^1.0.4",

@@ -59,5 +53,3 @@ "encodeurl": "^1.0.2",

"http-errors": "^1.6.3",
"is-generator-function": "^1.0.7",
"koa-compose": "^4.1.0",
"koa-convert": "^2.0.0",
"on-finished": "^2.3.0",

@@ -72,3 +64,2 @@ "only": "~0.0.2",

"eslint": "^7.32.0",
"eslint-config-koa": "^2.0.0",
"eslint-config-standard": "^16.0.3",

@@ -80,7 +71,7 @@ "eslint-plugin-import": "^2.18.2",

"gen-esm-wrapper": "^1.0.6",
"jest": "^27.0.6",
"supertest": "^3.1.0"
"jest": "^28.1.2",
"supertest": "^6.2.4"
},
"engines": {
"node": "^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4"
"node": ">= 12.17.0"
},

@@ -87,0 +78,0 @@ "files": [

@@ -5,3 +5,3 @@ <img src="/docs/logo.png" alt="Koa middleware framework for nodejs"/>

[![NPM version][npm-image]][npm-url]
[![build status][travis-image]][travis-url]
[![build status][github-action-image]][github-action-url]
[![Test coverage][coveralls-image]][coveralls-url]

@@ -21,3 +21,3 @@ [![OpenCollective Backers][backers-image]](#backers)

Koa requires __node v7.6.0__ or higher for ES2015 and async function support.
Koa requires __node v12.17.0__ or higher for ES2015 and async function support.

@@ -45,6 +45,4 @@ ```

- [Kick-Off-Koa](https://github.com/koajs/kick-off-koa) - An intro to Koa via a set of self-guided workshops.
- [Workshop](https://github.com/koajs/workshop) - A workshop to learn the basics of Koa, Express' spiritual successor.
- [Introduction Screencast](https://knowthen.com/episode-3-koajs-quickstart-guide/) - An introduction to installing and getting started with Koa
- [Guide](docs/guide.md) - Go straight to the docs.
## Middleware

@@ -187,2 +185,3 @@

- [KoaJS Slack Group](https://join.slack.com/t/koa-js/shared_invite/zt-5pjgthmb-1JeKDbByqqcARtlPbtf~vQ)
- [Badgeboard](https://koajs.github.io/badgeboard) and list of official modules

@@ -283,4 +282,4 @@ - [Examples](https://github.com/koajs/examples)

[npm-url]: https://www.npmjs.com/package/koa
[travis-image]: https://img.shields.io/travis/koajs/koa/master.svg?style=flat-square
[travis-url]: https://travis-ci.org/koajs/koa
[github-action-image]: https://github.com/koajs/koa/actions/workflows/node.js.yml/badge.svg
[github-action-url]: https://github.com/koajs/koa/actions/workflows/node.js.yml
[coveralls-image]: https://img.shields.io/codecov/c/github/koajs/koa.svg?style=flat-square

@@ -287,0 +286,0 @@ [coveralls-url]: https://codecov.io/github/koajs/koa?branch=master

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc