koa-compress 5.1.1 → 5.2.0

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,5 +1,36 @@
1
1
  SEE https://github.com/koajs/compress/releases
2
2
 
3
+ 5.2.0 / 2026-02-10
4
+ ==================
5
+
6
+ * add functional and local options
7
+ * updated dependencies
8
+ * copied the project setup from Koa
9
+ * add zstd
10
+ * use `negotiator` for content negotiation
11
+ * add TypeScript typings and tests
12
+
13
+ 5.1.1 / 2023-04-08
14
+ ==================
15
+
16
+ * minor refactoring + updated dependencies
17
+
18
+ 5.1.0 / 2021-08-17
19
+ ==================
20
+
21
+ * change brotli defaults (compression level to 4)
22
+ * updated dependencies
23
+
24
+ 5.0.1 / 2020-07-06
25
+ ==================
26
+
27
+ * updated to accomodate Node changes: zlib constants were moved to a different namespace
28
+
29
+ 5.0.0 / 2020-07-05
30
+ ==================
31
+
32
+ * add `defaultEncoding`
33
+
3
34
  4.0.1 / 2020-04-29
4
35
  ==================
5
36
 
package/README.md CHANGED
@@ -8,23 +8,28 @@ Compress middleware for Koa
8
8
  ## Example
9
9
 
10
10
  ```js
11
- const compress = require('koa-compress')
12
- const Koa = require('koa')
13
-
14
- const app = new Koa()
15
- app.use(compress({
16
- filter (content_type) {
17
- return /text/i.test(content_type)
18
- },
19
- threshold: 2048,
20
- gzip: {
21
- flush: require('zlib').constants.Z_SYNC_FLUSH
22
- },
23
- deflate: {
24
- flush: require('zlib').constants.Z_SYNC_FLUSH,
25
- },
26
- br: false // disable brotli
27
- }))
11
+ const compress = require("koa-compress");
12
+ const Koa = require("koa");
13
+
14
+ const app = new Koa();
15
+ app.use(
16
+ compress({
17
+ filter(content_type) {
18
+ return /text/i.test(content_type);
19
+ },
20
+ threshold: 2048,
21
+ gzip: {
22
+ flush: require("zlib").constants.Z_SYNC_FLUSH,
23
+ },
24
+ deflate: {
25
+ flush: require("zlib").constants.Z_SYNC_FLUSH,
26
+ },
27
+ zstd: {
28
+ flush: require("zlib").constants.Z_SYNC_FLUSH,
29
+ },
30
+ br: false, // disable brotli
31
+ }),
32
+ );
28
33
  ```
29
34
 
30
35
  ## Maintainers
@@ -45,22 +50,28 @@ function (mimeType: string): Boolean {
45
50
  An optional function that checks the response content type to decide whether to compress.
46
51
  By default, it uses [compressible](https://github.com/jshttp/compressible).
47
52
 
48
- ### options.threshold\<String|Number\>
53
+ ### options.threshold\<String|Number|Function\>
49
54
 
50
- Minimum response size in bytes to compress.
55
+ Minimum response size in bytes to compress or a function that returns such response (see below).
51
56
  Default `1024` bytes or `1kb`.
52
57
 
53
- ### options[encoding]\<Object\>
58
+ ### options[encoding]\<Object|Function\>
54
59
 
55
- The current encodings are, in order of preference: `br`, `gzip`, `deflate`.
60
+ The current encodings are, in order of preference: `br`, `zstd`, `gzip`, `deflate`.
56
61
  Setting `options[encoding] = {}` will pass those options to the encoding function.
57
62
  Setting `options[encoding] = false` will disable that encoding.
58
63
 
59
- #### options<span></span>.br
64
+ It can be a function that returns options (see below).
65
+
66
+ #### options.br
60
67
 
61
68
  [Brotli compression](https://en.wikipedia.org/wiki/Brotli) is supported in node v11.7.0+, which includes it natively.
62
69
  As of v5.1.0, the default quality level is 4 for performance reasons.
63
70
 
71
+ #### options.zstd
72
+
73
+ [Zstandard compression](https://en.wikipedia.org/wiki/Zstandard) is natively supported in the Node.js API. Minimum supported version: `v22.15.0` (LTS); also available on the Current line starting from `v23.8.0+`. This middleware performs runtime feature detection for `zlib.createZstdCompress`; if present, Zstd is enabled, otherwise it is skipped—no version configuration required.
74
+
64
75
  ### options.defaultEncoding\<String\>
65
76
 
66
77
  An optional string, which specifies what encoders to use for requests without
@@ -79,7 +90,37 @@ This bypasses the filter check.
79
90
 
80
91
  ```js
81
92
  app.use((ctx, next) => {
82
- ctx.compress = true
83
- ctx.body = fs.createReadStream(file)
84
- })
93
+ ctx.compress = true;
94
+ ctx.body = fs.createReadStream(file);
95
+ });
96
+ ```
97
+
98
+ `ctx.compress` can be an object similar to `options` above, whose properties (`threshold` and encoding options)
99
+ override the global `options` for this response and bypass the filter check.
100
+
101
+ ## Functional properties
102
+
103
+ Certain properties (`threshold` and encoding options) can be specified as functions. Such functions will be called
104
+ for every response with three arguments:
105
+
106
+ - `type` &mdash; the same as `ctx.response.type` (provided for convenience)
107
+ - `size` &mdash; the same as `ctx.response.length` (provided for convenience)
108
+ - `ctx` &mdash; the whole context object, if you want to do something unique
109
+
110
+ It should return a valid value for that property. It is possible to return a function of the same shape,
111
+ which will be used to calculate the actual property.
112
+
113
+ Example:
114
+
115
+ ```js
116
+ app.use((ctx, next) => {
117
+ // ...
118
+ ctx.compress = (type, size, ctx) => ({
119
+ br: size && size >= 65536,
120
+ gzip: size && size < 65536,
121
+ });
122
+ ctx.body = payload;
123
+ });
85
124
  ```
125
+
126
+ Read all about `ctx` in https://koajs.com/#context and `ctx.response` in https://koajs.com/#response
package/lib/index.d.ts ADDED
@@ -0,0 +1,137 @@
1
+ import type { BrotliOptions, ZlibOptions, ZstdOptions } from "node:zlib";
2
+ import type Koa = require("koa");
3
+
4
+ /**
5
+ * Function to calculate a threshold value dynamically from a MIME type,
6
+ * an existing size and the current context.
7
+ */
8
+ export type ThresholdFunction = (
9
+ /** MIME type of the response */
10
+ type: string,
11
+ /** Size of the response in bytes */
12
+ size: number,
13
+ /** Context of the request */
14
+ ctx: Koa.Context,
15
+ ) => number | string | ThresholdFunction;
16
+
17
+ /**
18
+ * Function to calculate compression parameters for `deflate` and `gzip` from a MIME type,
19
+ * an exisiting size and the current context.
20
+ */
21
+ export type ZlibOptionsFunction = (
22
+ /** MIME type of the response */
23
+ type: string,
24
+ /** Size of the response in bytes */
25
+ size: number,
26
+ /** Context of the request */
27
+ ctx: Koa.Context,
28
+ ) => boolean | null | ZlibOptions | ZlibOptionsFunction;
29
+
30
+ /**
31
+ * Function to calculate compression parameters for `brotli` from a MIME type,
32
+ * an exisiting size and the current context.
33
+ */
34
+ export type BrotliOptionsFunction = (
35
+ /** MIME type of the response */
36
+ type: string,
37
+ /** Size of the response in bytes */
38
+ size: number,
39
+ /** Context of the request */
40
+ ctx: Koa.Context,
41
+ ) => boolean | null | BrotliOptions | BrotliOptionsFunction;
42
+
43
+ /**
44
+ * Function to calculate compression parameters for `zstd` from a MIME type,
45
+ * an exisiting size and the current context.
46
+ */
47
+ export type ZstdOptionsFunction = (
48
+ /** MIME type of the response */
49
+ type: string,
50
+ /** Size of the response in bytes */
51
+ size: number,
52
+ /** Context of the request */
53
+ ctx: Koa.Context,
54
+ ) => boolean | null | ZstdOptions | ZstdOptionsFunction;
55
+
56
+ /**
57
+ * Compression options that govern how `koa/compress` handles responses.
58
+ */
59
+ export type CompressOptions = {
60
+ /**
61
+ * Function to determine if compression should be applied.
62
+ * Default: `compressible()`.
63
+ * @param type MIME type of the response
64
+ * @returns `true` if compression should be applied, `false` otherwise
65
+ */
66
+ filter?: (type: string) => boolean;
67
+ /**
68
+ * Lower limit to apply compression to content. If it is a number, it is size in bytes,
69
+ * if it is a string, it is a human-readable size accepted by `bytes()`, e.g., `"1mb"`,
70
+ * or a `ThresholdFunction` that can calculate that value. Default: `1024`.
71
+ */
72
+ threshold?: number | string | ThresholdFunction;
73
+ /**
74
+ * Default value for `Accept-Encoding` header, if it is not supplied by the client.
75
+ * Default: `"identity"`.
76
+ */
77
+ defaultEncoding?: string;
78
+ /**
79
+ * What `Accept-Encoding` value should be assumed if it is set to `"*"`. Default: `"gzip"`.
80
+ */
81
+ wildcardAcceptEncoding?: string;
82
+ /**
83
+ * An array of compression types, which should be used when we have multiple choices
84
+ * with the same weight. An item with a lower index has higher priority.
85
+ * Default: `['zstd', 'br', 'gzip', 'deflate']`.
86
+ */
87
+ encodingPreference?: string[];
88
+ /**
89
+ * Options to use when compressing with `deflate()`.
90
+ * If it is `false` or `null` this compression should be disabled.
91
+ * It can be a function used to calculate such values.
92
+ * Default: `{}`.
93
+ */
94
+ deflate?: boolean | null | ZlibOptions | ZlibOptionsFunction;
95
+ /**
96
+ * Options to use when compressing with `gzip()`.
97
+ * If it is `false` or `null` this compression should be disabled.
98
+ * It can be a function used to calculate such values.
99
+ * Default: `{}`.
100
+ */
101
+ gzip?: boolean | null | ZlibOptions | ZlibOptionsFunction;
102
+ /**
103
+ * Options to use when compressing with `br()`.
104
+ * If it is `false` or `null` this compression should be disabled.
105
+ * It can be a function used to calculate such values.
106
+ * Default: `{[zlib.constants.BROTLI_PARAM_QUALITY]: 4}`.
107
+ */
108
+ br?: boolean | null | BrotliOptions | BrotliOptionsFunction;
109
+ /**
110
+ * Options to use when compressing with `zstd()`.
111
+ * If it is `false` or `null` this compression should be disabled.
112
+ * It can be a function used to calculate such values.
113
+ * Default: `{}`.
114
+ */
115
+ zstd?: boolean | null | ZstdOptions | ZstdOptionsFunction;
116
+ };
117
+
118
+ /**
119
+ * The main function that constructs a middleware for compressing responses.
120
+ * @param options sets the default way to handle compression.
121
+ * @returns a middleware function that compresses responses.
122
+ */
123
+ declare function compress(options: CompressOptions = {}): Koa.Middleware;
124
+
125
+ declare module "koa" {
126
+ interface DefaultContext {
127
+ /**
128
+ * Context property used to handle individual responses.
129
+ * If it is set to `false`, the compression is disabled.
130
+ * If it is an object, it is mixed with the default options overriding
131
+ * its properties for this request.
132
+ */
133
+ compress?: boolean | CompressOptions;
134
+ }
135
+ }
136
+
137
+ export = compress;
package/lib/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ // @ts-self-types="./index.d.ts"
2
+
1
3
  'use strict'
2
4
 
3
5
  /**
@@ -7,13 +9,37 @@
7
9
  const compressible = require('compressible')
8
10
  const isJSON = require('koa-is-json')
9
11
  const Stream = require('stream')
12
+ const zlib = require('zlib')
10
13
  const bytes = require('bytes')
14
+ const Negotiator = require('negotiator')
15
+
16
+ const encodingMethods = {
17
+ zstd: zlib.createZstdCompress,
18
+ br: zlib.createBrotliCompress,
19
+ gzip: zlib.createGzip,
20
+ deflate: zlib.createDeflate
21
+ }
22
+
23
+ const encodingDefaultPreference = ['zstd', 'br', 'gzip', 'deflate', 'identity']
24
+
25
+ const preferredEncodings = encodingDefaultPreference.filter(
26
+ (encoding) => encodingMethods[encoding] || encoding === 'identity'
27
+ )
11
28
 
12
- const Encodings = require('./encodings')
29
+ const encodingMethodDefaultOptions = {
30
+ gzip: {},
31
+ deflate: {},
32
+ br: {
33
+ params: {
34
+ [zlib.constants.BROTLI_PARAM_QUALITY]: 4
35
+ }
36
+ },
37
+ zstd: {}
38
+ }
13
39
 
14
40
  /**
15
- * Regex to match no-transform directive in a cache-control header
16
- */
41
+ * Regex to match no-transform directive in a cache-control header
42
+ */
17
43
  const NO_TRANSFORM_REGEX = /(?:^|,)\s*?no-transform\s*?(?:,|$)/
18
44
 
19
45
  /**
@@ -30,18 +56,31 @@ const emptyBodyStatues = new Set([204, 205, 304])
30
56
  */
31
57
 
32
58
  module.exports = (options = {}) => {
33
- let { filter = compressible, threshold = 1024, defaultEncoding = 'identity' } = options
59
+ let {
60
+ filter = compressible,
61
+ threshold = 1024,
62
+ defaultEncoding,
63
+ wildcardAcceptEncoding,
64
+ encodingPreference = encodingDefaultPreference
65
+ } = options
34
66
  if (typeof threshold === 'string') threshold = bytes(threshold)
67
+ if (!wildcardAcceptEncoding || wildcardAcceptEncoding === '*') {
68
+ wildcardAcceptEncoding = 'gzip'
69
+ }
70
+ defaultEncoding =
71
+ defaultEncoding === '*'
72
+ ? wildcardAcceptEncoding
73
+ : !defaultEncoding
74
+ ? 'identity'
75
+ : defaultEncoding
35
76
 
36
- // `options.br = false` would remove it as a preferred encoding
37
- const preferredEncodings = Encodings.preferredEncodings.filter((encoding) => options[encoding] !== false && options[encoding] !== null)
38
77
  const encodingOptions = {}
39
- preferredEncodings.forEach((encoding) => {
78
+ for (const encoding of preferredEncodings) {
40
79
  encodingOptions[encoding] = {
41
- ...Encodings.encodingMethodDefaultOptions[encoding],
42
- ...(options[encoding] || {})
80
+ ...encodingMethodDefaultOptions[encoding],
81
+ ...options[encoding]
43
82
  }
44
- })
83
+ }
45
84
 
46
85
  Object.assign(compressMiddleware, {
47
86
  preferredEncodings,
@@ -56,27 +95,66 @@ module.exports = (options = {}) => {
56
95
  await next()
57
96
 
58
97
  let { body } = ctx
98
+ const { type, length: size } = ctx.response
59
99
  if (
60
100
  // early exit if there's no content body or the body is already encoded
61
101
  !body ||
62
- ctx.res.headersSent || !ctx.writable ||
102
+ ctx.res.headersSent ||
103
+ !ctx.writable ||
63
104
  ctx.compress === false ||
64
105
  ctx.request.method === 'HEAD' ||
65
106
  emptyBodyStatues.has(+ctx.response.status) ||
66
107
  ctx.response.get('Content-Encoding') ||
67
108
  // forced compression or implied
68
- !(ctx.compress === true || filter(ctx.response.type)) ||
109
+ !(ctx.compress === true || filter(type)) ||
69
110
  // don't compress for Cache-Control: no-transform
70
111
  // https://tools.ietf.org/html/rfc7234#section-5.2.1.6
71
- NO_TRANSFORM_REGEX.test(ctx.response.get('Cache-Control')) ||
72
- // don't compress if the current response is below the threshold
73
- (threshold && ctx.response.length < threshold)
74
- ) return
112
+ NO_TRANSFORM_REGEX.test(ctx.response.get('Cache-Control'))
113
+ ) {
114
+ return
115
+ }
116
+
117
+ // calculate "local" compression options
118
+ const responseOptions = { ...options, ...ctx.compress }
119
+ let { threshold = 1024 } = responseOptions
120
+ while (typeof threshold === 'function') {
121
+ threshold = threshold(type, size, ctx)
122
+ }
123
+ if (typeof threshold === 'string') threshold = bytes(threshold)
124
+
125
+ // don't compress if the current response is below the threshold
126
+ if (threshold && size < threshold) return
75
127
 
76
128
  // get the preferred content encoding
77
- const encodings = new Encodings({ preferredEncodings })
78
- encodings.parseAcceptEncoding(ctx.request.headers['accept-encoding'] || defaultEncoding)
79
- const encoding = encodings.getPreferredContentEncoding()
129
+ for (const encoding of compressMiddleware.preferredEncodings) {
130
+ // calculate compressor options, if any
131
+ if (!(encoding in responseOptions)) continue
132
+ let compressor = responseOptions[encoding]
133
+ while (typeof compressor === 'function') {
134
+ compressor = compressor(type, size, ctx)
135
+ }
136
+ responseOptions[encoding] = compressor
137
+ }
138
+
139
+ const finalEncodings = compressMiddleware.preferredEncodings.filter(
140
+ (encoding) =>
141
+ responseOptions[encoding] !== false &&
142
+ responseOptions[encoding] !== null
143
+ )
144
+
145
+ const acceptEncoding = ctx.request.headers['accept-encoding']
146
+ let request = ctx.request
147
+ if (acceptEncoding === '*') {
148
+ request = { headers: { 'accept-encoding': wildcardAcceptEncoding } }
149
+ } else if (!acceptEncoding) {
150
+ request = { headers: { 'accept-encoding': defaultEncoding } }
151
+ }
152
+
153
+ const negotiator = new Negotiator(request)
154
+ // if no encodings are supported, negotiator returns 'identity'
155
+ const encoding = negotiator.encoding(finalEncodings, {
156
+ preferred: encodingPreference
157
+ })
80
158
 
81
159
  // identity === no compression
82
160
  if (encoding === 'identity') return
@@ -89,8 +167,8 @@ module.exports = (options = {}) => {
89
167
  ctx.set('Content-Encoding', encoding)
90
168
  ctx.res.removeHeader('Content-Length')
91
169
 
92
- const compress = Encodings.encodingMethods[encoding]
93
- const stream = ctx.body = compress(encodingOptions[encoding])
170
+ const compress = encodingMethods[encoding]
171
+ const stream = (ctx.body = compress(responseOptions[encoding]))
94
172
 
95
173
  if (body instanceof Stream) return body.pipe(stream)
96
174
  stream.end(body)
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "koa-compress",
3
3
  "description": "Compress middleware for koa",
4
- "version": "5.1.1",
4
+ "version": "5.2.0",
5
+ "type": "commonjs",
5
6
  "author": {
6
7
  "name": "Jonathan Ong",
7
8
  "email": "me@jongleberry.com",
@@ -13,6 +14,11 @@
13
14
  "name": "Imed Jaberi",
14
15
  "email": "imed-jaberi@outlook.com",
15
16
  "url": "https://www.3imed-jaberi.com/"
17
+ },
18
+ {
19
+ "name": "Eugene Lazutkin",
20
+ "email": "eugene.lazutkin@gmail.com",
21
+ "url": "https://www.lazutkin.com/"
16
22
  }
17
23
  ],
18
24
  "license": "MIT",
@@ -20,23 +26,29 @@
20
26
  "dependencies": {
21
27
  "bytes": "^3.1.2",
22
28
  "compressible": "^2.0.18",
23
- "http-errors": "^1.8.1",
24
- "koa-is-json": "^1.0.0"
29
+ "http-errors": "^2.0.1",
30
+ "koa-is-json": "^1.0.0",
31
+ "negotiator": "^1.0.0"
25
32
  },
26
33
  "devDependencies": {
27
- "eslint": "^7.32.0",
28
- "eslint-config-standard": "^16.0.3",
29
- "eslint-plugin-import": "^2.26.0",
30
- "eslint-plugin-node": "^11.1.0",
31
- "eslint-plugin-promise": "^5.2.0",
32
- "eslint-plugin-standard": "^5.0.0",
33
- "jest": "^27.5.1",
34
- "koa": "^2.13.4",
35
- "supertest": "^6.2.4"
34
+ "@types/koa": "^3.0.1",
35
+ "@types/node": "^25.2.2",
36
+ "c8": "^10.1.3",
37
+ "jest": "^30.2.0",
38
+ "koa": "^3.1.1",
39
+ "snazzy": "^9.0.0",
40
+ "standard": "^17.1.2",
41
+ "supertest": "^7.2.2",
42
+ "typescript": "^5.9.3"
36
43
  },
37
44
  "scripts": {
38
- "eslint": "eslint --ignore-path .gitignore .",
39
- "test": "jest"
45
+ "test": "jest",
46
+ "test:coverage": "c8 --reporter=lcov --reporter=text-summary jest --coverage",
47
+ "lint": "standard",
48
+ "lint:fix": "standard --fix",
49
+ "lint:pretty": "standard | snazzy",
50
+ "ts-check": "tsc --noEmit",
51
+ "authors": "git log --format='%aN <%aE>' | sort -u > AUTHORS"
40
52
  },
41
53
  "files": [
42
54
  "lib",
@@ -44,7 +56,21 @@
44
56
  "HISTORY.md"
45
57
  ],
46
58
  "main": "lib",
59
+ "types": "lib/index.d.ts",
47
60
  "engines": {
48
61
  "node": ">= 12"
62
+ },
63
+ "standard": {
64
+ "globals": [
65
+ "afterAll",
66
+ "beforeAll",
67
+ "afterEach",
68
+ "jasmine",
69
+ "describe",
70
+ "test",
71
+ "jest",
72
+ "expect",
73
+ "it"
74
+ ]
49
75
  }
50
76
  }
package/lib/encodings.js DELETED
@@ -1,104 +0,0 @@
1
-
2
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding
3
- const errors = require('http-errors')
4
- const zlib = require('zlib')
5
-
6
- class Encodings {
7
- constructor (options = {}) {
8
- this.wildcardAcceptEncoding = options.wildcardAcceptEncoding || Encodings.wildcardAcceptEncoding
9
- this.preferredEncodings = options.preferredEncodings || Encodings.preferredEncodings
10
- this.reDirective = options.reDirective || Encodings.reDirective
11
-
12
- this.encodingWeights = new Map()
13
- }
14
-
15
- parseAcceptEncoding (acceptEncoding = '*') {
16
- const { encodingWeights, reDirective } = this
17
-
18
- acceptEncoding.split(',').forEach((directive) => {
19
- const match = reDirective.exec(directive)
20
- if (!match) return // not a supported encoding above
21
-
22
- const encoding = match[1]
23
-
24
- // weight must be in [0, 1]
25
- let weight = match[2] && !isNaN(match[2]) ? parseFloat(match[2], 10) : 1
26
- weight = Math.max(weight, 0)
27
- weight = Math.min(weight, 1)
28
-
29
- if (encoding === '*') {
30
- // set the weights for the default encodings
31
- this.wildcardAcceptEncoding.forEach((enc) => {
32
- if (!encodingWeights.has(enc)) encodingWeights.set(enc, weight)
33
- })
34
- return
35
- }
36
-
37
- encodingWeights.set(encoding, weight)
38
- })
39
- }
40
-
41
- getPreferredContentEncoding () {
42
- const {
43
- encodingWeights,
44
- preferredEncodings
45
- } = this
46
-
47
- // get ordered list of accepted encodings
48
- const acceptedEncodings = Array.from(encodingWeights.keys())
49
- // sort by weight
50
- .sort((a, b) => encodingWeights.get(b) - encodingWeights.get(a))
51
- // filter by supported encodings
52
- .filter((encoding) => encoding === 'identity' || typeof Encodings.encodingMethods[encoding] === 'function')
53
-
54
- // group them by weights
55
- const weightClasses = new Map()
56
- acceptedEncodings.forEach((encoding) => {
57
- const weight = encodingWeights.get(encoding)
58
- if (!weightClasses.has(weight)) weightClasses.set(weight, new Set())
59
- weightClasses.get(weight).add(encoding)
60
- })
61
-
62
- // search by weight, descending
63
- const weights = Array.from(weightClasses.keys()).sort((a, b) => b - a)
64
- for (let i = 0; i < weights.length; i++) {
65
- // encodings at this weight
66
- const encodings = weightClasses.get(weights[i])
67
- // return the first encoding in the preferred list
68
- for (let j = 0; j < preferredEncodings.length; j++) {
69
- const preferredEncoding = preferredEncodings[j]
70
- if (encodings.has(preferredEncoding)) return preferredEncoding
71
- }
72
- }
73
-
74
- // no encoding matches, check to see if the client set identity, q=0
75
- if (encodingWeights.get('identity') === 0) throw errors(406, 'Please accept br, gzip, deflate, or identity.')
76
-
77
- // by default, return nothing
78
- return 'identity'
79
- }
80
- }
81
-
82
- Encodings.encodingMethods = {
83
- gzip: zlib.createGzip,
84
- deflate: zlib.createDeflate,
85
- br: zlib.createBrotliCompress
86
- }
87
-
88
- Encodings.encodingMethodDefaultOptions = {
89
- gzip: {},
90
- deflate: {},
91
- br: {
92
- params: {
93
- [zlib.constants.BROTLI_PARAM_QUALITY]: 4
94
- }
95
- }
96
- }
97
-
98
- // how we treat `Accept-Encoding: *`
99
- Encodings.wildcardAcceptEncoding = ['gzip', 'deflate']
100
- // our preferred encodings
101
- Encodings.preferredEncodings = ['br', 'gzip', 'deflate']
102
- Encodings.reDirective = /^\s*(gzip|compress|deflate|br|identity|\*)\s*(?:;\s*q\s*=\s*(\d(?:\.\d)?))?\s*$/
103
-
104
- module.exports = Encodings