@eggjs/koa 2.14.2
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/LICENSE +23 -0
- package/Readme.md +279 -0
- package/dist/koa.mjs +4 -0
- package/lib/application.js +318 -0
- package/lib/context.js +251 -0
- package/lib/request.js +726 -0
- package/lib/response.js +588 -0
- package/package.json +93 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
(The MIT License)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 Koa contributors
|
|
4
|
+
Copyright (c) 2023 EggJS contributors
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
7
|
+
a copy of this software and associated documentation files (the
|
|
8
|
+
'Software'), to deal in the Software without restriction, including
|
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
12
|
+
the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be
|
|
15
|
+
included in all copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
20
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
21
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
22
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
23
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/Readme.md
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# @eggjs/koa
|
|
2
|
+
|
|
3
|
+
@eggjs/koa is forked from [Koa v2.x](https://github.com/koajs/koa/tree/v2.x) for LTS and drop Node.js < 16.13.0 support.
|
|
4
|
+
|
|
5
|
+
<img src="/docs/logo.png" alt="Koa middleware framework for nodejs"/>
|
|
6
|
+
|
|
7
|
+
[](https://npmjs.org/package/@eggjs/koa)
|
|
8
|
+
[](http://packagequality.com/#?package=@eggjs/koa)
|
|
9
|
+
[](https://npmjs.org/package/@eggjs/koa)
|
|
10
|
+
[](https://app.fossa.com/projects/git%2Bgithub.com%2Feggjs%2Fkoa?ref=badge_shield)
|
|
11
|
+
[](https://github.com/eggjs/koa/actions?query=branch%3Amaster)
|
|
12
|
+
[](https://codecov.io/gh/eggjs/koa)
|
|
13
|
+
[](https://snyk.io/test/npm/@eggjs/koa)
|
|
14
|
+
|
|
15
|
+
Expressive HTTP middleware framework for node.js to make web applications and APIs more enjoyable to write. Koa's middleware stack flows in a stack-like manner, allowing you to perform actions downstream then filter and manipulate the response upstream.
|
|
16
|
+
|
|
17
|
+
Only methods that are common to nearly all HTTP servers are integrated directly into Koa's small ~570 SLOC codebase. This
|
|
18
|
+
includes things like content negotiation, normalization of node inconsistencies, redirection, and a few others.
|
|
19
|
+
|
|
20
|
+
Koa is not bundled with any middleware.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
@eggjs/koa requires __node v16.3.0__ or higher for Node.js LTS support.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @eggjs/koa
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Hello Koa
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
const Koa = require('@eggjs/koa');
|
|
34
|
+
const app = new Koa();
|
|
35
|
+
|
|
36
|
+
// response
|
|
37
|
+
app.use(ctx => {
|
|
38
|
+
ctx.body = 'Hello Koa';
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
app.listen(3000);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Getting started
|
|
45
|
+
|
|
46
|
+
- [Kick-Off-Koa](https://github.com/koajs/kick-off-koa) - An intro to Koa via a set of self-guided workshops.
|
|
47
|
+
- [Workshop](https://github.com/koajs/workshop) - A workshop to learn the basics of Koa, Express' spiritual successor.
|
|
48
|
+
- [Introduction Screencast](https://knowthen.com/episode-3-koajs-quickstart-guide/) - An introduction to installing and getting started with Koa
|
|
49
|
+
|
|
50
|
+
## Middleware
|
|
51
|
+
|
|
52
|
+
Koa is a middleware framework that can take two different kinds of functions as middleware:
|
|
53
|
+
|
|
54
|
+
- async function
|
|
55
|
+
- common function
|
|
56
|
+
|
|
57
|
+
Here is an example of logger middleware with each of the different functions:
|
|
58
|
+
|
|
59
|
+
### ___async___ functions (node v7.6+)
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
app.use(async (ctx, next) => {
|
|
63
|
+
const start = Date.now();
|
|
64
|
+
await next();
|
|
65
|
+
const ms = Date.now() - start;
|
|
66
|
+
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Common function
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
// Middleware normally takes two parameters (ctx, next), ctx is the context for one request,
|
|
74
|
+
// 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.
|
|
75
|
+
|
|
76
|
+
app.use((ctx, next) => {
|
|
77
|
+
const start = Date.now();
|
|
78
|
+
return next().then(() => {
|
|
79
|
+
const ms = Date.now() - start;
|
|
80
|
+
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Koa v1.x Middleware Signature
|
|
86
|
+
|
|
87
|
+
The middleware signature changed between v1.x and v2.x. The older signature is deprecated.
|
|
88
|
+
|
|
89
|
+
__Old signature middleware support will be removed in v3__
|
|
90
|
+
|
|
91
|
+
Please see the [Migration Guide](docs/migration.md) for more information on upgrading from v1.x and
|
|
92
|
+
using v1.x middleware with v2.x.
|
|
93
|
+
|
|
94
|
+
## Context, Request and Response
|
|
95
|
+
|
|
96
|
+
Each middleware receives a Koa `Context` object that encapsulates an incoming
|
|
97
|
+
http message and the corresponding response to that message. `ctx` is often used
|
|
98
|
+
as the parameter name for the context object.
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
app.use(async (ctx, next) => {
|
|
102
|
+
await next();
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Koa provides a `Request` object as the `request` property of the `Context`.
|
|
107
|
+
Koa's `Request` object provides helpful methods for working with
|
|
108
|
+
http requests which delegate to an [IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)
|
|
109
|
+
from the node `http` module.
|
|
110
|
+
|
|
111
|
+
Here is an example of checking that a requesting client supports xml.
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
app.use(async (ctx, next) => {
|
|
115
|
+
ctx.assert(ctx.request.accepts('xml'), 406);
|
|
116
|
+
// equivalent to:
|
|
117
|
+
// if (!ctx.request.accepts('xml')) ctx.throw(406);
|
|
118
|
+
await next();
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Koa provides a `Response` object as the `response` property of the `Context`.
|
|
123
|
+
Koa's `Response` object provides helpful methods for working with
|
|
124
|
+
http responses which delegate to a [ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse)
|
|
125
|
+
.
|
|
126
|
+
|
|
127
|
+
Koa's pattern of delegating to Node's request and response objects rather than extending them
|
|
128
|
+
provides a cleaner interface and reduces conflicts between different middleware and with Node
|
|
129
|
+
itself as well as providing better support for stream handling. The `IncomingMessage` can still be
|
|
130
|
+
directly accessed as the `req` property on the `Context` and `ServerResponse` can be directly
|
|
131
|
+
accessed as the `res` property on the `Context`.
|
|
132
|
+
|
|
133
|
+
Here is an example using Koa's `Response` object to stream a file as the response body.
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
app.use(async (ctx, next) => {
|
|
137
|
+
await next();
|
|
138
|
+
ctx.response.type = 'xml';
|
|
139
|
+
ctx.response.body = fs.createReadStream('really_large.xml');
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The `Context` object also provides shortcuts for methods on its `request` and `response`. In the prior
|
|
144
|
+
examples, `ctx.type` can be used instead of `ctx.response.type` and `ctx.accepts` can be used
|
|
145
|
+
instead of `ctx.request.accepts`.
|
|
146
|
+
|
|
147
|
+
For more information on `Request`, `Response` and `Context`, see the [Request API Reference](docs/api/request.md),
|
|
148
|
+
[Response API Reference](docs/api/response.md) and [Context API Reference](docs/api/context.md).
|
|
149
|
+
|
|
150
|
+
## Koa Application
|
|
151
|
+
|
|
152
|
+
The object created when executing `new Koa()` is known as the Koa application object.
|
|
153
|
+
|
|
154
|
+
The application object is Koa's interface with node's http server and handles the registration
|
|
155
|
+
of middleware, dispatching to the middleware from http, default error handling, as well as
|
|
156
|
+
configuration of the context, request and response objects.
|
|
157
|
+
|
|
158
|
+
Learn more about the application object in the [Application API Reference](docs/api/index.md).
|
|
159
|
+
|
|
160
|
+
## Documentation
|
|
161
|
+
|
|
162
|
+
- [Usage Guide](docs/guide.md)
|
|
163
|
+
- [Error Handling](docs/error-handling.md)
|
|
164
|
+
- [Koa for Express Users](docs/koa-vs-express.md)
|
|
165
|
+
- [FAQ](docs/faq.md)
|
|
166
|
+
- [API documentation](docs/api/index.md)
|
|
167
|
+
|
|
168
|
+
## Troubleshooting
|
|
169
|
+
|
|
170
|
+
Check the [Troubleshooting Guide](docs/troubleshooting.md) or [Debugging Koa](docs/guide.md#debugging-koa) in
|
|
171
|
+
the general Koa guide.
|
|
172
|
+
|
|
173
|
+
## Running tests
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
npm test
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Reporting vulnerabilities
|
|
180
|
+
|
|
181
|
+
To report a security vulnerability, please do not open an issue, as this notifies attackers of the vulnerability. Instead, please email [fengmk2](mailto:fengmk2+eggjs@gmail.com) to disclose.
|
|
182
|
+
|
|
183
|
+
## Authors
|
|
184
|
+
|
|
185
|
+
See [AUTHORS](AUTHORS).
|
|
186
|
+
|
|
187
|
+
## Community
|
|
188
|
+
|
|
189
|
+
- [Badgeboard](https://koajs.github.io/badgeboard) and list of official modules
|
|
190
|
+
- [Examples](https://github.com/koajs/examples)
|
|
191
|
+
- [Middleware](https://github.com/koajs/koa/wiki) list
|
|
192
|
+
- [Wiki](https://github.com/koajs/koa/wiki)
|
|
193
|
+
- [Reddit Community](https://www.reddit.com/r/koajs)
|
|
194
|
+
- [Mailing list](https://groups.google.com/forum/#!forum/koajs)
|
|
195
|
+
- [中文文档 v1.x](https://github.com/guo-yu/koa-guide)
|
|
196
|
+
- [中文文档 v2.x](https://github.com/demopark/koa-docs-Zh-CN)
|
|
197
|
+
- __[#koajs]__ on freenode
|
|
198
|
+
|
|
199
|
+
## Job Board
|
|
200
|
+
|
|
201
|
+
Looking for a career upgrade?
|
|
202
|
+
|
|
203
|
+
<a href="https://astro.netlify.com/automattic"><img src="https://astro.netlify.com/static/automattic.png"></a>
|
|
204
|
+
<a href="https://astro.netlify.com/segment"><img src="https://astro.netlify.com/static/segment.png"></a>
|
|
205
|
+
<a href="https://astro.netlify.com/auth0"><img src="https://astro.netlify.com/static/auth0.png"/></a>
|
|
206
|
+
|
|
207
|
+
## Backers
|
|
208
|
+
|
|
209
|
+
Support us with a monthly donation and help us continue our activities.
|
|
210
|
+
|
|
211
|
+
<a href="https://opencollective.com/koajs/backer/0/website" target="_blank"><img src="https://opencollective.com/koajs/backer/0/avatar.svg"></a>
|
|
212
|
+
<a href="https://opencollective.com/koajs/backer/1/website" target="_blank"><img src="https://opencollective.com/koajs/backer/1/avatar.svg"></a>
|
|
213
|
+
<a href="https://opencollective.com/koajs/backer/2/website" target="_blank"><img src="https://opencollective.com/koajs/backer/2/avatar.svg"></a>
|
|
214
|
+
<a href="https://opencollective.com/koajs/backer/3/website" target="_blank"><img src="https://opencollective.com/koajs/backer/3/avatar.svg"></a>
|
|
215
|
+
<a href="https://opencollective.com/koajs/backer/4/website" target="_blank"><img src="https://opencollective.com/koajs/backer/4/avatar.svg"></a>
|
|
216
|
+
<a href="https://opencollective.com/koajs/backer/5/website" target="_blank"><img src="https://opencollective.com/koajs/backer/5/avatar.svg"></a>
|
|
217
|
+
<a href="https://opencollective.com/koajs/backer/6/website" target="_blank"><img src="https://opencollective.com/koajs/backer/6/avatar.svg"></a>
|
|
218
|
+
<a href="https://opencollective.com/koajs/backer/7/website" target="_blank"><img src="https://opencollective.com/koajs/backer/7/avatar.svg"></a>
|
|
219
|
+
<a href="https://opencollective.com/koajs/backer/8/website" target="_blank"><img src="https://opencollective.com/koajs/backer/8/avatar.svg"></a>
|
|
220
|
+
<a href="https://opencollective.com/koajs/backer/9/website" target="_blank"><img src="https://opencollective.com/koajs/backer/9/avatar.svg"></a>
|
|
221
|
+
<a href="https://opencollective.com/koajs/backer/10/website" target="_blank"><img src="https://opencollective.com/koajs/backer/10/avatar.svg"></a>
|
|
222
|
+
<a href="https://opencollective.com/koajs/backer/11/website" target="_blank"><img src="https://opencollective.com/koajs/backer/11/avatar.svg"></a>
|
|
223
|
+
<a href="https://opencollective.com/koajs/backer/12/website" target="_blank"><img src="https://opencollective.com/koajs/backer/12/avatar.svg"></a>
|
|
224
|
+
<a href="https://opencollective.com/koajs/backer/13/website" target="_blank"><img src="https://opencollective.com/koajs/backer/13/avatar.svg"></a>
|
|
225
|
+
<a href="https://opencollective.com/koajs/backer/14/website" target="_blank"><img src="https://opencollective.com/koajs/backer/14/avatar.svg"></a>
|
|
226
|
+
<a href="https://opencollective.com/koajs/backer/15/website" target="_blank"><img src="https://opencollective.com/koajs/backer/15/avatar.svg"></a>
|
|
227
|
+
<a href="https://opencollective.com/koajs/backer/16/website" target="_blank"><img src="https://opencollective.com/koajs/backer/16/avatar.svg"></a>
|
|
228
|
+
<a href="https://opencollective.com/koajs/backer/17/website" target="_blank"><img src="https://opencollective.com/koajs/backer/17/avatar.svg"></a>
|
|
229
|
+
<a href="https://opencollective.com/koajs/backer/18/website" target="_blank"><img src="https://opencollective.com/koajs/backer/18/avatar.svg"></a>
|
|
230
|
+
<a href="https://opencollective.com/koajs/backer/19/website" target="_blank"><img src="https://opencollective.com/koajs/backer/19/avatar.svg"></a>
|
|
231
|
+
<a href="https://opencollective.com/koajs/backer/20/website" target="_blank"><img src="https://opencollective.com/koajs/backer/20/avatar.svg"></a>
|
|
232
|
+
<a href="https://opencollective.com/koajs/backer/21/website" target="_blank"><img src="https://opencollective.com/koajs/backer/21/avatar.svg"></a>
|
|
233
|
+
<a href="https://opencollective.com/koajs/backer/22/website" target="_blank"><img src="https://opencollective.com/koajs/backer/22/avatar.svg"></a>
|
|
234
|
+
<a href="https://opencollective.com/koajs/backer/23/website" target="_blank"><img src="https://opencollective.com/koajs/backer/23/avatar.svg"></a>
|
|
235
|
+
<a href="https://opencollective.com/koajs/backer/24/website" target="_blank"><img src="https://opencollective.com/koajs/backer/24/avatar.svg"></a>
|
|
236
|
+
<a href="https://opencollective.com/koajs/backer/25/website" target="_blank"><img src="https://opencollective.com/koajs/backer/25/avatar.svg"></a>
|
|
237
|
+
<a href="https://opencollective.com/koajs/backer/26/website" target="_blank"><img src="https://opencollective.com/koajs/backer/26/avatar.svg"></a>
|
|
238
|
+
<a href="https://opencollective.com/koajs/backer/27/website" target="_blank"><img src="https://opencollective.com/koajs/backer/27/avatar.svg"></a>
|
|
239
|
+
<a href="https://opencollective.com/koajs/backer/28/website" target="_blank"><img src="https://opencollective.com/koajs/backer/28/avatar.svg"></a>
|
|
240
|
+
<a href="https://opencollective.com/koajs/backer/29/website" target="_blank"><img src="https://opencollective.com/koajs/backer/29/avatar.svg"></a>
|
|
241
|
+
|
|
242
|
+
## Sponsors
|
|
243
|
+
|
|
244
|
+
Become a sponsor and get your logo on our README on Github with a link to your site.
|
|
245
|
+
|
|
246
|
+
<a href="https://opencollective.com/koajs/sponsor/0/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/0/avatar.svg"></a>
|
|
247
|
+
<a href="https://opencollective.com/koajs/sponsor/1/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/1/avatar.svg"></a>
|
|
248
|
+
<a href="https://opencollective.com/koajs/sponsor/2/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/2/avatar.svg"></a>
|
|
249
|
+
<a href="https://opencollective.com/koajs/sponsor/3/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/3/avatar.svg"></a>
|
|
250
|
+
<a href="https://opencollective.com/koajs/sponsor/4/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/4/avatar.svg"></a>
|
|
251
|
+
<a href="https://opencollective.com/koajs/sponsor/5/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/5/avatar.svg"></a>
|
|
252
|
+
<a href="https://opencollective.com/koajs/sponsor/6/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/6/avatar.svg"></a>
|
|
253
|
+
<a href="https://opencollective.com/koajs/sponsor/7/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/7/avatar.svg"></a>
|
|
254
|
+
<a href="https://opencollective.com/koajs/sponsor/8/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/8/avatar.svg"></a>
|
|
255
|
+
<a href="https://opencollective.com/koajs/sponsor/9/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/9/avatar.svg"></a>
|
|
256
|
+
<a href="https://opencollective.com/koajs/sponsor/10/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/10/avatar.svg"></a>
|
|
257
|
+
<a href="https://opencollective.com/koajs/sponsor/11/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/11/avatar.svg"></a>
|
|
258
|
+
<a href="https://opencollective.com/koajs/sponsor/12/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/12/avatar.svg"></a>
|
|
259
|
+
<a href="https://opencollective.com/koajs/sponsor/13/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/13/avatar.svg"></a>
|
|
260
|
+
<a href="https://opencollective.com/koajs/sponsor/14/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/14/avatar.svg"></a>
|
|
261
|
+
<a href="https://opencollective.com/koajs/sponsor/15/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/15/avatar.svg"></a>
|
|
262
|
+
<a href="https://opencollective.com/koajs/sponsor/16/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/16/avatar.svg"></a>
|
|
263
|
+
<a href="https://opencollective.com/koajs/sponsor/17/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/17/avatar.svg"></a>
|
|
264
|
+
<a href="https://opencollective.com/koajs/sponsor/18/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/18/avatar.svg"></a>
|
|
265
|
+
<a href="https://opencollective.com/koajs/sponsor/19/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/19/avatar.svg"></a>
|
|
266
|
+
<a href="https://opencollective.com/koajs/sponsor/20/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/20/avatar.svg"></a>
|
|
267
|
+
<a href="https://opencollective.com/koajs/sponsor/21/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/21/avatar.svg"></a>
|
|
268
|
+
<a href="https://opencollective.com/koajs/sponsor/22/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/22/avatar.svg"></a>
|
|
269
|
+
<a href="https://opencollective.com/koajs/sponsor/23/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/23/avatar.svg"></a>
|
|
270
|
+
<a href="https://opencollective.com/koajs/sponsor/24/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/24/avatar.svg"></a>
|
|
271
|
+
<a href="https://opencollective.com/koajs/sponsor/25/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/25/avatar.svg"></a>
|
|
272
|
+
<a href="https://opencollective.com/koajs/sponsor/26/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/26/avatar.svg"></a>
|
|
273
|
+
<a href="https://opencollective.com/koajs/sponsor/27/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/27/avatar.svg"></a>
|
|
274
|
+
<a href="https://opencollective.com/koajs/sponsor/28/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/28/avatar.svg"></a>
|
|
275
|
+
<a href="https://opencollective.com/koajs/sponsor/29/website" target="_blank"><img src="https://opencollective.com/koajs/sponsor/29/avatar.svg"></a>
|
|
276
|
+
|
|
277
|
+
# License
|
|
278
|
+
|
|
279
|
+
[MIT](https://github.com/eggjs/koa/blob/master/LICENSE)
|
package/dist/koa.mjs
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Module dependencies.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const isGeneratorFunction = require('is-generator-function');
|
|
9
|
+
const debug = require('debug')('koa:application');
|
|
10
|
+
const onFinished = require('on-finished');
|
|
11
|
+
const assert = require('assert');
|
|
12
|
+
const response = require('./response');
|
|
13
|
+
const compose = require('koa-compose');
|
|
14
|
+
const context = require('./context');
|
|
15
|
+
const request = require('./request');
|
|
16
|
+
const statuses = require('statuses');
|
|
17
|
+
const Emitter = require('events');
|
|
18
|
+
const util = require('util');
|
|
19
|
+
const Stream = require('stream');
|
|
20
|
+
const http = require('http');
|
|
21
|
+
const only = require('only');
|
|
22
|
+
const convert = require('koa-convert');
|
|
23
|
+
const deprecate = require('depd')('koa');
|
|
24
|
+
const { HttpError } = require('http-errors');
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Expose `Application` class.
|
|
28
|
+
* Inherits from `Emitter.prototype`.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
module.exports = class Application extends Emitter {
|
|
32
|
+
/**
|
|
33
|
+
* Initialize a new `Application`.
|
|
34
|
+
*
|
|
35
|
+
* @api public
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
*
|
|
40
|
+
* @param {object} [options] Application options
|
|
41
|
+
* @param {string} [options.env='development'] Environment
|
|
42
|
+
* @param {string[]} [options.keys] Signed cookie keys
|
|
43
|
+
* @param {boolean} [options.proxy] Trust proxy headers
|
|
44
|
+
* @param {number} [options.subdomainOffset] Subdomain offset
|
|
45
|
+
* @param {string} [options.proxyIpHeader] Proxy IP header, defaults to X-Forwarded-For
|
|
46
|
+
* @param {number} [options.maxIpsCount] Max IPs read from proxy IP header, default to 0 (means infinity)
|
|
47
|
+
*
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
constructor(options) {
|
|
51
|
+
super();
|
|
52
|
+
options = options || {};
|
|
53
|
+
this.proxy = options.proxy || false;
|
|
54
|
+
this.subdomainOffset = options.subdomainOffset || 2;
|
|
55
|
+
this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For';
|
|
56
|
+
this.maxIpsCount = options.maxIpsCount || 0;
|
|
57
|
+
this.env = options.env || process.env.NODE_ENV || 'development';
|
|
58
|
+
if (options.keys) this.keys = options.keys;
|
|
59
|
+
this.middleware = [];
|
|
60
|
+
this.context = Object.create(context);
|
|
61
|
+
this.request = Object.create(request);
|
|
62
|
+
this.response = Object.create(response);
|
|
63
|
+
// util.inspect.custom support for node 6+
|
|
64
|
+
/* istanbul ignore else */
|
|
65
|
+
if (util.inspect.custom) {
|
|
66
|
+
this[util.inspect.custom] = this.inspect;
|
|
67
|
+
}
|
|
68
|
+
if (options.asyncLocalStorage) {
|
|
69
|
+
const { AsyncLocalStorage } = require('async_hooks');
|
|
70
|
+
assert(AsyncLocalStorage, 'Requires node 12.17.0 or higher to enable asyncLocalStorage');
|
|
71
|
+
this.ctxStorage = new AsyncLocalStorage();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Shorthand for:
|
|
77
|
+
*
|
|
78
|
+
* http.createServer(app.callback()).listen(...)
|
|
79
|
+
*
|
|
80
|
+
* @param {Mixed} ...
|
|
81
|
+
* @return {Server}
|
|
82
|
+
* @api public
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
listen(...args) {
|
|
86
|
+
debug('listen');
|
|
87
|
+
const server = http.createServer(this.callback());
|
|
88
|
+
return server.listen(...args);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Return JSON representation.
|
|
93
|
+
* We only bother showing settings.
|
|
94
|
+
*
|
|
95
|
+
* @return {Object}
|
|
96
|
+
* @api public
|
|
97
|
+
*/
|
|
98
|
+
|
|
99
|
+
toJSON() {
|
|
100
|
+
return only(this, [
|
|
101
|
+
'subdomainOffset',
|
|
102
|
+
'proxy',
|
|
103
|
+
'env'
|
|
104
|
+
]);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Inspect implementation.
|
|
109
|
+
*
|
|
110
|
+
* @return {Object}
|
|
111
|
+
* @api public
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
inspect() {
|
|
115
|
+
return this.toJSON();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Use the given middleware `fn`.
|
|
120
|
+
*
|
|
121
|
+
* Old-style middleware will be converted.
|
|
122
|
+
*
|
|
123
|
+
* @param {Function} fn
|
|
124
|
+
* @return {Application} self
|
|
125
|
+
* @api public
|
|
126
|
+
*/
|
|
127
|
+
|
|
128
|
+
use(fn) {
|
|
129
|
+
if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');
|
|
130
|
+
if (isGeneratorFunction(fn)) {
|
|
131
|
+
deprecate('Support for generators will be removed in v3. ' +
|
|
132
|
+
'See the documentation for examples of how to convert old middleware ' +
|
|
133
|
+
'https://github.com/koajs/koa/blob/master/docs/migration.md');
|
|
134
|
+
fn = convert(fn);
|
|
135
|
+
}
|
|
136
|
+
debug('use %s', fn._name || fn.name || '-');
|
|
137
|
+
this.middleware.push(fn);
|
|
138
|
+
return this;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Return a request handler callback
|
|
143
|
+
* for node's native http server.
|
|
144
|
+
*
|
|
145
|
+
* @return {Function}
|
|
146
|
+
* @api public
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
callback() {
|
|
150
|
+
const fn = compose(this.middleware);
|
|
151
|
+
|
|
152
|
+
if (!this.listenerCount('error')) this.on('error', this.onerror);
|
|
153
|
+
|
|
154
|
+
const handleRequest = (req, res) => {
|
|
155
|
+
const ctx = this.createContext(req, res);
|
|
156
|
+
if (!this.ctxStorage) {
|
|
157
|
+
return this.handleRequest(ctx, fn);
|
|
158
|
+
}
|
|
159
|
+
return this.ctxStorage.run(ctx, async() => {
|
|
160
|
+
return await this.handleRequest(ctx, fn);
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
return handleRequest;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* return currnect contenxt from async local storage
|
|
169
|
+
*/
|
|
170
|
+
get currentContext() {
|
|
171
|
+
if (this.ctxStorage) return this.ctxStorage.getStore();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Handle request in callback.
|
|
176
|
+
*
|
|
177
|
+
* @api private
|
|
178
|
+
*/
|
|
179
|
+
|
|
180
|
+
handleRequest(ctx, fnMiddleware) {
|
|
181
|
+
const res = ctx.res;
|
|
182
|
+
res.statusCode = 404;
|
|
183
|
+
const onerror = err => ctx.onerror(err);
|
|
184
|
+
const handleResponse = () => respond(ctx);
|
|
185
|
+
onFinished(res, onerror);
|
|
186
|
+
return fnMiddleware(ctx).then(handleResponse).catch(onerror);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Initialize a new context.
|
|
191
|
+
*
|
|
192
|
+
* @api private
|
|
193
|
+
*/
|
|
194
|
+
|
|
195
|
+
createContext(req, res) {
|
|
196
|
+
const context = Object.create(this.context);
|
|
197
|
+
const request = context.request = Object.create(this.request);
|
|
198
|
+
const response = context.response = Object.create(this.response);
|
|
199
|
+
context.app = request.app = response.app = this;
|
|
200
|
+
context.req = request.req = response.req = req;
|
|
201
|
+
context.res = request.res = response.res = res;
|
|
202
|
+
request.ctx = response.ctx = context;
|
|
203
|
+
request.response = response;
|
|
204
|
+
response.request = request;
|
|
205
|
+
context.originalUrl = request.originalUrl = req.url;
|
|
206
|
+
context.state = {};
|
|
207
|
+
return context;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Default error handler.
|
|
212
|
+
*
|
|
213
|
+
* @param {Error} err
|
|
214
|
+
* @api private
|
|
215
|
+
*/
|
|
216
|
+
|
|
217
|
+
onerror(err) {
|
|
218
|
+
// When dealing with cross-globals a normal `instanceof` check doesn't work properly.
|
|
219
|
+
// See https://github.com/koajs/koa/issues/1466
|
|
220
|
+
// We can probably remove it once jest fixes https://github.com/facebook/jest/issues/2549.
|
|
221
|
+
const isNativeError =
|
|
222
|
+
Object.prototype.toString.call(err) === '[object Error]' ||
|
|
223
|
+
err instanceof Error;
|
|
224
|
+
if (!isNativeError) throw new TypeError(util.format('non-error thrown: %j', err));
|
|
225
|
+
|
|
226
|
+
if (404 === err.status || err.expose) return;
|
|
227
|
+
if (this.silent) return;
|
|
228
|
+
|
|
229
|
+
const msg = err.stack || err.toString();
|
|
230
|
+
console.error(`\n${msg.replace(/^/gm, ' ')}\n`);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Help TS users comply to CommonJS, ESM, bundler mismatch.
|
|
235
|
+
* @see https://github.com/koajs/koa/issues/1513
|
|
236
|
+
*/
|
|
237
|
+
|
|
238
|
+
static get default() {
|
|
239
|
+
return Application;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
createAsyncCtxStorageMiddleware() {
|
|
243
|
+
const app = this;
|
|
244
|
+
return async function asyncCtxStorage(ctx, next) {
|
|
245
|
+
await app.ctxStorage.run(ctx, async() => {
|
|
246
|
+
return await next();
|
|
247
|
+
});
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Response helper.
|
|
254
|
+
*/
|
|
255
|
+
|
|
256
|
+
function respond(ctx) {
|
|
257
|
+
// allow bypassing koa
|
|
258
|
+
if (false === ctx.respond) return;
|
|
259
|
+
|
|
260
|
+
if (!ctx.writable) return;
|
|
261
|
+
|
|
262
|
+
const res = ctx.res;
|
|
263
|
+
let body = ctx.body;
|
|
264
|
+
const code = ctx.status;
|
|
265
|
+
|
|
266
|
+
// ignore body
|
|
267
|
+
if (statuses.empty[code]) {
|
|
268
|
+
// strip headers
|
|
269
|
+
ctx.body = null;
|
|
270
|
+
return res.end();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if ('HEAD' === ctx.method) {
|
|
274
|
+
if (!res.headersSent && !ctx.response.has('Content-Length')) {
|
|
275
|
+
const { length } = ctx.response;
|
|
276
|
+
if (Number.isInteger(length)) ctx.length = length;
|
|
277
|
+
}
|
|
278
|
+
return res.end();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// status body
|
|
282
|
+
if (null == body) {
|
|
283
|
+
if (ctx.response._explicitNullBody) {
|
|
284
|
+
ctx.response.remove('Content-Type');
|
|
285
|
+
ctx.response.remove('Transfer-Encoding');
|
|
286
|
+
return res.end();
|
|
287
|
+
}
|
|
288
|
+
if (ctx.req.httpVersionMajor >= 2) {
|
|
289
|
+
body = String(code);
|
|
290
|
+
} else {
|
|
291
|
+
body = ctx.message || String(code);
|
|
292
|
+
}
|
|
293
|
+
if (!res.headersSent) {
|
|
294
|
+
ctx.type = 'text';
|
|
295
|
+
ctx.length = Buffer.byteLength(body);
|
|
296
|
+
}
|
|
297
|
+
return res.end(body);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// responses
|
|
301
|
+
if (Buffer.isBuffer(body)) return res.end(body);
|
|
302
|
+
if ('string' === typeof body) return res.end(body);
|
|
303
|
+
if (body instanceof Stream) return body.pipe(res);
|
|
304
|
+
|
|
305
|
+
// body: json
|
|
306
|
+
body = JSON.stringify(body);
|
|
307
|
+
if (!res.headersSent) {
|
|
308
|
+
ctx.length = Buffer.byteLength(body);
|
|
309
|
+
}
|
|
310
|
+
res.end(body);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Make HttpError available to consumers of the library so that consumers don't
|
|
315
|
+
* have a direct dependency upon `http-errors`
|
|
316
|
+
*/
|
|
317
|
+
|
|
318
|
+
module.exports.HttpError = HttpError;
|