@fastify/compress 6.2.0 → 6.3.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.
@@ -2,6 +2,11 @@ name: CI
2
2
 
3
3
  on:
4
4
  push:
5
+ branches:
6
+ - main
7
+ - master
8
+ - next
9
+ - 'v*'
5
10
  paths-ignore:
6
11
  - 'docs/**'
7
12
  - '*.md'
package/README.md CHANGED
@@ -99,7 +99,8 @@ await fastify.register(
99
99
  )
100
100
  ```
101
101
  ### customTypes
102
- [mime-db](https://github.com/jshttp/mime-db) is used to determine if a `content-type` should be compressed. You can compress additional content types via regular expression.
102
+ [mime-db](https://github.com/jshttp/mime-db) is used to determine if a `content-type` should be compressed. You can compress additional content types via regular expression or by providing a function.
103
+
103
104
  ```javascript
104
105
  await fastify.register(
105
106
  import('@fastify/compress'),
@@ -107,6 +108,15 @@ await fastify.register(
107
108
  )
108
109
  ```
109
110
 
111
+ or
112
+
113
+ ```javascript
114
+ await fastify.register(
115
+ import('@fastify/compress'),
116
+ { customTypes: contentType => contentType.endsWith('x-protobuf') }
117
+ )
118
+ ```
119
+
110
120
  ### onUnsupportedEncoding
111
121
  When the encoding is not supported, a custom error response can be sent in place of the uncompressed payload by setting the `onUnsupportedEncoding(encoding, request, reply)` option to be a function that can modify the reply and return a `string | Buffer | Stream | Error` payload.
112
122
  ```javascript
package/index.js CHANGED
@@ -6,7 +6,7 @@ const pump = require('pump')
6
6
  const mimedb = require('mime-db')
7
7
  const intoStream = require('into-stream')
8
8
  const peek = require('peek-stream')
9
- const Minipass = require('minipass')
9
+ const { Minipass } = require('minipass')
10
10
  const pumpify = require('pumpify')
11
11
  const encodingNegotiator = require('@fastify/accept-negotiator')
12
12
  const { inherits, format } = require('util')
@@ -107,6 +107,8 @@ function fastifyCompress (fastify, opts, next) {
107
107
  next()
108
108
  }
109
109
 
110
+ const defaultCompressibleTypes = /^text\/(?!event-stream)|\+json$|\+text$|\+xml$|octet-stream$/
111
+
110
112
  function processCompressParams (opts) {
111
113
  /* istanbul ignore next */
112
114
  if (!opts) {
@@ -123,7 +125,11 @@ function processCompressParams (opts) {
123
125
  params.onUnsupportedEncoding = opts.onUnsupportedEncoding
124
126
  params.inflateIfDeflated = opts.inflateIfDeflated === true
125
127
  params.threshold = typeof opts.threshold === 'number' ? opts.threshold : 1024
126
- params.compressibleTypes = opts.customTypes instanceof RegExp ? opts.customTypes : /^text\/(?!event-stream)|\+json$|\+text$|\+xml$|octet-stream$/
128
+ params.compressibleTypes = opts.customTypes instanceof RegExp
129
+ ? opts.customTypes.test.bind(opts.customTypes)
130
+ : typeof opts.customTypes === 'function'
131
+ ? opts.customTypes
132
+ : defaultCompressibleTypes.test.bind(defaultCompressibleTypes)
127
133
  params.compressStream = {
128
134
  br: () => ((opts.zlib || zlib).createBrotliCompress || zlib.createBrotliCompress)(params.brotliOptions),
129
135
  gzip: () => ((opts.zlib || zlib).createGzip || zlib.createGzip)(params.zlibOptions),
@@ -142,7 +148,7 @@ function processCompressParams (opts) {
142
148
  params.encodings = Array.isArray(opts.encodings)
143
149
  ? supportedEncodings
144
150
  .filter(encoding => opts.encodings.includes(encoding))
145
- .sort((a, b) => opts.encodings.indexOf(a) - supportedEncodings.indexOf(b))
151
+ .sort((a, b) => opts.encodings.indexOf(a) - opts.encodings.indexOf(b))
146
152
  : supportedEncodings
147
153
 
148
154
  return params
@@ -174,7 +180,7 @@ function processDecompressParams (opts) {
174
180
  params.encodings = Array.isArray(opts.requestEncodings)
175
181
  ? supportedEncodings
176
182
  .filter(encoding => opts.requestEncodings.includes(encoding))
177
- .sort((a, b) => opts.requestEncodings.indexOf(a) - supportedEncodings.indexOf(b))
183
+ .sort((a, b) => opts.requestEncodings.indexOf(a) - opts.requestEncodings.indexOf(b))
178
184
  : supportedEncodings
179
185
 
180
186
  if (opts.forceRequestEncoding) {
@@ -461,7 +467,7 @@ function getEncodingHeader (encodings, request) {
461
467
  }
462
468
 
463
469
  function shouldCompress (type, compressibleTypes) {
464
- if (compressibleTypes.test(type)) return true
470
+ if (compressibleTypes(type)) return true
465
471
  const data = mimedb[type.split(';', 1)[0].trim().toLowerCase()]
466
472
  if (data === undefined) return false
467
473
  return data.compressible === true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastify/compress",
3
- "version": "6.2.0",
3
+ "version": "6.3.0",
4
4
  "description": "Fastify compression utils",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
@@ -9,14 +9,14 @@
9
9
  "fastify-plugin": "^4.0.0",
10
10
  "into-stream": "^6.0.0",
11
11
  "mime-db": "^1.51.0",
12
- "minipass": "^3.1.6",
12
+ "minipass": "^5.0.0",
13
13
  "peek-stream": "^1.1.3",
14
14
  "pump": "^3.0.0",
15
15
  "pumpify": "^2.0.1"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@fastify/pre-commit": "^2.0.2",
19
- "@types/node": "^18.0.0",
19
+ "@types/node": "^20.1.0",
20
20
  "@typescript-eslint/eslint-plugin": "^5.9.0",
21
21
  "@typescript-eslint/parser": "^5.9.0",
22
22
  "adm-zip": "^0.5.9",
@@ -24,8 +24,8 @@
24
24
  "jsonstream": "^1.0.3",
25
25
  "standard": "^17.0.0",
26
26
  "tap": "^16.0.0",
27
- "tsd": "^0.24.1",
28
- "typescript": "^4.5.4"
27
+ "tsd": "^0.28.0",
28
+ "typescript": "^5.0.2"
29
29
  },
30
30
  "scripts": {
31
31
  "coverage": "npm run unit -- --cov",
@@ -785,6 +785,29 @@ test('It should not compress :', async (t) => {
785
785
  t.equal(response.statusCode, 200)
786
786
  })
787
787
 
788
+ t.test('when `customTypes` is a function and returns false on the provided `Content-Type` reply header`', async (t) => {
789
+ t.plan(2)
790
+
791
+ const fastify = Fastify()
792
+ await fastify.register(compressPlugin, { customTypes: value => value === 'application/x-user-header' })
793
+
794
+ fastify.get('/', (request, reply) => {
795
+ reply
796
+ .type('application/x-other-type')
797
+ .compress(createReadStream('./package.json'))
798
+ })
799
+
800
+ const response = await fastify.inject({
801
+ url: '/',
802
+ method: 'GET',
803
+ headers: {
804
+ 'accept-encoding': 'gzip'
805
+ }
806
+ })
807
+ t.notOk(response.headers['content-encoding'])
808
+ t.equal(response.statusCode, 200)
809
+ })
810
+
788
811
  t.test('when `X-No-Compression` request header is `true`', async (t) => {
789
812
  t.plan(3)
790
813
 
@@ -2443,7 +2466,31 @@ test('It should compress data if `customTypes` is set and matches `Content-Type`
2443
2466
  t.equal(payload.toString('utf-8'), file)
2444
2467
  })
2445
2468
 
2446
- test('It should not apply `customTypes` option if the passed value is not a RegExp', async (t) => {
2469
+ test('It should compress data if `customTypes` is a function and returns true on the provided `Content-Type` reply header value', async (t) => {
2470
+ t.plan(2)
2471
+ const fastify = Fastify()
2472
+ await fastify.register(compressPlugin, { customTypes: value => value === 'application/x-user-header' })
2473
+
2474
+ fastify.get('/', (request, reply) => {
2475
+ reply
2476
+ .type('application/x-user-header')
2477
+ .send(createReadStream('./package.json'))
2478
+ })
2479
+
2480
+ const response = await fastify.inject({
2481
+ url: '/',
2482
+ method: 'GET',
2483
+ headers: {
2484
+ 'accept-encoding': 'gzip'
2485
+ }
2486
+ })
2487
+ const file = readFileSync('./package.json', 'utf8')
2488
+ const payload = zlib.gunzipSync(response.rawPayload)
2489
+ t.equal(response.headers['content-encoding'], 'gzip')
2490
+ t.equal(payload.toString('utf-8'), file)
2491
+ })
2492
+
2493
+ test('It should not apply `customTypes` option if the passed value is not a RegExp or Function', async (t) => {
2447
2494
  t.plan(2)
2448
2495
 
2449
2496
  const fastify = Fastify()
@@ -2703,7 +2750,7 @@ test('It should sort and follow custom `encodings` options', async (t) => {
2703
2750
  const fastify = Fastify()
2704
2751
  await fastify.register(compressPlugin, {
2705
2752
  global: true,
2706
- encodings: ['gzip', 'br']
2753
+ encodings: ['br', 'gzip']
2707
2754
  })
2708
2755
 
2709
2756
  fastify.get('/', (request, reply) => {
@@ -2725,6 +2772,35 @@ test('It should sort and follow custom `encodings` options', async (t) => {
2725
2772
  t.equal(payload.toString('utf-8'), file)
2726
2773
  })
2727
2774
 
2775
+ test('It should sort and prefer the order of custom `encodings` options', async (t) => {
2776
+ t.plan(2)
2777
+
2778
+ const fastify = Fastify()
2779
+ await fastify.register(compressPlugin, {
2780
+ global: true,
2781
+ encodings: ['gzip', 'deflate', 'br']
2782
+ })
2783
+
2784
+ fastify.get('/', (request, reply) => {
2785
+ reply
2786
+ .type('text/plain')
2787
+ .compress(createReadStream('./package.json'))
2788
+ })
2789
+
2790
+ const response = await fastify.inject({
2791
+ url: '/',
2792
+ method: 'GET',
2793
+ headers: {
2794
+ 'accept-encoding': 'hello,gzip,br'
2795
+ }
2796
+ })
2797
+
2798
+ const file = readFileSync('./package.json', 'utf8')
2799
+ const payload = zlib.gunzipSync(response.rawPayload)
2800
+ t.equal(response.headers['content-encoding'], 'gzip')
2801
+ t.equal(payload.toString('utf-8'), file)
2802
+ })
2803
+
2728
2804
  test('It should sort and follow custom `requestEncodings` options', async (t) => {
2729
2805
  t.plan(2)
2730
2806
 
package/types/index.d.ts CHANGED
@@ -59,11 +59,13 @@ type RouteDecompressOptions = Pick<fastifyCompress.FastifyCompressOptions,
59
59
 
60
60
  type EncodingToken = 'br' | 'deflate' | 'gzip' | 'identity';
61
61
 
62
+ type CompressibleContentTypeFunction = (contentType: string) => boolean;
63
+
62
64
  declare namespace fastifyCompress {
63
65
 
64
66
  export interface FastifyCompressOptions {
65
67
  brotliOptions?: BrotliOptions;
66
- customTypes?: RegExp;
68
+ customTypes?: RegExp | CompressibleContentTypeFunction;
67
69
  encodings?: EncodingToken[];
68
70
  forceRequestEncoding?: EncodingToken;
69
71
  global?: boolean;
@@ -28,6 +28,10 @@ const withGlobalOptions: FastifyCompressOptions = {
28
28
  const app: FastifyInstance = fastify()
29
29
  app.register(fastifyCompress, withGlobalOptions)
30
30
 
31
+ app.register(fastifyCompress, {
32
+ customTypes: value => value === 'application/json'
33
+ })
34
+
31
35
  app.get('/test-one', async (request, reply) => {
32
36
  expectType<void>(reply.compress(stream))
33
37
  })