@fastify/compress 7.0.2 → 8.0.0-pre.fv5.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.
@@ -17,7 +17,7 @@ on:
17
17
 
18
18
  jobs:
19
19
  test:
20
- uses: fastify/workflows/.github/workflows/plugins-ci.yml@v3
20
+ uses: fastify/workflows/.github/workflows/plugins-ci.yml@v4.1.0
21
21
  with:
22
22
  license-check: true
23
23
  lint: true
package/.taprc CHANGED
@@ -1,2 +1,3 @@
1
+ disable-coverage: true
1
2
  files:
2
3
  - test/**/*.test.js
package/index.js CHANGED
@@ -7,12 +7,12 @@ const fp = require('fastify-plugin')
7
7
  const encodingNegotiator = require('@fastify/accept-negotiator')
8
8
  const pump = require('pump')
9
9
  const mimedb = require('mime-db')
10
- const intoStream = require('into-stream')
11
10
  const peek = require('peek-stream')
12
11
  const { Minipass } = require('minipass')
13
12
  const pumpify = require('pumpify')
13
+ const { Readable } = require('readable-stream')
14
14
 
15
- const { isStream, isGzip, isDeflate } = require('./lib/utils')
15
+ const { isStream, isGzip, isDeflate, intoAsyncIterator } = require('./lib/utils')
16
16
 
17
17
  const InvalidRequestEncodingError = createError('FST_CP_ERR_INVALID_CONTENT_ENCODING', 'Unsupported Content-Encoding: %s', 415)
18
18
  const InvalidRequestCompressedPayloadError = createError('FST_CP_ERR_INVALID_CONTENT', 'Could not decompress the request payload using the provided encoding', 400)
@@ -276,7 +276,7 @@ function buildRouteCompress (fastify, params, routeOptions, decorateOnly) {
276
276
  if (Buffer.byteLength(payload) < params.threshold) {
277
277
  return next()
278
278
  }
279
- payload = intoStream(payload)
279
+ payload = Readable.from(intoAsyncIterator(payload))
280
280
  }
281
281
 
282
282
  setVaryHeader(reply)
@@ -400,7 +400,7 @@ function compress (params) {
400
400
  if (Buffer.byteLength(payload) < params.threshold) {
401
401
  return this.send(payload)
402
402
  }
403
- payload = intoStream(payload)
403
+ payload = Readable.from(intoAsyncIterator(payload))
404
404
  }
405
405
 
406
406
  setVaryHeader(this)
@@ -509,7 +509,7 @@ function maybeUnzip (payload, serialize) {
509
509
  // handle case where serialize doesn't return a string or Buffer
510
510
  if (!Buffer.isBuffer(buf)) return result
511
511
  if (isCompressed(buf) === 0) return result
512
- return intoStream(result)
512
+ return Readable.from(intoAsyncIterator(result))
513
513
  }
514
514
 
515
515
  function zipStream (deflate, encoding) {
package/lib/utils.js CHANGED
@@ -35,4 +35,45 @@ function isStream (stream) {
35
35
  return stream !== null && typeof stream === 'object' && typeof stream.pipe === 'function'
36
36
  }
37
37
 
38
- module.exports = { isGzip, isDeflate, isStream }
38
+ /**
39
+ * Provide a async iteratable for Readable.from
40
+ */
41
+ async function * intoAsyncIterator (payload) {
42
+ if (typeof payload === 'object') {
43
+ if (Buffer.isBuffer(payload)) {
44
+ yield payload
45
+ return
46
+ }
47
+
48
+ if (
49
+ // ArrayBuffer
50
+ payload instanceof ArrayBuffer ||
51
+ // NodeJS.TypedArray
52
+ ArrayBuffer.isView(payload)
53
+ ) {
54
+ yield Buffer.from(payload)
55
+ return
56
+ }
57
+
58
+ // Iterator
59
+ if (Symbol.iterator in payload) {
60
+ for (const chunk of payload) {
61
+ yield chunk
62
+ }
63
+ return
64
+ }
65
+
66
+ // Async Iterator
67
+ if (Symbol.asyncIterator in payload) {
68
+ for await (const chunk of payload) {
69
+ yield chunk
70
+ }
71
+ return
72
+ }
73
+ }
74
+
75
+ // string
76
+ yield payload
77
+ }
78
+
79
+ module.exports = { isGzip, isDeflate, isStream, intoAsyncIterator }
package/package.json CHANGED
@@ -1,41 +1,41 @@
1
1
  {
2
2
  "name": "@fastify/compress",
3
- "version": "7.0.2",
3
+ "version": "8.0.0-pre.fv5.1",
4
4
  "description": "Fastify compression utils",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
7
7
  "types": "types/index.d.ts",
8
8
  "dependencies": {
9
9
  "@fastify/accept-negotiator": "^1.1.0",
10
- "fastify-plugin": "^4.5.0",
11
- "into-stream": "^6.0.0",
10
+ "fastify-plugin": "^4.5.1",
12
11
  "mime-db": "^1.52.0",
13
- "minipass": "^7.0.2",
12
+ "minipass": "^7.0.4",
14
13
  "peek-stream": "^1.1.3",
15
14
  "pump": "^3.0.0",
16
- "pumpify": "^2.0.1"
15
+ "pumpify": "^2.0.1",
16
+ "readable-stream": "^4.5.2"
17
17
  },
18
18
  "devDependencies": {
19
- "@fastify/pre-commit": "^2.0.2",
20
- "@types/node": "^20.4.2",
21
- "@typescript-eslint/eslint-plugin": "^7.1.0",
22
- "@typescript-eslint/parser": "^7.1.0",
23
- "adm-zip": "^0.5.10",
24
- "fastify": "^4.19.2",
19
+ "@fastify/pre-commit": "^2.1.0",
20
+ "@types/node": "^20.12.7",
21
+ "@typescript-eslint/eslint-plugin": "^7.6.0",
22
+ "@typescript-eslint/parser": "^7.6.0",
23
+ "adm-zip": "^0.5.12",
24
+ "fastify": "^4.26.2",
25
25
  "jsonstream": "^1.0.3",
26
26
  "standard": "^17.1.0",
27
- "tap": "^16.3.7",
28
- "tsd": "^0.30.0",
29
- "typescript": "^5.1.6"
27
+ "tap": "^18.7.2",
28
+ "tsd": "^0.31.0",
29
+ "typescript": "^5.4.5"
30
30
  },
31
31
  "scripts": {
32
- "coverage": "npm run test:unit -- --coverage-report=html",
33
32
  "lint": "standard",
34
33
  "lint:fix": "npm run lint -- --fix",
35
34
  "lint:fix:typescript": "npm run lint:fix -- --parser @typescript-eslint/parser --plugin @typescript-eslint/eslint-plugin \"**/*.d.ts\"",
36
35
  "test": "npm run test:unit && npm run test:typescript",
37
36
  "test:typescript": "tsd",
38
37
  "test:unit": "tap",
38
+ "test:coverage": "npm run test:unit -- --coverage-report=html",
39
39
  "test:unit:verbose": "npm run test:unit -- -Rspec"
40
40
  },
41
41
  "keywords": [
@@ -0,0 +1,62 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const Fastify = require('fastify')
5
+ const fastifyCompress = require('../..')
6
+ const { request } = require('node:http')
7
+
8
+ function fetch (url) {
9
+ return new Promise(function (resolve, reject) {
10
+ request(url, function (response) {
11
+ // we need to use Buffer.concat to prevent wrong utf8 handling
12
+ let body = Buffer.from('')
13
+ response.on('data', function (chunk) {
14
+ body = Buffer.concat([body, Buffer.from(chunk, 'utf-8')])
15
+ })
16
+ response.once('error', reject)
17
+ response.once('end', function () {
18
+ resolve(body.toString())
19
+ })
20
+ })
21
+ .once('error', reject)
22
+ .end()
23
+ })
24
+ }
25
+
26
+ test('should not corrupt the file content', async (t) => {
27
+ t.plan(2)
28
+
29
+ // provide 2 byte unicode content
30
+ const twoByteUnicodeContent = new Array(5_000)
31
+ .fill('0')
32
+ .map(() => {
33
+ const random = new Array(10).fill('A').join('🍃')
34
+ return random + '- FASTIFY COMPRESS,🍃 FASTIFY COMPRESS'
35
+ })
36
+ .join('\n')
37
+ const fastify = new Fastify()
38
+ t.teardown(() => fastify.close())
39
+
40
+ fastify.register(async (instance, opts) => {
41
+ await fastify.register(fastifyCompress)
42
+ // compression
43
+ instance.get('/compress', async (req, reply) => {
44
+ return twoByteUnicodeContent
45
+ })
46
+ })
47
+
48
+ // no compression
49
+ fastify.get('/no-compress', async (req, reply) => {
50
+ return twoByteUnicodeContent
51
+ })
52
+
53
+ const address = await fastify.listen({ port: 0, host: '127.0.0.1' })
54
+
55
+ const [body1, body2] = await Promise.all([
56
+ fetch(`${address}/compress`),
57
+ fetch(`${address}/no-compress`)
58
+ ])
59
+
60
+ t.equal(body1, body2)
61
+ t.equal(body1, twoByteUnicodeContent)
62
+ })
@@ -4,7 +4,7 @@ const { createReadStream } = require('node:fs')
4
4
  const { Socket } = require('node:net')
5
5
  const { Duplex, PassThrough, Readable, Stream, Transform, Writable } = require('node:stream')
6
6
  const { test } = require('tap')
7
- const { isStream, isDeflate, isGzip } = require('../lib/utils')
7
+ const { isStream, isDeflate, isGzip, intoAsyncIterator } = require('../lib/utils')
8
8
 
9
9
  test('isStream() utility should be able to detect Streams', async (t) => {
10
10
  t.plan(12)
@@ -61,3 +61,45 @@ test('isGzip() utility should be able to detect gzip compressed Buffer', async (
61
61
  t.equal(isGzip(undefined), false)
62
62
  t.equal(isGzip(''), false)
63
63
  })
64
+
65
+ test('intoAsyncIterator() utility should handle different data', async (t) => {
66
+ t.plan(8)
67
+
68
+ const buf = Buffer.from('foo')
69
+ const str = 'foo'
70
+ const arr = [str, str]
71
+ const arrayBuffer = new ArrayBuffer(8)
72
+ const typedArray = new Int32Array(arrayBuffer)
73
+ const asyncIterator = (async function * () {
74
+ yield str
75
+ })()
76
+ const obj = {}
77
+
78
+ for await (const buffer of intoAsyncIterator(buf)) {
79
+ t.equal(buffer, buf)
80
+ }
81
+
82
+ for await (const string of intoAsyncIterator(str)) {
83
+ t.equal(string, str)
84
+ }
85
+
86
+ for await (const chunk of intoAsyncIterator(arr)) {
87
+ t.equal(chunk, str)
88
+ }
89
+
90
+ for await (const chunk of intoAsyncIterator(arrayBuffer)) {
91
+ t.equal(chunk.toString(), Buffer.from(arrayBuffer).toString())
92
+ }
93
+
94
+ for await (const chunk of intoAsyncIterator(typedArray)) {
95
+ t.equal(chunk.toString(), Buffer.from(typedArray).toString())
96
+ }
97
+
98
+ for await (const chunk of intoAsyncIterator(asyncIterator)) {
99
+ t.equal(chunk, str)
100
+ }
101
+
102
+ for await (const chunk of intoAsyncIterator(obj)) {
103
+ t.equal(chunk, obj)
104
+ }
105
+ })
package/types/index.d.ts CHANGED
@@ -2,13 +2,12 @@ import {
2
2
  FastifyPluginCallback,
3
3
  FastifyReply,
4
4
  FastifyRequest,
5
+ RouteOptions as FastifyRouteOptions,
5
6
  RawServerBase,
6
- RawServerDefault,
7
- RouteOptions as FastifyRouteOptions
8
- } from 'fastify'
9
- import { Input, InputObject } from 'into-stream'
10
- import { Stream } from 'stream'
11
- import { BrotliOptions, ZlibOptions } from 'zlib'
7
+ RawServerDefault
8
+ } from 'fastify';
9
+ import { Stream } from 'stream';
10
+ import { BrotliOptions, ZlibOptions } from 'zlib';
12
11
 
13
12
  declare module 'fastify' {
14
13
  export interface FastifyContextConfig {
@@ -26,7 +25,7 @@ declare module 'fastify' {
26
25
  }
27
26
 
28
27
  interface FastifyReply {
29
- compress(input: Stream | Input | InputObject): void;
28
+ compress(input: Stream | Input): void;
30
29
  }
31
30
 
32
31
  export interface RouteOptions {
@@ -61,6 +60,14 @@ type EncodingToken = 'br' | 'deflate' | 'gzip' | 'identity';
61
60
 
62
61
  type CompressibleContentTypeFunction = (contentType: string) => boolean;
63
62
 
63
+ type Input =
64
+ | Buffer
65
+ | NodeJS.TypedArray
66
+ | ArrayBuffer
67
+ | string
68
+ | Iterable<Buffer | string>
69
+ | AsyncIterable<Buffer | string>;
70
+
64
71
  declare namespace fastifyCompress {
65
72
 
66
73
  export interface FastifyCompressOptions {