koa-files 2.3.6 → 2.3.8

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  >
6
6
  > [![NPM Version][npm-image]][npm-url]
7
7
  > [![Download Status][download-image]][npm-url]
8
- > [![Snyk Vulnerabilities][snyk-image]][snyk-url]
8
+ > [![Languages Status][languages-image]][github-url]
9
9
  > ![Node Version][node-image]
10
10
 
11
11
  ## Installation
@@ -17,13 +17,13 @@ $ npm install koa-files
17
17
  ## API
18
18
 
19
19
  ```js
20
- const Koa = require('koa');
21
- const server = require('koa-files');
20
+ import Koa from 'koa';
21
+ import files from 'koa-files';
22
22
 
23
23
  const app = new Koa();
24
24
 
25
25
  // Static files server
26
- app.use(server(root, options));
26
+ app.use(files(root, options));
27
27
  ```
28
28
 
29
29
  - `root` root directory string. nothing above this root directory can be served.
@@ -64,10 +64,8 @@ app.use(server(root, options));
64
64
  * @author nuintun
65
65
  */
66
66
 
67
- 'use strict';
68
-
69
- const Koa = require('koa');
70
- const server = require('koa-files');
67
+ import Koa from 'koa';
68
+ import files from 'koa-files';
71
69
 
72
70
  const app = new Koa();
73
71
  const port = process.env.PORT || 80;
@@ -82,7 +80,7 @@ function httpError(error) {
82
80
  }
83
81
 
84
82
  // Static files server
85
- app.use(server('tests', { cacheControl: 'public, max-age=31557600' }));
83
+ app.use(files('tests', { cacheControl: 'public, max-age=31557600' }));
86
84
 
87
85
  // Listen error event
88
86
  app.on('error', error => !httpError(error) && console.error(error));
@@ -102,6 +100,6 @@ MIT
102
100
  [npm-image]: https://img.shields.io/npm/v/koa-files.svg?style=flat-square
103
101
  [npm-url]: https://www.npmjs.org/package/koa-files
104
102
  [download-image]: https://img.shields.io/npm/dm/koa-files.svg?style=flat-square
105
- [snyk-image]: https://img.shields.io/snyk/vulnerabilities/github/nuintun/koa-files.svg?style=flat-square
106
- [snyk-url]: https://snyk.io/test/github/nuintun/koa-files
103
+ [languages-image]: https://img.shields.io/github/languages/top/nuintun/koa-files?style=flat-square
104
+ [github-url]: https://github.com/nuintun/koa-files
107
105
  [node-image]: https://img.shields.io/node/v/koa-files.svg?style=flat-square
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @package koa-files
3
3
  * @license MIT
4
- * @version 2.3.6
4
+ * @version 2.3.8
5
5
  * @author nuintun <nuintun@qq.com>
6
6
  * @description A static files serving middleware for koa.
7
7
  * @see https://github.com/nuintun/koa-files#readme
@@ -27,27 +27,29 @@ const fs__default = /*#__PURE__*/ _interopDefault(fs);
27
27
  const parseRange__default = /*#__PURE__*/ _interopDefault(parseRange);
28
28
 
29
29
  /**
30
- * @module Send
30
+ * @module Files
31
31
  * @license MIT
32
32
  * @author nuintun
33
33
  */
34
34
  /**
35
- * @class Send
35
+ * @class Files
36
36
  */
37
- class Send {
37
+ class Files {
38
38
  /**
39
39
  * @constructor
40
- * @param {string} root
41
- * @param {Options} options
40
+ * @description Create files service
41
+ * @param root Files service root
42
+ * @param options Files service options
42
43
  */
43
44
  constructor(root, options = {}) {
44
45
  this.options = options;
45
46
  this.root = utils.unixify(path.resolve(root));
46
47
  }
47
48
  /**
49
+ * @private
48
50
  * @method isConditionalGET
49
- * @param {Context} context
50
- * @returns {boolean}
51
+ * @description Check if request is conditional GET
52
+ * @param context Koa context
51
53
  */
52
54
  isConditionalGET(context) {
53
55
  const { request } = context;
@@ -59,9 +61,10 @@ class Send {
59
61
  );
60
62
  }
61
63
  /**
64
+ * @private
62
65
  * @method isPreconditionFailure
63
- * @param {Context} context
64
- * @returns {boolean}
66
+ * @description Check if request precondition failure
67
+ * @param context Koa context
65
68
  */
66
69
  isPreconditionFailure(context) {
67
70
  const { request, response } = context;
@@ -80,9 +83,10 @@ class Send {
80
83
  return false;
81
84
  }
82
85
  /**
86
+ * @private
83
87
  * @method isRangeFresh
84
- * @param {Context} context
85
- * @returns {boolean}
88
+ * @description Check if request range fresh
89
+ * @param context Koa context
86
90
  */
87
91
  isRangeFresh(context) {
88
92
  const { request, response } = context;
@@ -101,19 +105,21 @@ class Send {
101
105
  return Date.parse(lastModified) <= Date.parse(ifRange);
102
106
  }
103
107
  /**
108
+ * @private
104
109
  * @method isIgnore
105
- * @param {string} path
106
- * @returns {boolean}
110
+ * @description Check if path is ignore
111
+ * @param path File path
107
112
  */
108
113
  isIgnore(path) {
109
114
  const { ignore } = this.options;
110
115
  return (typeof ignore === 'function' ? ignore(path) : false) === true;
111
116
  }
112
117
  /**
118
+ * @private
113
119
  * @method parseRange
114
- * @param {Context} context
115
- * @param {Stats} stats
116
- * @returns {Ranges}
120
+ * @description Parse range
121
+ * @param context Koa context
122
+ * @param stats File stats
117
123
  */
118
124
  parseRange(context, stats) {
119
125
  const { size } = stats;
@@ -178,10 +184,12 @@ class Send {
178
184
  return ranges.length ? ranges : [{ start: 0 }];
179
185
  }
180
186
  /**
187
+ * @private
181
188
  * @method setupHeaders
182
- * @param {Context} context
183
- * @param {string} path
184
- * @param {Stats} stats
189
+ * @description Setup headers
190
+ * @param context Koa context
191
+ * @param path File path
192
+ * @param stats File stats
185
193
  */
186
194
  setupHeaders(context, path$1, stats) {
187
195
  const { options } = this;
@@ -213,12 +221,13 @@ class Send {
213
221
  }
214
222
  }
215
223
  /**
224
+ * @private
216
225
  * @method read
217
- * @param {string} path
218
- * @param {Range} range
219
- * @param {PassThrough} buffer
220
- * @param {boolean} end
221
- * @returns {Promise<true>}
226
+ * @description Read file
227
+ * @param path File path
228
+ * @param range Read range
229
+ * @param buffer Destination stream
230
+ * @param end Is destory destination stream after read
222
231
  */
223
232
  read(path, range, buffer, end) {
224
233
  return new Promise((resolve, reject) => {
@@ -261,14 +270,16 @@ class Send {
261
270
  });
262
271
  }
263
272
  /**
273
+ * @private
264
274
  * @method send
265
- * @param {Context} context
266
- * @param {string} path
267
- * @param {Range[]} ranges
275
+ * @description Send file
276
+ * @param context Koa context
277
+ * @param path File path
278
+ * @param ranges Read ranges
268
279
  */
269
280
  async send(context, path, ranges) {
270
- // Ranges count
271
- let count = ranges.length;
281
+ // Ranges length
282
+ let { length } = ranges;
272
283
  // Set stream body, highWaterMark 64kb
273
284
  const stream$1 = new stream.PassThrough({ highWaterMark: 65536 });
274
285
  // Set response body
@@ -276,7 +287,7 @@ class Send {
276
287
  // Read file ranges
277
288
  try {
278
289
  for (const range of ranges) {
279
- await this.read(path, range, stream$1, --count === 0);
290
+ await this.read(path, range, stream$1, --length === 0);
280
291
  }
281
292
  } catch (error) {
282
293
  // End stream when read exception
@@ -284,9 +295,10 @@ class Send {
284
295
  }
285
296
  }
286
297
  /**
298
+ * @public
287
299
  * @method response
288
- * @param {Context} context
289
- * @returns {Promise<boolean>}
300
+ * @description Response to koa context
301
+ * @param context Koa context
290
302
  */
291
303
  async response(context) {
292
304
  const { root } = this;
@@ -374,4 +386,4 @@ class Send {
374
386
  }
375
387
  }
376
388
 
377
- module.exports = Send;
389
+ module.exports = Files;
package/cjs/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @package koa-files
3
3
  * @license MIT
4
- * @version 2.3.6
4
+ * @version 2.3.8
5
5
  * @author nuintun <nuintun@qq.com>
6
6
  * @description A static files serving middleware for koa.
7
7
  * @see https://github.com/nuintun/koa-files#readme
@@ -9,7 +9,7 @@
9
9
 
10
10
  'use strict';
11
11
 
12
- const Send = require('./Send.cjs');
12
+ const Files = require('./Files.cjs');
13
13
 
14
14
  /**
15
15
  * @module index
@@ -22,15 +22,15 @@ const Send = require('./Send.cjs');
22
22
  * @param {Options} options
23
23
  */
24
24
  function server(root, options) {
25
- const send = new Send(root, options);
25
+ const files = new Files(root, options);
26
26
  if (options && options.defer) {
27
27
  return async (context, next) => {
28
28
  await next();
29
- await send.response(context);
29
+ await files.response(context);
30
30
  };
31
31
  }
32
32
  return async (context, next) => {
33
- if (!(await send.response(context))) {
33
+ if (!(await files.response(context))) {
34
34
  await next();
35
35
  }
36
36
  };
package/cjs/utils.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @package koa-files
3
3
  * @license MIT
4
- * @version 2.3.6
4
+ * @version 2.3.8
5
5
  * @author nuintun <nuintun@qq.com>
6
6
  * @description A static files serving middleware for koa.
7
7
  * @see https://github.com/nuintun/koa-files#readme
@@ -26,10 +26,9 @@ const fs__default = /*#__PURE__*/ _interopDefault(fs);
26
26
  const CHARS = Array.from('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
27
27
  /**
28
28
  * @function isOutRoot
29
- * @description Test path is out of bound of root
30
- * @param {string} path
31
- * @param {string} root
32
- * @returns {boolean}
29
+ * @description Check if path is out of root
30
+ * @param path The path to check
31
+ * @param root The root path
33
32
  */
34
33
  function isOutRoot(path$1, root) {
35
34
  path$1 = path.relative(root, path$1);
@@ -37,18 +36,16 @@ function isOutRoot(path$1, root) {
37
36
  }
38
37
  /**
39
38
  * @function unixify
40
- * @description Convert path separators to posix/unix-style forward slashes
41
- * @param {string} path
42
- * @returns {string}
39
+ * @description Convert path to unix style
40
+ * @param path The path to convert
43
41
  */
44
42
  function unixify(path) {
45
43
  return path.replace(/\\/g, '/');
46
44
  }
47
45
  /**
48
46
  * @function decodeURI
49
- * @description Decode URI component.
50
- * @param {string} URI
51
- * @returns {string|-1}
47
+ * @description Decode URI component
48
+ * @param URI The URI to decode
52
49
  */
53
50
  function decodeURI(URI) {
54
51
  try {
@@ -59,8 +56,7 @@ function decodeURI(URI) {
59
56
  }
60
57
  /**
61
58
  * @function boundaryGenerator
62
- * @description Create boundary
63
- * @returns {string}
59
+ * @description Generate a boundary
64
60
  */
65
61
  function boundaryGenerator() {
66
62
  let boundary = '';
@@ -73,8 +69,8 @@ function boundaryGenerator() {
73
69
  }
74
70
  /**
75
71
  * @function fstat
76
- * @param {string} path
77
- * @returns {Promise<Stats>}
72
+ * @description Get file stats
73
+ * @param path The file path
78
74
  */
79
75
  function fstat(path) {
80
76
  return new Promise((resolve, reject) => {
@@ -85,16 +81,16 @@ function fstat(path) {
85
81
  }
86
82
  /**
87
83
  * @function hasTrailingSlash
88
- * @param {string} path
89
- * @returns {boolean}
84
+ * @description Check if path has trailing slash
85
+ * @param path The path to check
90
86
  */
91
87
  function hasTrailingSlash(path) {
92
88
  return /\/$/.test(path);
93
89
  }
94
90
  /**
95
91
  * @function parseTokens
96
- * @description Parse a HTTP tokens.
97
- * @param {string[]} value
92
+ * @description Parse HTTP tokens
93
+ * @param value The tokens value string
98
94
  */
99
95
  function parseTokens(value) {
100
96
  let end = 0;
@@ -123,25 +119,25 @@ function parseTokens(value) {
123
119
  tokens.push(value.substring(start, end));
124
120
  return tokens;
125
121
  }
122
+ /**
123
+ * @function isETag
124
+ * @description Check if etag is valid
125
+ * @param value The value to check
126
+ */
127
+ function isETag(value) {
128
+ return /^(?:W\/)?"[\s\S]+"$/.test(value);
129
+ }
126
130
  /**
127
131
  * @function isETagFresh
128
- * @param {string} match
129
- * @param {string} etag
130
- * @returns {boolean}
132
+ * @description Check if etag is fresh
133
+ * @param match The match value
134
+ * @param etag The etag value
131
135
  */
132
136
  function isETagFresh(match, etag) {
133
137
  return parseTokens(match).some(match => {
134
138
  return match === etag || match === 'W/' + etag || 'W/' + match === etag;
135
139
  });
136
140
  }
137
- /**
138
- * @function isETag
139
- * @param {string} etag
140
- * @returns {boolean}
141
- */
142
- function isETag(etag) {
143
- return /(?:W\/)?"(?:[ !#-\x7E\x80-\xFF]*|\r\n[\t ]|\\.)*"/.test(etag);
144
- }
145
141
 
146
142
  exports.boundaryGenerator = boundaryGenerator;
147
143
  exports.decodeURI = decodeURI;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @package koa-files
3
3
  * @license MIT
4
- * @version 2.3.6
4
+ * @version 2.3.8
5
5
  * @author nuintun <nuintun@qq.com>
6
6
  * @description A static files serving middleware for koa.
7
7
  * @see https://github.com/nuintun/koa-files#readme
@@ -16,27 +16,29 @@ import { resolve, extname, join } from 'path';
16
16
  import { unixify, isETagFresh, isETag, boundaryGenerator, decodeURI, isOutRoot, fstat, hasTrailingSlash } from './utils.js';
17
17
 
18
18
  /**
19
- * @module Send
19
+ * @module Files
20
20
  * @license MIT
21
21
  * @author nuintun
22
22
  */
23
23
  /**
24
- * @class Send
24
+ * @class Files
25
25
  */
26
- class Send {
26
+ class Files {
27
27
  /**
28
28
  * @constructor
29
- * @param {string} root
30
- * @param {Options} options
29
+ * @description Create files service
30
+ * @param root Files service root
31
+ * @param options Files service options
31
32
  */
32
33
  constructor(root, options = {}) {
33
34
  this.options = options;
34
35
  this.root = unixify(resolve(root));
35
36
  }
36
37
  /**
38
+ * @private
37
39
  * @method isConditionalGET
38
- * @param {Context} context
39
- * @returns {boolean}
40
+ * @description Check if request is conditional GET
41
+ * @param context Koa context
40
42
  */
41
43
  isConditionalGET(context) {
42
44
  const { request } = context;
@@ -48,9 +50,10 @@ class Send {
48
50
  );
49
51
  }
50
52
  /**
53
+ * @private
51
54
  * @method isPreconditionFailure
52
- * @param {Context} context
53
- * @returns {boolean}
55
+ * @description Check if request precondition failure
56
+ * @param context Koa context
54
57
  */
55
58
  isPreconditionFailure(context) {
56
59
  const { request, response } = context;
@@ -69,9 +72,10 @@ class Send {
69
72
  return false;
70
73
  }
71
74
  /**
75
+ * @private
72
76
  * @method isRangeFresh
73
- * @param {Context} context
74
- * @returns {boolean}
77
+ * @description Check if request range fresh
78
+ * @param context Koa context
75
79
  */
76
80
  isRangeFresh(context) {
77
81
  const { request, response } = context;
@@ -90,19 +94,21 @@ class Send {
90
94
  return Date.parse(lastModified) <= Date.parse(ifRange);
91
95
  }
92
96
  /**
97
+ * @private
93
98
  * @method isIgnore
94
- * @param {string} path
95
- * @returns {boolean}
99
+ * @description Check if path is ignore
100
+ * @param path File path
96
101
  */
97
102
  isIgnore(path) {
98
103
  const { ignore } = this.options;
99
104
  return (typeof ignore === 'function' ? ignore(path) : false) === true;
100
105
  }
101
106
  /**
107
+ * @private
102
108
  * @method parseRange
103
- * @param {Context} context
104
- * @param {Stats} stats
105
- * @returns {Ranges}
109
+ * @description Parse range
110
+ * @param context Koa context
111
+ * @param stats File stats
106
112
  */
107
113
  parseRange(context, stats) {
108
114
  const { size } = stats;
@@ -167,10 +173,12 @@ class Send {
167
173
  return ranges.length ? ranges : [{ start: 0 }];
168
174
  }
169
175
  /**
176
+ * @private
170
177
  * @method setupHeaders
171
- * @param {Context} context
172
- * @param {string} path
173
- * @param {Stats} stats
178
+ * @description Setup headers
179
+ * @param context Koa context
180
+ * @param path File path
181
+ * @param stats File stats
174
182
  */
175
183
  setupHeaders(context, path, stats) {
176
184
  const { options } = this;
@@ -202,12 +210,13 @@ class Send {
202
210
  }
203
211
  }
204
212
  /**
213
+ * @private
205
214
  * @method read
206
- * @param {string} path
207
- * @param {Range} range
208
- * @param {PassThrough} buffer
209
- * @param {boolean} end
210
- * @returns {Promise<true>}
215
+ * @description Read file
216
+ * @param path File path
217
+ * @param range Read range
218
+ * @param buffer Destination stream
219
+ * @param end Is destory destination stream after read
211
220
  */
212
221
  read(path, range, buffer, end) {
213
222
  return new Promise((resolve, reject) => {
@@ -250,14 +259,16 @@ class Send {
250
259
  });
251
260
  }
252
261
  /**
262
+ * @private
253
263
  * @method send
254
- * @param {Context} context
255
- * @param {string} path
256
- * @param {Range[]} ranges
264
+ * @description Send file
265
+ * @param context Koa context
266
+ * @param path File path
267
+ * @param ranges Read ranges
257
268
  */
258
269
  async send(context, path, ranges) {
259
- // Ranges count
260
- let count = ranges.length;
270
+ // Ranges length
271
+ let { length } = ranges;
261
272
  // Set stream body, highWaterMark 64kb
262
273
  const stream = new PassThrough({ highWaterMark: 65536 });
263
274
  // Set response body
@@ -265,7 +276,7 @@ class Send {
265
276
  // Read file ranges
266
277
  try {
267
278
  for (const range of ranges) {
268
- await this.read(path, range, stream, --count === 0);
279
+ await this.read(path, range, stream, --length === 0);
269
280
  }
270
281
  } catch (error) {
271
282
  // End stream when read exception
@@ -273,9 +284,10 @@ class Send {
273
284
  }
274
285
  }
275
286
  /**
287
+ * @public
276
288
  * @method response
277
- * @param {Context} context
278
- * @returns {Promise<boolean>}
289
+ * @description Response to koa context
290
+ * @param context Koa context
279
291
  */
280
292
  async response(context) {
281
293
  const { root } = this;
@@ -363,4 +375,4 @@ class Send {
363
375
  }
364
376
  }
365
377
 
366
- export { Send as default };
378
+ export { Files as default };
package/esm/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * @package koa-files
3
3
  * @license MIT
4
- * @version 2.3.6
4
+ * @version 2.3.8
5
5
  * @author nuintun <nuintun@qq.com>
6
6
  * @description A static files serving middleware for koa.
7
7
  * @see https://github.com/nuintun/koa-files#readme
8
8
  */
9
9
 
10
- import Send from './Send.js';
10
+ import Files from './Files.js';
11
11
 
12
12
  /**
13
13
  * @module index
@@ -20,15 +20,15 @@ import Send from './Send.js';
20
20
  * @param {Options} options
21
21
  */
22
22
  function server(root, options) {
23
- const send = new Send(root, options);
23
+ const files = new Files(root, options);
24
24
  if (options && options.defer) {
25
25
  return async (context, next) => {
26
26
  await next();
27
- await send.response(context);
27
+ await files.response(context);
28
28
  };
29
29
  }
30
30
  return async (context, next) => {
31
- if (!(await send.response(context))) {
31
+ if (!(await files.response(context))) {
32
32
  await next();
33
33
  }
34
34
  };
package/esm/utils.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @package koa-files
3
3
  * @license MIT
4
- * @version 2.3.6
4
+ * @version 2.3.8
5
5
  * @author nuintun <nuintun@qq.com>
6
6
  * @description A static files serving middleware for koa.
7
7
  * @see https://github.com/nuintun/koa-files#readme
@@ -18,10 +18,9 @@ import { relative, isAbsolute } from 'path';
18
18
  const CHARS = Array.from('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
19
19
  /**
20
20
  * @function isOutRoot
21
- * @description Test path is out of bound of root
22
- * @param {string} path
23
- * @param {string} root
24
- * @returns {boolean}
21
+ * @description Check if path is out of root
22
+ * @param path The path to check
23
+ * @param root The root path
25
24
  */
26
25
  function isOutRoot(path, root) {
27
26
  path = relative(root, path);
@@ -29,18 +28,16 @@ function isOutRoot(path, root) {
29
28
  }
30
29
  /**
31
30
  * @function unixify
32
- * @description Convert path separators to posix/unix-style forward slashes
33
- * @param {string} path
34
- * @returns {string}
31
+ * @description Convert path to unix style
32
+ * @param path The path to convert
35
33
  */
36
34
  function unixify(path) {
37
35
  return path.replace(/\\/g, '/');
38
36
  }
39
37
  /**
40
38
  * @function decodeURI
41
- * @description Decode URI component.
42
- * @param {string} URI
43
- * @returns {string|-1}
39
+ * @description Decode URI component
40
+ * @param URI The URI to decode
44
41
  */
45
42
  function decodeURI(URI) {
46
43
  try {
@@ -51,8 +48,7 @@ function decodeURI(URI) {
51
48
  }
52
49
  /**
53
50
  * @function boundaryGenerator
54
- * @description Create boundary
55
- * @returns {string}
51
+ * @description Generate a boundary
56
52
  */
57
53
  function boundaryGenerator() {
58
54
  let boundary = '';
@@ -65,8 +61,8 @@ function boundaryGenerator() {
65
61
  }
66
62
  /**
67
63
  * @function fstat
68
- * @param {string} path
69
- * @returns {Promise<Stats>}
64
+ * @description Get file stats
65
+ * @param path The file path
70
66
  */
71
67
  function fstat(path) {
72
68
  return new Promise((resolve, reject) => {
@@ -77,16 +73,16 @@ function fstat(path) {
77
73
  }
78
74
  /**
79
75
  * @function hasTrailingSlash
80
- * @param {string} path
81
- * @returns {boolean}
76
+ * @description Check if path has trailing slash
77
+ * @param path The path to check
82
78
  */
83
79
  function hasTrailingSlash(path) {
84
80
  return /\/$/.test(path);
85
81
  }
86
82
  /**
87
83
  * @function parseTokens
88
- * @description Parse a HTTP tokens.
89
- * @param {string[]} value
84
+ * @description Parse HTTP tokens
85
+ * @param value The tokens value string
90
86
  */
91
87
  function parseTokens(value) {
92
88
  let end = 0;
@@ -115,24 +111,24 @@ function parseTokens(value) {
115
111
  tokens.push(value.substring(start, end));
116
112
  return tokens;
117
113
  }
114
+ /**
115
+ * @function isETag
116
+ * @description Check if etag is valid
117
+ * @param value The value to check
118
+ */
119
+ function isETag(value) {
120
+ return /^(?:W\/)?"[\s\S]+"$/.test(value);
121
+ }
118
122
  /**
119
123
  * @function isETagFresh
120
- * @param {string} match
121
- * @param {string} etag
122
- * @returns {boolean}
124
+ * @description Check if etag is fresh
125
+ * @param match The match value
126
+ * @param etag The etag value
123
127
  */
124
128
  function isETagFresh(match, etag) {
125
129
  return parseTokens(match).some(match => {
126
130
  return match === etag || match === 'W/' + etag || 'W/' + match === etag;
127
131
  });
128
132
  }
129
- /**
130
- * @function isETag
131
- * @param {string} etag
132
- * @returns {boolean}
133
- */
134
- function isETag(etag) {
135
- return /(?:W\/)?"(?:[ !#-\x7E\x80-\xFF]*|\r\n[\t ]|\\.)*"/.test(etag);
136
- }
137
133
 
138
134
  export { boundaryGenerator, decodeURI, fstat, hasTrailingSlash, isETag, isETagFresh, isOutRoot, parseTokens, unixify };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koa-files",
3
- "version": "2.3.6",
3
+ "version": "2.3.8",
4
4
  "description": "A static files serving middleware for koa.",
5
5
  "type": "module",
6
6
  "main": "cjs/index.cjs",
@@ -8,7 +8,8 @@
8
8
  "types": "types/index.d.ts",
9
9
  "exports": {
10
10
  "import": "./esm/index.js",
11
- "require": "./cjs/index.cjs"
11
+ "require": "./cjs/index.cjs",
12
+ "types": "./types/index.d.ts"
12
13
  },
13
14
  "files": [
14
15
  "cjs",
@@ -44,10 +45,10 @@
44
45
  "test": "node tests",
45
46
  "lint": "tsc --noEmit",
46
47
  "clean": "node tools/clean.js",
47
- "format": "prettier --write .",
48
48
  "prepublishOnly": "npm run build",
49
49
  "build:cjs": "rollup -c tools/rollup.cjs.js",
50
50
  "build:esm": "rollup -c tools/rollup.esm.js",
51
+ "format": "prettier --write . --ignore-path .prettierignore",
51
52
  "build": "npm run clean && npm run build:main && npm run format",
52
53
  "build:main": "npm run build:cjs && npm run build:esm && npm run build:types",
53
54
  "build:types": "tsc --declaration --emitDeclarationOnly --declarationDir types"
@@ -56,20 +57,20 @@
56
57
  "destroy": "^1.2.0",
57
58
  "etag": "^1.8.1",
58
59
  "range-parser": "^1.2.1",
59
- "tslib": "^2.5.0"
60
+ "tslib": "^2.6.2"
60
61
  },
61
62
  "devDependencies": {
62
- "@rollup/plugin-typescript": "^11.0.0",
63
- "@types/destroy": "^1.0.0",
64
- "@types/etag": "^1.8.1",
65
- "@types/koa": "^2.13.5",
66
- "@types/range-parser": "^1.2.4",
67
- "koa": "^2.14.1",
68
- "magic-string": "^0.30.0",
69
- "prettier": "^2.8.6",
70
- "rimraf": "^4.4.0",
71
- "rollup": "^3.20.0",
72
- "typescript": "^5.0.2"
63
+ "@rollup/plugin-typescript": "^11.1.6",
64
+ "@types/destroy": "^1.0.3",
65
+ "@types/etag": "^1.8.3",
66
+ "@types/koa": "^2.15.0",
67
+ "@types/range-parser": "^1.2.7",
68
+ "koa": "^2.15.1",
69
+ "magic-string": "^0.30.8",
70
+ "prettier": "^3.2.5",
71
+ "rimraf": "^5.0.5",
72
+ "rollup": "^4.13.0",
73
+ "typescript": "^5.4.2"
73
74
  },
74
75
  "peerDependencies": {
75
76
  "koa": "^2.0.0"
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @module Files
3
+ * @license MIT
4
+ * @author nuintun
5
+ */
6
+ import { Context } from 'koa';
7
+ export interface Options {
8
+ etag?: boolean;
9
+ cacheControl?: string;
10
+ acceptRanges?: boolean;
11
+ lastModified?: boolean;
12
+ ignore?: (path: string) => boolean;
13
+ }
14
+ /**
15
+ * @class Files
16
+ */
17
+ export default class Files {
18
+ private root;
19
+ private options;
20
+ /**
21
+ * @constructor
22
+ * @description Create files service
23
+ * @param root Files service root
24
+ * @param options Files service options
25
+ */
26
+ constructor(root: string, options?: Options);
27
+ /**
28
+ * @private
29
+ * @method isConditionalGET
30
+ * @description Check if request is conditional GET
31
+ * @param context Koa context
32
+ */
33
+ private isConditionalGET;
34
+ /**
35
+ * @private
36
+ * @method isPreconditionFailure
37
+ * @description Check if request precondition failure
38
+ * @param context Koa context
39
+ */
40
+ private isPreconditionFailure;
41
+ /**
42
+ * @private
43
+ * @method isRangeFresh
44
+ * @description Check if request range fresh
45
+ * @param context Koa context
46
+ */
47
+ private isRangeFresh;
48
+ /**
49
+ * @private
50
+ * @method isIgnore
51
+ * @description Check if path is ignore
52
+ * @param path File path
53
+ */
54
+ private isIgnore;
55
+ /**
56
+ * @private
57
+ * @method parseRange
58
+ * @description Parse range
59
+ * @param context Koa context
60
+ * @param stats File stats
61
+ */
62
+ private parseRange;
63
+ /**
64
+ * @private
65
+ * @method setupHeaders
66
+ * @description Setup headers
67
+ * @param context Koa context
68
+ * @param path File path
69
+ * @param stats File stats
70
+ */
71
+ private setupHeaders;
72
+ /**
73
+ * @private
74
+ * @method read
75
+ * @description Read file
76
+ * @param path File path
77
+ * @param range Read range
78
+ * @param buffer Destination stream
79
+ * @param end Is destory destination stream after read
80
+ */
81
+ private read;
82
+ /**
83
+ * @private
84
+ * @method send
85
+ * @description Send file
86
+ * @param context Koa context
87
+ * @param path File path
88
+ * @param ranges Read ranges
89
+ */
90
+ private send;
91
+ /**
92
+ * @public
93
+ * @method response
94
+ * @description Response to koa context
95
+ * @param context Koa context
96
+ */
97
+ response(context: Context): Promise<boolean>;
98
+ }
package/types/index.d.ts CHANGED
@@ -4,8 +4,8 @@
4
4
  * @author nuintun
5
5
  */
6
6
  import { Middleware } from 'koa';
7
- import { Options as SendOptions } from './Send';
8
- export interface Options extends SendOptions {
7
+ import { Options as FilesOptions } from './Files';
8
+ export interface Options extends FilesOptions {
9
9
  defer?: boolean;
10
10
  }
11
11
  /**
package/types/utils.d.ts CHANGED
@@ -7,60 +7,56 @@
7
7
  import { Stats } from 'fs';
8
8
  /**
9
9
  * @function isOutRoot
10
- * @description Test path is out of bound of root
11
- * @param {string} path
12
- * @param {string} root
13
- * @returns {boolean}
10
+ * @description Check if path is out of root
11
+ * @param path The path to check
12
+ * @param root The root path
14
13
  */
15
14
  export declare function isOutRoot(path: string, root: string): boolean;
16
15
  /**
17
16
  * @function unixify
18
- * @description Convert path separators to posix/unix-style forward slashes
19
- * @param {string} path
20
- * @returns {string}
17
+ * @description Convert path to unix style
18
+ * @param path The path to convert
21
19
  */
22
20
  export declare function unixify(path: string): string;
23
21
  /**
24
22
  * @function decodeURI
25
- * @description Decode URI component.
26
- * @param {string} URI
27
- * @returns {string|-1}
23
+ * @description Decode URI component
24
+ * @param URI The URI to decode
28
25
  */
29
26
  export declare function decodeURI(URI: string): string | -1;
30
27
  /**
31
28
  * @function boundaryGenerator
32
- * @description Create boundary
33
- * @returns {string}
29
+ * @description Generate a boundary
34
30
  */
35
31
  export declare function boundaryGenerator(): string;
36
32
  /**
37
33
  * @function fstat
38
- * @param {string} path
39
- * @returns {Promise<Stats>}
34
+ * @description Get file stats
35
+ * @param path The file path
40
36
  */
41
37
  export declare function fstat(path: string): Promise<Stats>;
42
38
  /**
43
39
  * @function hasTrailingSlash
44
- * @param {string} path
45
- * @returns {boolean}
40
+ * @description Check if path has trailing slash
41
+ * @param path The path to check
46
42
  */
47
43
  export declare function hasTrailingSlash(path: string): boolean;
48
44
  /**
49
45
  * @function parseTokens
50
- * @description Parse a HTTP tokens.
51
- * @param {string[]} value
46
+ * @description Parse HTTP tokens
47
+ * @param value The tokens value string
52
48
  */
53
49
  export declare function parseTokens(value: string): string[];
54
50
  /**
55
- * @function isETagFresh
56
- * @param {string} match
57
- * @param {string} etag
58
- * @returns {boolean}
51
+ * @function isETag
52
+ * @description Check if etag is valid
53
+ * @param value The value to check
59
54
  */
60
- export declare function isETagFresh(match: string, etag: string): boolean;
55
+ export declare function isETag(value: string): boolean;
61
56
  /**
62
- * @function isETag
63
- * @param {string} etag
64
- * @returns {boolean}
57
+ * @function isETagFresh
58
+ * @description Check if etag is fresh
59
+ * @param match The match value
60
+ * @param etag The etag value
65
61
  */
66
- export declare function isETag(etag: string): boolean;
62
+ export declare function isETagFresh(match: string, etag: string): boolean;
package/types/Send.d.ts DELETED
@@ -1,86 +0,0 @@
1
- /**
2
- * @module Send
3
- * @license MIT
4
- * @author nuintun
5
- */
6
- import { Context } from 'koa';
7
- export interface Options {
8
- etag?: boolean;
9
- cacheControl?: string;
10
- acceptRanges?: boolean;
11
- lastModified?: boolean;
12
- ignore?: (path: string) => boolean;
13
- }
14
- /**
15
- * @class Send
16
- */
17
- export default class Send {
18
- private root;
19
- private options;
20
- /**
21
- * @constructor
22
- * @param {string} root
23
- * @param {Options} options
24
- */
25
- constructor(root: string, options?: Options);
26
- /**
27
- * @method isConditionalGET
28
- * @param {Context} context
29
- * @returns {boolean}
30
- */
31
- private isConditionalGET;
32
- /**
33
- * @method isPreconditionFailure
34
- * @param {Context} context
35
- * @returns {boolean}
36
- */
37
- private isPreconditionFailure;
38
- /**
39
- * @method isRangeFresh
40
- * @param {Context} context
41
- * @returns {boolean}
42
- */
43
- private isRangeFresh;
44
- /**
45
- * @method isIgnore
46
- * @param {string} path
47
- * @returns {boolean}
48
- */
49
- private isIgnore;
50
- /**
51
- * @method parseRange
52
- * @param {Context} context
53
- * @param {Stats} stats
54
- * @returns {Ranges}
55
- */
56
- private parseRange;
57
- /**
58
- * @method setupHeaders
59
- * @param {Context} context
60
- * @param {string} path
61
- * @param {Stats} stats
62
- */
63
- private setupHeaders;
64
- /**
65
- * @method read
66
- * @param {string} path
67
- * @param {Range} range
68
- * @param {PassThrough} buffer
69
- * @param {boolean} end
70
- * @returns {Promise<true>}
71
- */
72
- private read;
73
- /**
74
- * @method send
75
- * @param {Context} context
76
- * @param {string} path
77
- * @param {Range[]} ranges
78
- */
79
- private send;
80
- /**
81
- * @method response
82
- * @param {Context} context
83
- * @returns {Promise<boolean>}
84
- */
85
- response(context: Context): Promise<boolean>;
86
- }