koa 2.2.0 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/History.md CHANGED
@@ -1,4 +1,55 @@
1
1
 
2
+ 2.5.1 / 2018-04-27
3
+ ==================
4
+
5
+ * test: node v10 on travis (#1182)
6
+ * fix tests: remove unnecessary assert doesNotThrow and api calls (#1170)
7
+ * use this.response insteadof this.ctx.response (#1163)
8
+ * deps: remove istanbul (#1151)
9
+ * Update guide.md (#1150)
10
+
11
+ 2.5.0 / 2018-02-11
12
+ ==================
13
+
14
+ * feat: ignore set header/status when header sent (#1137)
15
+ * run coverage using --runInBand (#1141)
16
+ * [Update] license year to 2018 (#1130)
17
+ * docs: small grammatical fix in api docs index (#1111)
18
+ * docs: fixed typo (#1112)
19
+ * docs: capitalize K in word koa (#1126)
20
+ * Error handling: on non-error throw try to stringify if error is an object (#1113)
21
+ * Use eslint-config-koa (#1105)
22
+ * Update mgol's name in AUTHORS, add .mailmap (#1100)
23
+ * Avoid generating package locks instead of ignoring them (#1108)
24
+ * chore: update copyright year to 2017 (#1095)
25
+
26
+
27
+ 2.4.1 / 2017-11-06
28
+ ==================
29
+
30
+ * fix bad merge w/ 2.4.0
31
+
32
+ 2.4.0 / 2017-11-06
33
+ ==================
34
+
35
+ UNPUBLISHED
36
+
37
+ * update `package.engines.node` to be more strict
38
+ * update `fresh@^0.5.2`
39
+ * fix: `inspect()` no longer crashes `context`
40
+ * fix: gated `res.statusMessage` for HTTP/2
41
+ * added: `app.handleRequest()` is exposed
42
+
43
+ 2.3.0 / 2017-06-20
44
+ ==================
45
+
46
+ * fix: use `Buffer.from()`
47
+ * test on node 7 & 8
48
+ * add `package-lock.json` to `.gitignore`
49
+ * run `lint --fix`
50
+ * add `request.header` in addition to `request.headers`
51
+ * add IPv6 hostname support
52
+
2
53
  2.2.0 / 2017-03-14
3
54
  ==================
4
55
 
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  (The MIT License)
2
2
 
3
- Copyright (c) 2016 Koa contributors
3
+ Copyright (c) 2018 Koa contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
package/Readme.md CHANGED
@@ -1,4 +1,4 @@
1
- <img src="https://dl.dropboxusercontent.com/u/6396913/koa/logo.png" alt="koa middleware framework for nodejs" width="255px" />
1
+ <img src="/docs/logo.png" alt="Koa middleware framework for nodejs"/>
2
2
 
3
3
  [![gitter][gitter-image]][gitter-url]
4
4
  [![NPM version][npm-image]][npm-url]
@@ -22,7 +22,7 @@ Koa requires __node v7.6.0__ or higher for ES2015 and async function support.
22
22
  $ npm install koa
23
23
  ```
24
24
 
25
- ## Hello koa
25
+ ## Hello Koa
26
26
 
27
27
  ```js
28
28
  const Koa = require('koa');
@@ -38,17 +38,17 @@ app.listen(3000);
38
38
 
39
39
  ## Getting started
40
40
 
41
- - [Kick-Off-Koa](https://github.com/koajs/kick-off-koa) - An intro to koa via a set of self-guided workshops.
42
- - [Workshop](https://github.com/koajs/workshop) - A workshop to learn the basics of koa, Express' spiritual successor.
41
+ - [Kick-Off-Koa](https://github.com/koajs/kick-off-koa) - An intro to Koa via a set of self-guided workshops.
42
+ - [Workshop](https://github.com/koajs/workshop) - A workshop to learn the basics of Koa, Express' spiritual successor.
43
43
  - [Introduction Screencast](http://knowthen.com/episode-3-koajs-quickstart-guide/) - An introduction to installing and getting started with Koa
44
44
 
45
45
 
46
46
  ## Middleware
47
47
 
48
- Koa is a middleware framework that can take 3 different kinds of functions as middleware:
48
+ Koa is a middleware framework that can take two different kinds of functions as middleware:
49
49
 
50
- * common function
51
50
  * async function
51
+ * common function
52
52
 
53
53
  Here is an example of logger middleware with each of the different functions:
54
54
 
@@ -56,9 +56,9 @@ Here is an example of logger middleware with each of the different functions:
56
56
 
57
57
  ```js
58
58
  app.use(async (ctx, next) => {
59
- const start = new Date();
59
+ const start = Date.now();
60
60
  await next();
61
- const ms = new Date() - start;
61
+ const ms = Date.now() - start;
62
62
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
63
63
  });
64
64
  ```
@@ -70,9 +70,9 @@ app.use(async (ctx, next) => {
70
70
  // next is a function that is invoked to execute the downstream middleware. It returns a Promise with a then function for running code after completion.
71
71
 
72
72
  app.use((ctx, next) => {
73
- const start = new Date();
73
+ const start = Date.now();
74
74
  return next().then(() => {
75
- const ms = new Date() - start;
75
+ const ms = Date.now() - start;
76
76
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
77
77
  });
78
78
  });
@@ -195,7 +195,7 @@ the general Koa guide.
195
195
  ## Running tests
196
196
 
197
197
  ```
198
- $ make test
198
+ $ npm test
199
199
  ```
200
200
 
201
201
  ## Authors
@@ -211,9 +211,18 @@ See [AUTHORS](AUTHORS).
211
211
  - [G+ Community](https://plus.google.com/communities/101845768320796750641)
212
212
  - [Reddit Community](https://www.reddit.com/r/koajs)
213
213
  - [Mailing list](https://groups.google.com/forum/#!forum/koajs)
214
- - [中文文档](https://github.com/guo-yu/koa-guide)
214
+ - [中文文档 v1.x](https://github.com/guo-yu/koa-guide)
215
+ - [中文文档 v2.x](https://github.com/demopark/koa-docs-Zh-CN)
215
216
  - __[#koajs]__ on freenode
216
217
 
218
+ ## Job Board
219
+
220
+ Looking for a career upgrade?
221
+
222
+ <a href="https://astro.netlify.com/automattic"><img src="https://astro.netlify.com/static/automattic.png"></a>
223
+ <a href="https://astro.netlify.com/segment"><img src="https://astro.netlify.com/static/segment.png"></a>
224
+ <a href="https://astro.netlify.com/auth0"><img src="https://astro.netlify.com/static/auth0.png"/></a>
225
+
217
226
  ## Backers
218
227
 
219
228
  Support us with a monthly donation and help us continue our activities.
@@ -58,10 +58,10 @@ module.exports = class Application extends Emitter {
58
58
  * @api public
59
59
  */
60
60
 
61
- listen() {
61
+ listen(...args) {
62
62
  debug('listen');
63
63
  const server = http.createServer(this.callback());
64
- return server.listen.apply(server, arguments);
64
+ return server.listen(...args);
65
65
  }
66
66
 
67
67
  /**
@@ -128,17 +128,28 @@ module.exports = class Application extends Emitter {
128
128
  if (!this.listeners('error').length) this.on('error', this.onerror);
129
129
 
130
130
  const handleRequest = (req, res) => {
131
- res.statusCode = 404;
132
131
  const ctx = this.createContext(req, res);
133
- const onerror = err => ctx.onerror(err);
134
- const handleResponse = () => respond(ctx);
135
- onFinished(res, onerror);
136
- return fn(ctx).then(handleResponse).catch(onerror);
132
+ return this.handleRequest(ctx, fn);
137
133
  };
138
134
 
139
135
  return handleRequest;
140
136
  }
141
137
 
138
+ /**
139
+ * Handle request in callback.
140
+ *
141
+ * @api private
142
+ */
143
+
144
+ handleRequest(ctx, fnMiddleware) {
145
+ const res = ctx.res;
146
+ res.statusCode = 404;
147
+ const onerror = err => ctx.onerror(err);
148
+ const handleResponse = () => respond(ctx);
149
+ onFinished(res, onerror);
150
+ return fnMiddleware(ctx).then(handleResponse).catch(onerror);
151
+ }
152
+
142
153
  /**
143
154
  * Initialize a new context.
144
155
  *
package/lib/context.js CHANGED
@@ -5,6 +5,7 @@
5
5
  * Module dependencies.
6
6
  */
7
7
 
8
+ const util = require('util');
8
9
  const createError = require('http-errors');
9
10
  const httpAssert = require('http-assert');
10
11
  const delegate = require('delegates');
@@ -25,6 +26,7 @@ const proto = module.exports = {
25
26
  */
26
27
 
27
28
  inspect() {
29
+ if (this === proto) return this;
28
30
  return this.toJSON();
29
31
  },
30
32
 
@@ -87,8 +89,8 @@ const proto = module.exports = {
87
89
  * @api public
88
90
  */
89
91
 
90
- throw() {
91
- throw createError.apply(null, arguments);
92
+ throw(...args) {
93
+ throw createError(...args);
92
94
  },
93
95
 
94
96
  /**
@@ -104,7 +106,7 @@ const proto = module.exports = {
104
106
  // to node-style callbacks.
105
107
  if (null == err) return;
106
108
 
107
- if (!(err instanceof Error)) err = new Error(`non-error thrown: ${err}`);
109
+ if (!(err instanceof Error)) err = new Error(util.format('non-error thrown: %j', err));
108
110
 
109
111
  let headerSent = false;
110
112
  if (this.headerSent || !this.writable) {
@@ -198,6 +200,7 @@ delegate(proto, 'request')
198
200
  .getter('protocol')
199
201
  .getter('host')
200
202
  .getter('hostname')
203
+ .getter('URL')
201
204
  .getter('header')
202
205
  .getter('headers')
203
206
  .getter('secure')
package/lib/request.js CHANGED
@@ -5,6 +5,7 @@
5
5
  * Module dependencies.
6
6
  */
7
7
 
8
+ const URL = require('url').URL;
8
9
  const net = require('net');
9
10
  const contentType = require('content-type');
10
11
  const stringify = require('url').format;
@@ -31,6 +32,16 @@ module.exports = {
31
32
  return this.req.headers;
32
33
  },
33
34
 
35
+ /**
36
+ * Set request header.
37
+ *
38
+ * @api public
39
+ */
40
+
41
+ set header(val) {
42
+ this.req.headers = val;
43
+ },
44
+
34
45
  /**
35
46
  * Return request header, alias as request.header
36
47
  *
@@ -42,6 +53,16 @@ module.exports = {
42
53
  return this.req.headers;
43
54
  },
44
55
 
56
+ /**
57
+ * Set request header, alias as request.header
58
+ *
59
+ * @api public
60
+ */
61
+
62
+ set headers(val) {
63
+ this.req.headers = val;
64
+ },
65
+
45
66
  /**
46
67
  * Get request URL.
47
68
  *
@@ -244,9 +265,32 @@ module.exports = {
244
265
  get hostname() {
245
266
  const host = this.host;
246
267
  if (!host) return '';
268
+ if ('[' == host[0]) return this.URL.hostname || ''; // IPv6
247
269
  return host.split(':')[0];
248
270
  },
249
271
 
272
+ /**
273
+ * Get WHATWG parsed URL.
274
+ * Lazily memoized.
275
+ *
276
+ * @return {URL|Object}
277
+ * @api public
278
+ */
279
+
280
+ get URL() {
281
+ if (!this.memoizedURL) {
282
+ const protocol = this.protocol;
283
+ const host = this.host;
284
+ const originalUrl = this.originalUrl || ''; // avoid undefined in template string
285
+ try {
286
+ this.memoizedURL = new URL(`${protocol}://${host}${originalUrl}`);
287
+ } catch (err) {
288
+ this.memoizedURL = Object.create(null);
289
+ }
290
+ }
291
+ return this.memoizedURL;
292
+ },
293
+
250
294
  /**
251
295
  * Check if the request is fresh, aka
252
296
  * Last-Modified and/or the ETag
@@ -265,7 +309,7 @@ module.exports = {
265
309
 
266
310
  // 2xx or 304 as per rfc2616 14.26
267
311
  if ((s >= 200 && s < 300) || 304 == s) {
268
- return fresh(this.header, this.ctx.response.header);
312
+ return fresh(this.header, this.response.header);
269
313
  }
270
314
 
271
315
  return false;
@@ -460,8 +504,8 @@ module.exports = {
460
504
  * @api public
461
505
  */
462
506
 
463
- accepts() {
464
- return this.accept.types.apply(this.accept, arguments);
507
+ accepts(...args) {
508
+ return this.accept.types(...args);
465
509
  },
466
510
 
467
511
  /**
@@ -477,8 +521,8 @@ module.exports = {
477
521
  * @api public
478
522
  */
479
523
 
480
- acceptsEncodings() {
481
- return this.accept.encodings.apply(this.accept, arguments);
524
+ acceptsEncodings(...args) {
525
+ return this.accept.encodings(...args);
482
526
  },
483
527
 
484
528
  /**
@@ -494,8 +538,8 @@ module.exports = {
494
538
  * @api public
495
539
  */
496
540
 
497
- acceptsCharsets() {
498
- return this.accept.charsets.apply(this.accept, arguments);
541
+ acceptsCharsets(...args) {
542
+ return this.accept.charsets(...args);
499
543
  },
500
544
 
501
545
  /**
@@ -511,8 +555,8 @@ module.exports = {
511
555
  * @api public
512
556
  */
513
557
 
514
- acceptsLanguages() {
515
- return this.accept.languages.apply(this.accept, arguments);
558
+ acceptsLanguages(...args) {
559
+ return this.accept.languages(...args);
516
560
  },
517
561
 
518
562
  /**
package/lib/response.js CHANGED
@@ -80,12 +80,13 @@ module.exports = {
80
80
  */
81
81
 
82
82
  set status(code) {
83
+ if (this.headerSent) return;
84
+
83
85
  assert('number' == typeof code, 'status code must be a number');
84
86
  assert(statuses[code], `invalid status code: ${code}`);
85
- assert(!this.res.headersSent, 'headers have already been sent');
86
87
  this._explicitStatus = true;
87
88
  this.res.statusCode = code;
88
- this.res.statusMessage = statuses[code];
89
+ if (this.req.httpVersionMajor < 2) this.res.statusMessage = statuses[code];
89
90
  if (this.body && statuses.empty[code]) this.body = null;
90
91
  },
91
92
 
@@ -133,8 +134,6 @@ module.exports = {
133
134
  const original = this._body;
134
135
  this._body = val;
135
136
 
136
- if (this.res.headersSent) return;
137
-
138
137
  // no content
139
138
  if (null == val) {
140
139
  if (!statuses.empty[this.status]) this.status = 204;
@@ -233,6 +232,8 @@ module.exports = {
233
232
  */
234
233
 
235
234
  vary(field) {
235
+ if (this.headerSent) return;
236
+
236
237
  vary(this.res, field);
237
238
  },
238
239
 
@@ -305,7 +306,7 @@ module.exports = {
305
306
  */
306
307
 
307
308
  set type(type) {
308
- type = getType(type) || false;
309
+ type = getType(type);
309
310
  if (type) {
310
311
  this.set('Content-Type', type);
311
312
  } else {
@@ -434,6 +435,8 @@ module.exports = {
434
435
  */
435
436
 
436
437
  set(field, val) {
438
+ if (this.headerSent) return;
439
+
437
440
  if (2 == arguments.length) {
438
441
  if (Array.isArray(val)) val = val.map(String);
439
442
  else val = String(val);
@@ -481,6 +484,8 @@ module.exports = {
481
484
  */
482
485
 
483
486
  remove(field) {
487
+ if (this.headerSent) return;
488
+
484
489
  this.res.removeHeader(field);
485
490
  },
486
491
 
package/package.json CHANGED
@@ -1,10 +1,14 @@
1
1
  {
2
2
  "name": "koa",
3
- "version": "2.2.0",
3
+ "version": "2.5.1",
4
4
  "description": "Koa web app framework",
5
5
  "main": "lib/application.js",
6
6
  "scripts": {
7
- "test": "make test"
7
+ "test": "jest",
8
+ "test-cov": "jest --coverage --runInBand --forceExit",
9
+ "lint": "eslint benchmarks lib test",
10
+ "bench": "make -C benchmarks",
11
+ "authors": "git log --format='%aN <%aE>' | sort -u > AUTHORS"
8
12
  },
9
13
  "repository": "koajs/koa",
10
14
  "keywords": [
@@ -28,11 +32,11 @@
28
32
  "destroy": "^1.0.3",
29
33
  "error-inject": "~1.0.0",
30
34
  "escape-html": "~1.0.1",
31
- "fresh": "^0.5.0",
35
+ "fresh": "^0.5.2",
32
36
  "http-assert": "^1.1.0",
33
37
  "http-errors": "^1.2.8",
34
38
  "is-generator-function": "^1.0.3",
35
- "koa-compose": "^3.0.0",
39
+ "koa-compose": "^4.0.0",
36
40
  "koa-convert": "^1.2.0",
37
41
  "koa-is-json": "^1.0.0",
38
42
  "mime-types": "^2.0.7",
@@ -44,23 +48,29 @@
44
48
  "vary": "^1.0.0"
45
49
  },
46
50
  "devDependencies": {
47
- "babel-eslint": "^7.1.1",
48
51
  "eslint": "^3.17.1",
52
+ "eslint-config-koa": "^2.0.0",
49
53
  "eslint-config-standard": "^7.0.1",
50
- "eslint-plugin-babel": "^4.1.1",
51
54
  "eslint-plugin-promise": "^3.5.0",
52
55
  "eslint-plugin-standard": "^2.1.1",
53
- "istanbul": "^0.4.0",
54
- "mocha": "^3.2.0",
55
- "should": "^6.0.3",
56
- "should-http": "0.0.3",
57
- "supertest": "^3.0.0",
58
- "test-console": "^0.7.1"
56
+ "jest": "^20.0.0",
57
+ "supertest": "^3.0.0"
59
58
  },
60
59
  "engines": {
61
- "node": ">= 6.0.0"
60
+ "node": "^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4"
62
61
  },
63
62
  "files": [
64
63
  "lib"
65
- ]
64
+ ],
65
+ "jest": {
66
+ "testMatch": [
67
+ "**/test/!(helpers)/*.js"
68
+ ],
69
+ "coverageReporters": [
70
+ "text-summary",
71
+ "lcov"
72
+ ],
73
+ "bail": true,
74
+ "testEnvironment": "node"
75
+ }
66
76
  }