@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.
- package/.github/workflows/ci.yml +5 -0
- package/README.md +11 -1
- package/index.js +11 -5
- package/package.json +5 -5
- package/test/global-compress.test.js +78 -2
- package/types/index.d.ts +3 -1
- package/types/index.test-d.ts +4 -0
package/.github/workflows/ci.yml
CHANGED
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
|
|
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) -
|
|
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) -
|
|
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
|
|
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.
|
|
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": "^
|
|
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": "^
|
|
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.
|
|
28
|
-
"typescript": "^
|
|
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
|
|
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: ['
|
|
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;
|
package/types/index.test-d.ts
CHANGED
|
@@ -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
|
})
|