@fastify/compress 8.2.0 → 8.3.1

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
@@ -57,6 +57,23 @@ await fastify.register(
57
57
  { global: false }
58
58
  )
59
59
  ```
60
+
61
+ If only compression or decompression is required, set the `globalCompression` or `globalDecompression` config flags to `false` respectively (both are `true` by default).
62
+
63
+ ```js
64
+ await fastify.register(
65
+ import('@fastify/compress'),
66
+ // Disable compression but keep decompression enabled (default behavior for globalDecompression is true)
67
+ { globalCompression: false }
68
+ )
69
+
70
+ // Disable decompression but keep compression enabled
71
+ await fastify.register(
72
+ import('@fastify/compress'),
73
+ { globalDecompression: false }
74
+ )
75
+ ```
76
+
60
77
  Fastify encapsulation can be used to set global compression but run it only in a subset of routes by wrapping them inside a plugin.
61
78
 
62
79
  > ℹ️ Note: If using `@fastify/compress` plugin together with `@fastify/static` plugin, `@fastify/compress` must be registered (with *global hook*) **before** registering `@fastify/static`.
package/index.js CHANGED
@@ -124,7 +124,9 @@ function processCompressParams (opts) {
124
124
  }
125
125
 
126
126
  const params = {
127
- global: (typeof opts.global === 'boolean') ? opts.global : true
127
+ global: (typeof opts.globalCompression === 'boolean')
128
+ ? opts.globalCompression
129
+ : (typeof opts.global === 'boolean') ? opts.global : true
128
130
  }
129
131
 
130
132
  params.removeContentLengthHeader = typeof opts.removeContentLengthHeader === 'boolean' ? opts.removeContentLengthHeader : true
@@ -184,7 +186,9 @@ function processDecompressParams (opts) {
184
186
  const customZlib = opts.zlib || zlib
185
187
 
186
188
  const params = {
187
- global: (typeof opts.global === 'boolean') ? opts.global : true,
189
+ global: (typeof opts.globalDecompression === 'boolean')
190
+ ? opts.globalDecompression
191
+ : (typeof opts.global === 'boolean') ? opts.global : true,
188
192
  onUnsupportedRequestEncoding: opts.onUnsupportedRequestEncoding,
189
193
  onInvalidRequestPayload: opts.onInvalidRequestPayload,
190
194
  decompressStream: {
@@ -443,7 +447,7 @@ function compress (params) {
443
447
 
444
448
  stream = zipStream(params.compressStream, encoding)
445
449
  pump(payload, stream, onEnd.bind(this))
446
- this.send(stream)
450
+ return this.send(stream)
447
451
  }
448
452
  }
449
453
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastify/compress",
3
- "version": "8.2.0",
3
+ "version": "8.3.1",
4
4
  "description": "Fastify compression utils",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
@@ -3399,3 +3399,152 @@ for (const contentType of notByDefaultSupportedContentTypes) {
3399
3399
  t.assert.equal(response.rawPayload.toString('utf-8'), file)
3400
3400
  })
3401
3401
  }
3402
+
3403
+ test('It should support separate globalCompression and globalDecompression settings', async (t) => {
3404
+ t.plan(3)
3405
+
3406
+ // Test case: disable compression but enable decompression globally
3407
+ const fastify = Fastify()
3408
+ await fastify.register(compressPlugin, {
3409
+ globalCompression: false,
3410
+ globalDecompression: true
3411
+ })
3412
+
3413
+ const testData = { message: 'test data for decompression only' }
3414
+
3415
+ fastify.get('/', (request, reply) => {
3416
+ reply.send(testData)
3417
+ })
3418
+
3419
+ // Test that compression is disabled
3420
+ const getResponse = await fastify.inject({
3421
+ url: '/',
3422
+ method: 'GET',
3423
+ headers: {
3424
+ 'accept-encoding': 'gzip, deflate, br'
3425
+ }
3426
+ })
3427
+
3428
+ t.assert.equal(getResponse.statusCode, 200)
3429
+ // No compression should happen since globalCompression is false
3430
+ t.assert.equal(getResponse.headers['content-encoding'], undefined)
3431
+ t.assert.deepEqual(getResponse.json(), testData)
3432
+ })
3433
+
3434
+ test('It should enable decompression when globalDecompression is true', async (t) => {
3435
+ t.plan(2)
3436
+
3437
+ // Test case: enable decompression globally
3438
+ const fastify = Fastify()
3439
+ await fastify.register(compressPlugin, {
3440
+ globalCompression: false,
3441
+ globalDecompression: true
3442
+ })
3443
+
3444
+ // Create a compressed request payload to test decompression
3445
+ const compressedPayload = zlib.gzipSync(JSON.stringify({ input: 'compressed data' }))
3446
+
3447
+ fastify.post('/', (request, reply) => {
3448
+ // This should be decompressed automatically
3449
+ reply.send({ received: request.body })
3450
+ })
3451
+
3452
+ // Test that decompression is enabled
3453
+ const postResponse = await fastify.inject({
3454
+ url: '/',
3455
+ method: 'POST',
3456
+ headers: {
3457
+ 'content-encoding': 'gzip',
3458
+ 'content-type': 'application/json'
3459
+ },
3460
+ payload: compressedPayload
3461
+ })
3462
+
3463
+ t.assert.equal(postResponse.statusCode, 200)
3464
+ // Decompression should work since globalDecompression is true
3465
+ t.assert.deepEqual(postResponse.json(), { received: { input: 'compressed data' } })
3466
+ })
3467
+
3468
+ test('It should fall back to global option when specific options are not provided', async (t) => {
3469
+ t.plan(2)
3470
+
3471
+ // Test that global: false affects both compression and decompression
3472
+ const fastify = Fastify()
3473
+ await fastify.register(compressPlugin, {
3474
+ global: false
3475
+ })
3476
+
3477
+ const testData = { message: 'test data' }
3478
+
3479
+ fastify.get('/', (request, reply) => {
3480
+ reply.send(testData)
3481
+ })
3482
+
3483
+ const response = await fastify.inject({
3484
+ url: '/',
3485
+ method: 'GET',
3486
+ headers: {
3487
+ 'accept-encoding': 'gzip, deflate, br'
3488
+ }
3489
+ })
3490
+
3491
+ t.assert.equal(response.statusCode, 200)
3492
+ // No compression should happen since global is false
3493
+ t.assert.equal(response.headers['content-encoding'], undefined)
3494
+ })
3495
+
3496
+ test('It should demonstrate globalCompression overrides global setting', async (t) => {
3497
+ t.plan(2)
3498
+
3499
+ // Test that globalCompression: true overrides global: false
3500
+ const fastify = Fastify()
3501
+ await fastify.register(compressPlugin, {
3502
+ global: false,
3503
+ globalCompression: true,
3504
+ threshold: 0
3505
+ })
3506
+
3507
+ fastify.get('/', (request, reply) => {
3508
+ reply.send({ message: 'globalCompression overrides global' })
3509
+ })
3510
+
3511
+ const response = await fastify.inject({
3512
+ url: '/',
3513
+ method: 'GET',
3514
+ headers: { 'accept-encoding': 'gzip' }
3515
+ })
3516
+
3517
+ t.assert.equal(response.statusCode, 200)
3518
+ t.assert.equal(response.headers['content-encoding'], 'gzip') // Compression enabled despite global: false
3519
+ })
3520
+
3521
+ test('It should demonstrate globalDecompression controls decompression independently', async (t) => {
3522
+ t.plan(2)
3523
+
3524
+ // Test globalDecompression: false disables decompression even with global: true
3525
+ const fastify = Fastify()
3526
+ await fastify.register(compressPlugin, {
3527
+ global: true,
3528
+ globalDecompression: false
3529
+ })
3530
+
3531
+ const compressedPayload = zlib.gzipSync(JSON.stringify({ test: 'decompression' }))
3532
+
3533
+ fastify.post('/', (request, reply) => {
3534
+ reply.send({ received: request.body })
3535
+ })
3536
+
3537
+ const response = await fastify.inject({
3538
+ url: '/',
3539
+ method: 'POST',
3540
+ headers: {
3541
+ 'content-encoding': 'gzip',
3542
+ 'content-type': 'application/json'
3543
+ },
3544
+ payload: compressedPayload
3545
+ })
3546
+
3547
+ // Should get 400 error since decompression is disabled and compressed data can't be parsed
3548
+ t.assert.equal(response.statusCode, 400)
3549
+ t.assert.ok(response.body.includes('Content-Length') || response.body.includes('Bad Request'))
3550
+ })
@@ -0,0 +1,43 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('node:test')
4
+ const zlib = require('node:zlib')
5
+ const Fastify = require('fastify')
6
+ const fastifyCompress = require('../..')
7
+
8
+ const largeJsonString = JSON.stringify({
9
+ text: 'Lorem ipsum dolor sit amet. '.repeat(2048),
10
+ })
11
+
12
+ async function routes (fastify) {
13
+ fastify.route({
14
+ method: 'GET',
15
+ url: '/api/compress-test',
16
+ handler: async function (_request, reply) {
17
+ reply.type('application/json')
18
+ return reply.compress(largeJsonString)
19
+ }
20
+ })
21
+ }
22
+
23
+ test('should compress large payload without premature close', async (t) => {
24
+ const fastify = Fastify()
25
+ await fastify.register(fastifyCompress, { encodings: ['gzip'], global: true })
26
+ await fastify.register(routes)
27
+
28
+ const response = await fastify.inject({
29
+ url: '/api/compress-test',
30
+ method: 'GET',
31
+ headers: { 'accept-encoding': 'gzip' }
32
+ })
33
+
34
+ t.assert.equal(response.statusCode, 200)
35
+ t.assert.equal(response.headers['content-encoding'], 'gzip')
36
+ t.assert.ok(
37
+ response.rawPayload.length > 0,
38
+ `Expected compressed response body, got ${response.rawPayload.length} bytes`
39
+ )
40
+
41
+ const decompressed = zlib.gunzipSync(response.rawPayload)
42
+ t.assert.equal(decompressed.toString('utf-8'), largeJsonString)
43
+ })
package/types/index.d.ts CHANGED
@@ -77,6 +77,8 @@ declare namespace fastifyCompress {
77
77
  encodings?: EncodingToken[];
78
78
  forceRequestEncoding?: EncodingToken;
79
79
  global?: boolean;
80
+ globalDecompression?: boolean;
81
+ globalCompression?: boolean;
80
82
  inflateIfDeflated?: boolean;
81
83
  onInvalidRequestPayload?: (encoding: string, request: FastifyRequest, error: Error) => Error | undefined | null;
82
84
  onUnsupportedEncoding?: (encoding: string, request: FastifyRequest, reply: FastifyReply) => string | Buffer | Stream;