@fastify/reply-from 8.3.0 → 8.4.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/.taprc CHANGED
@@ -1,8 +1,11 @@
1
1
  ts: false
2
2
  jsx: false
3
3
  flow: false
4
- coverage: true
5
- check-coverage: false
4
+
5
+ functions: 97
6
+ lines: 96
7
+ statements: 96
8
+ branches: 96
6
9
 
7
10
  files:
8
11
  - test/**/*.js
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @fastify/reply-from
2
2
 
3
- [![CI](https://github.com/fastify/reply-fro/workflows/CI/badge.svg)](https://github.com/fastify/reply-fro/actions/workflows/ci.yml)
3
+ [![CI](https://github.com/fastify/fastify-reply-from/workflows/CI/badge.svg)](https://github.com/fastify/fastify-reply-from/actions/workflows/ci.yml)
4
4
  [![NPM version](https://img.shields.io/npm/v/@fastify/reply-from.svg?style=flat)](https://www.npmjs.com/package/@fastify/reply-from)
5
5
  [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/)
6
6
 
@@ -166,7 +166,7 @@ proxy.register(require('@fastify/reply-from'), {
166
166
  sessionOptions: { // HTTP/2 session connect options, pass in any options from https://nodejs.org/api/http2.html#http2_http2_connect_authority_options_listener
167
167
  rejectUnauthorized: true
168
168
  },
169
- requestTimeout: { // HTTP/2 request options, pass in any options from https://nodejs.org/api/http2.html#http2_clienthttp2session_request_headers_options
169
+ requestOptions: { // HTTP/2 request options, pass in any options from https://nodejs.org/api/http2.html#clienthttp2sessionrequestheaders-options
170
170
  endStream: true
171
171
  }
172
172
  }
@@ -203,8 +203,7 @@ This only applies when a custom [`body`](#body) is not passed in. Defaults to:
203
203
 
204
204
  ```js
205
205
  [
206
- 'application/json',
207
- 'application/x-www-form-urlencoded'
206
+ 'application/json'
208
207
  ]
209
208
  ```
210
209
 
@@ -217,6 +216,34 @@ By default: `['GET', 'HEAD', 'OPTIONS', 'TRACE' ]`
217
216
 
218
217
  This plugin will always retry on 503 errors, _unless_ `retryMethods` does not contain `GET`.
219
218
 
219
+ #### `globalAgent`
220
+
221
+ Enables the possibility to explictly opt-in for global agents.
222
+
223
+ Usage for undici global agent:
224
+ ```js
225
+ import { setGlobalDispatcher, ProxyAgent } from 'undici'
226
+
227
+ const proxyAgent = new ProxyAgent('my.proxy.server')
228
+ setGlobalDispatcher(proxyAgent)
229
+
230
+ fastify.register(FastifyReplyFrom, {
231
+ base: 'http://localhost:3001/',
232
+ globalAgent: true
233
+ })
234
+ ```
235
+
236
+ Usage for http/https global agent:
237
+ ```js
238
+ fastify.register(FastifyReplyFrom, {
239
+ base: 'http://localhost:3001/',
240
+ // http and https is allowed to use http.globalAgent or https.globalAgent
241
+ globalAgent: true,
242
+ http: {
243
+ }
244
+ })
245
+ ```
246
+
220
247
  ---
221
248
 
222
249
  #### `maxRetriesOn503`
package/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const fp = require('fastify-plugin')
4
- const lru = require('tiny-lru')
4
+ const { lru } = require('tiny-lru')
5
5
  const querystring = require('fast-querystring')
6
6
  const Stream = require('stream')
7
7
  const buildRequest = require('./lib/request')
@@ -21,7 +21,7 @@ const {
21
21
  InternalServerError
22
22
  } = require('./lib/errors')
23
23
 
24
- module.exports = fp(function from (fastify, opts, next) {
24
+ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
25
25
  const contentTypesToEncode = new Set([
26
26
  'application/json',
27
27
  ...(opts.contentTypesToEncode || [])
@@ -33,12 +33,18 @@ module.exports = fp(function from (fastify, opts, next) {
33
33
 
34
34
  const cache = opts.disableCache ? undefined : lru(opts.cacheURLs || 100)
35
35
  const base = opts.base
36
- const { request, close, retryOnError } = buildRequest({
36
+ const requestBuilt = buildRequest({
37
37
  http: opts.http,
38
38
  http2: opts.http2,
39
39
  base,
40
- undici: opts.undici
40
+ undici: opts.undici,
41
+ globalAgent: opts.globalAgent
41
42
  })
43
+ if (requestBuilt instanceof Error) {
44
+ next(requestBuilt)
45
+ return
46
+ }
47
+ const { request, close, retryOnError } = requestBuilt
42
48
  const disableRequestLogging = opts.disableRequestLogging || false
43
49
 
44
50
  fastify.decorateReply('from', function (source, opts) {
@@ -60,8 +66,9 @@ module.exports = fp(function from (fastify, opts, next) {
60
66
  const dest = getUpstream(req, base)
61
67
  let url
62
68
  if (cache) {
63
- url = cache.get(source) || buildURL(source, dest)
64
- cache.set(source, url)
69
+ const cacheKey = dest + source
70
+ url = cache.get(cacheKey) || buildURL(source, dest)
71
+ cache.set(cacheKey, url)
65
72
  } else {
66
73
  url = buildURL(source, dest)
67
74
  }
@@ -234,7 +241,9 @@ function onErrorDefault (reply, { error }) {
234
241
  }
235
242
 
236
243
  function isFastifyMultipartRegistered (fastify) {
237
- return fastify.hasContentTypeParser('multipart') && fastify.hasRequestDecorator('multipart')
244
+ // TODO: remove fastify.hasContentTypeParser('multipart') in next major
245
+ // It is used to be compatible with @fastify/multipart@<=7.3.0
246
+ return (fastify.hasContentTypeParser('multipart') || fastify.hasContentTypeParser('multipart/form-data')) && fastify.hasRequestDecorator('multipart')
238
247
  }
239
248
 
240
249
  function createRequestRetry (requestImpl, reply, retriesCount, retryOnError, maxRetriesOn503) {
@@ -274,3 +283,7 @@ function createRequestRetry (requestImpl, reply, retriesCount, retryOnError, max
274
283
 
275
284
  return requestRetry
276
285
  }
286
+
287
+ module.exports = fastifyReplyFrom
288
+ module.exports.default = fastifyReplyFrom
289
+ module.exports.fastifyReplyFrom = fastifyReplyFrom
package/lib/request.js CHANGED
@@ -41,21 +41,27 @@ function buildRequest (opts) {
41
41
  const httpOpts = getHttpOpts(opts)
42
42
  const baseUrl = opts.base && new URL(opts.base).origin
43
43
  const undiciOpts = opts.undici || {}
44
+ const globalAgent = opts.globalAgent
44
45
  let http2Client
45
46
  let undiciAgent
46
47
  let undiciInstance
47
48
  let agents
48
49
 
49
50
  if (isHttp2) {
50
- if (!opts.base) throw new Error('Option base is required when http2 is true')
51
+ if (!opts.base) return new Error('Option base is required when http2 is true')
51
52
  if (opts.base.startsWith('unix+')) {
52
- throw new Error('Unix socket destination is not supported when http2 is true')
53
+ return new Error('Unix socket destination is not supported when http2 is true')
53
54
  }
54
- } else {
55
+ } else if (!globalAgent) {
55
56
  agents = httpOpts.agents || {
56
57
  'http:': new http.Agent(httpOpts.agentOptions),
57
58
  'https:': new https.Agent(httpOpts.agentOptions)
58
59
  }
60
+ } else {
61
+ agents = {
62
+ 'http:': http.globalAgent,
63
+ 'https:': https.globalAgent
64
+ }
59
65
  }
60
66
 
61
67
  if (isHttp2) {
@@ -68,8 +74,10 @@ function buildRequest (opts) {
68
74
  undiciInstance = new undici.Pool(protocol + '://localhost', undiciOpts)
69
75
  } else if (isUndiciInstance(opts.undici)) {
70
76
  undiciInstance = opts.undici
71
- } else {
77
+ } else if (!globalAgent) {
72
78
  undiciAgent = new undici.Agent(getUndiciOptions(opts.undici))
79
+ } else {
80
+ undiciAgent = undici.getGlobalDispatcher()
73
81
  }
74
82
  return { request: handleUndici, close, retryOnError: 'UND_ERR_SOCKET' }
75
83
  } else {
@@ -77,6 +85,10 @@ function buildRequest (opts) {
77
85
  }
78
86
 
79
87
  function close () {
88
+ if (globalAgent) {
89
+ return
90
+ }
91
+
80
92
  if (hasUndiciOptions) {
81
93
  undiciAgent && undiciAgent.destroy()
82
94
  undiciInstance && undiciInstance.destroy()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastify/reply-from",
3
- "version": "8.3.0",
3
+ "version": "8.4.0",
4
4
  "description": "forward your HTTP request to another server, for fastify",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
@@ -28,10 +28,10 @@
28
28
  },
29
29
  "homepage": "https://github.com/fastify/fastify-reply-from#readme",
30
30
  "devDependencies": {
31
- "@fastify/formbody": "^7.0.1",
32
- "@fastify/multipart": "^7.1.0",
31
+ "@fastify/formbody": "^7.4.0",
32
+ "@fastify/multipart": "^7.4.0",
33
33
  "@fastify/pre-commit": "^2.0.2",
34
- "@sinonjs/fake-timers": "^9.1.2",
34
+ "@sinonjs/fake-timers": "^10.0.0",
35
35
  "@types/node": "^18.0.0",
36
36
  "@types/tap": "^15.0.7",
37
37
  "fastify": "^4.0.2",
@@ -46,7 +46,7 @@
46
46
  "split2": "^4.1.0",
47
47
  "standard": "^17.0.0",
48
48
  "tap": "^16.2.0",
49
- "tsd": "^0.23.0"
49
+ "tsd": "^0.25.0"
50
50
  },
51
51
  "dependencies": {
52
52
  "@fastify/error": "^3.0.0",
@@ -54,7 +54,7 @@
54
54
  "fast-querystring": "^1.0.0",
55
55
  "fastify-plugin": "^4.0.0",
56
56
  "pump": "^3.0.0",
57
- "tiny-lru": "^8.0.2",
57
+ "tiny-lru": "^10.0.0",
58
58
  "undici": "^5.5.1"
59
59
  },
60
60
  "pre-commit": [
@@ -0,0 +1,72 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const Fastify = require('fastify')
5
+ const From = require('..')
6
+
7
+ async function createTarget (i) {
8
+ const target = Fastify({
9
+ keepAliveTimeout: 1
10
+ })
11
+
12
+ target.get('/test', async () => {
13
+ return `Hello from target ${i}`
14
+ })
15
+
16
+ t.teardown(() => target.close())
17
+ await target.listen({ port: 3000 + i })
18
+ }
19
+
20
+ t.plan(4)
21
+
22
+ async function run () {
23
+ await Promise.all([
24
+ createTarget(1),
25
+ createTarget(2)
26
+ ])
27
+
28
+ const instance = Fastify({
29
+ keepAliveTimeout: 1
30
+ })
31
+
32
+ instance.register(From, {
33
+ base: 'http://localhost',
34
+ http: true
35
+ })
36
+
37
+ instance.get('/', (req, reply) => {
38
+ const hostNumber = parseInt(req.headers['x-host-number'])
39
+ const port = 3000 + hostNumber
40
+
41
+ reply.from('/test', {
42
+ getUpstream () {
43
+ return `http://localhost:${port}`
44
+ }
45
+ })
46
+ })
47
+
48
+ t.teardown(() => instance.close())
49
+ await instance.listen({ port: 3000 })
50
+
51
+ const res1 = await instance.inject({
52
+ method: 'GET',
53
+ url: '/',
54
+ headers: {
55
+ 'x-host-number': 1
56
+ }
57
+ })
58
+ t.equal(res1.statusCode, 200)
59
+ t.equal(res1.body, 'Hello from target 1')
60
+
61
+ const res2 = await instance.inject({
62
+ method: 'GET',
63
+ url: '/',
64
+ headers: {
65
+ 'x-host-number': 2
66
+ }
67
+ })
68
+ t.equal(res2.statusCode, 200)
69
+ t.equal(res2.body, 'Hello from target 2')
70
+ }
71
+
72
+ run()
@@ -0,0 +1,57 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const Fastify = require('fastify')
5
+ const From = require('..')
6
+ const http = require('http')
7
+ const get = require('simple-get').concat
8
+
9
+ test('http global agent is used, but not destroyed', async (t) => {
10
+ http.globalAgent.destroy = () => {
11
+ t.fail()
12
+ }
13
+ const instance = Fastify()
14
+ t.teardown(instance.close.bind(instance))
15
+ instance.get('/', (request, reply) => {
16
+ reply.from()
17
+ })
18
+
19
+ const target = http.createServer((req, res) => {
20
+ t.pass('request proxied')
21
+ t.equal(req.method, 'GET')
22
+ t.equal(req.url, '/')
23
+ res.statusCode = 200
24
+ res.end()
25
+ })
26
+ t.teardown(target.close.bind(target))
27
+
28
+ const executionFlow = () => new Promise((resolve) => {
29
+ target.listen({ port: 0 }, (err) => {
30
+ t.error(err)
31
+
32
+ instance.register(From, {
33
+ base: `http://localhost:${target.address().port}`,
34
+ globalAgent: true,
35
+ http: {
36
+ }
37
+ })
38
+
39
+ instance.listen({ port: 0 }, (err) => {
40
+ t.error(err)
41
+
42
+ get(
43
+ `http://localhost:${instance.server.address().port}`,
44
+ (err, res) => {
45
+ t.error(err)
46
+ t.equal(res.statusCode, 200)
47
+ resolve()
48
+ }
49
+ )
50
+ })
51
+ })
52
+ })
53
+
54
+ await executionFlow()
55
+
56
+ target.close()
57
+ })
@@ -0,0 +1,13 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const Fastify = require('fastify')
5
+ const From = require('../index')
6
+
7
+ test('http2 invalid base', async (t) => {
8
+ const instance = Fastify()
9
+
10
+ await t.rejects(instance.register(From, {
11
+ http2: { requestTimeout: 100 }
12
+ }), new Error('Option base is required when http2 is true'))
13
+ })
@@ -0,0 +1,16 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const Fastify = require('fastify')
5
+ const From = require('../index')
6
+
7
+ test('throw an error if http2 is used with a Unix socket destination', async t => {
8
+ t.plan(1)
9
+
10
+ const instance = Fastify()
11
+
12
+ await t.rejects(instance.register(From, {
13
+ base: 'unix+http://localhost:1337',
14
+ http2: { requestTimeout: 100 }
15
+ }), new Error('Unix socket destination is not supported when http2 is true'))
16
+ })
@@ -0,0 +1,69 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const Fastify = require('fastify')
5
+ const From = require('..')
6
+ const https = require('https')
7
+ const get = require('simple-get').concat
8
+
9
+ const fs = require('fs')
10
+ const path = require('path')
11
+ const certs = {
12
+ key: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.key')),
13
+ cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.cert'))
14
+ }
15
+
16
+ test('https global agent is used, but not destroyed', async (t) => {
17
+ https.globalAgent.destroy = () => {
18
+ t.fail()
19
+ }
20
+ const instance = Fastify({
21
+ https: certs
22
+ })
23
+ t.teardown(instance.close.bind(instance))
24
+ instance.get('/', (request, reply) => {
25
+ reply.from()
26
+ })
27
+
28
+ const target = https.createServer(certs, (req, res) => {
29
+ t.pass('request proxied')
30
+ t.equal(req.method, 'GET')
31
+ t.equal(req.url, '/')
32
+ res.statusCode = 200
33
+ res.end()
34
+ })
35
+ t.teardown(target.close.bind(target))
36
+
37
+ const executionFlow = () => new Promise((resolve) => {
38
+ target.listen({ port: 0 }, (err) => {
39
+ t.error(err)
40
+
41
+ instance.register(From, {
42
+ base: `https://localhost:${target.address().port}`,
43
+ globalAgent: true,
44
+ http: {
45
+ }
46
+ })
47
+
48
+ instance.listen({ port: 0 }, (err) => {
49
+ t.error(err)
50
+
51
+ get(
52
+ {
53
+ url: `https://localhost:${instance.server.address().port}`,
54
+ rejectUnauthorized: false
55
+ },
56
+ (err, res) => {
57
+ t.error(err)
58
+ t.equal(res.statusCode, 200)
59
+ resolve()
60
+ }
61
+ )
62
+ })
63
+ })
64
+ })
65
+
66
+ await executionFlow()
67
+
68
+ target.close()
69
+ })
@@ -0,0 +1,131 @@
1
+ 'use strict'
2
+
3
+ const test = require('tap').test
4
+ const Fastify = require('fastify')
5
+ const From = require('../index')
6
+ const http = require('http')
7
+ const get = require('simple-get').concat
8
+ const { parse } = require('querystring')
9
+
10
+ test('with explicitly set content-type application/octet-stream', t => {
11
+ const instance = Fastify()
12
+ instance.register(From, {
13
+ contentTypesToEncode: ['application/octet-stream']
14
+ })
15
+
16
+ instance.addContentTypeParser(
17
+ 'application/octet-stream',
18
+ { parseAs: 'buffer', bodyLimit: 1000 },
19
+ (req, body, done) => done(null, parse(body.toString()))
20
+ )
21
+
22
+ t.plan(9)
23
+ t.teardown(instance.close.bind(instance))
24
+
25
+ const target = http.createServer((req, res) => {
26
+ t.pass('request proxied')
27
+ t.equal(req.method, 'POST')
28
+ t.equal(req.headers['content-type'], 'application/octet-stream')
29
+ let data = ''
30
+ req.setEncoding('utf8')
31
+ req.on('data', (d) => {
32
+ data += d
33
+ })
34
+ req.on('end', () => {
35
+ const str = data.toString()
36
+ t.same(JSON.parse(data), { some: 'info', another: 'detail' })
37
+ res.statusCode = 200
38
+ res.setHeader('content-type', 'application/octet-stream')
39
+ res.end(str)
40
+ })
41
+ })
42
+
43
+ instance.post('/', (request, reply) => {
44
+ reply.from(`http://localhost:${target.address().port}`)
45
+ })
46
+
47
+ t.teardown(target.close.bind(target))
48
+
49
+ instance.listen({ port: 0 }, (err) => {
50
+ t.error(err)
51
+
52
+ target.listen({ port: 0 }, (err) => {
53
+ t.error(err)
54
+
55
+ get({
56
+ url: `http://localhost:${instance.server.address().port}`,
57
+ method: 'POST',
58
+ headers: { 'content-type': 'application/octet-stream' },
59
+ body: 'some=info&another=detail'
60
+ }, (err, res, data) => {
61
+ t.error(err)
62
+ t.equal(res.headers['content-type'], 'application/octet-stream')
63
+ t.same(JSON.parse(data), { some: 'info', another: 'detail' })
64
+ })
65
+ })
66
+ })
67
+ })
68
+
69
+ test('with implicit content-type application/octet-stream', t => {
70
+ const instance = Fastify()
71
+ instance.register(From, {
72
+ contentTypesToEncode: ['application/octet-stream']
73
+ })
74
+
75
+ instance.addContentTypeParser(
76
+ 'application/octet-stream',
77
+ { parseAs: 'buffer', bodyLimit: 1000 },
78
+ (req, body, done) => done(null, parse(body.toString()))
79
+ )
80
+
81
+ instance.addContentTypeParser(
82
+ '*',
83
+ { parseAs: 'buffer', bodyLimit: 1000 },
84
+ (req, body, done) => done(null, parse(body.toString()))
85
+ )
86
+
87
+ t.plan(9)
88
+ t.teardown(instance.close.bind(instance))
89
+
90
+ const target = http.createServer((req, res) => {
91
+ t.pass('request proxied')
92
+ t.equal(req.method, 'POST')
93
+ t.equal(req.headers['content-type'], 'application/octet-stream')
94
+ let data = ''
95
+ req.setEncoding('utf8')
96
+ req.on('data', (d) => {
97
+ data += d
98
+ })
99
+ req.on('end', () => {
100
+ const str = data.toString()
101
+ t.same(JSON.parse(data), { some: 'info', another: 'detail' })
102
+ res.statusCode = 200
103
+ res.setHeader('content-type', 'application/octet-stream')
104
+ res.end(str)
105
+ })
106
+ })
107
+
108
+ instance.post('/', (request, reply) => {
109
+ reply.from(`http://localhost:${target.address().port}`)
110
+ })
111
+
112
+ t.teardown(target.close.bind(target))
113
+
114
+ instance.listen({ port: 0 }, (err) => {
115
+ t.error(err)
116
+
117
+ target.listen({ port: 0 }, (err) => {
118
+ t.error(err)
119
+
120
+ get({
121
+ url: `http://localhost:${instance.server.address().port}`,
122
+ method: 'POST',
123
+ body: 'some=info&another=detail'
124
+ }, (err, res, data) => {
125
+ t.error(err)
126
+ t.equal(res.headers['content-type'], 'application/octet-stream')
127
+ t.same(JSON.parse(data), { some: 'info', another: 'detail' })
128
+ })
129
+ })
130
+ })
131
+ })
@@ -0,0 +1,66 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const Fastify = require('fastify')
5
+ const http = require('http')
6
+ const get = require('simple-get').concat
7
+ const undici = require('undici')
8
+ const From = require('..')
9
+
10
+ test('undici global agent is used, but not destroyed', async (t) => {
11
+ const mockAgent = new undici.Agent()
12
+ mockAgent.destroy = () => {
13
+ t.fail()
14
+ }
15
+ undici.setGlobalDispatcher(mockAgent)
16
+ const instance = Fastify()
17
+
18
+ t.teardown(instance.close.bind(instance))
19
+
20
+ const target = http.createServer((req, res) => {
21
+ res.statusCode = 200
22
+ res.end()
23
+ })
24
+
25
+ instance.get('/', (request, reply) => {
26
+ reply.from()
27
+ })
28
+
29
+ t.teardown(target.close.bind(target))
30
+
31
+ const executionFlow = () => new Promise((resolve) => {
32
+ target.listen({ port: 0 }, (err) => {
33
+ t.error(err)
34
+
35
+ instance.register(From, {
36
+ base: `http://localhost:${target.address().port}`,
37
+ globalAgent: true
38
+ })
39
+
40
+ instance.listen({ port: 0 }, (err) => {
41
+ t.error(err)
42
+
43
+ get(
44
+ `http://localhost:${instance.server.address().port}`,
45
+ (err, res) => {
46
+ t.error(err)
47
+ t.equal(res.statusCode, 200)
48
+
49
+ get(
50
+ `http://localhost:${instance.server.address().port}`,
51
+ (err, res) => {
52
+ t.error(err)
53
+ t.equal(res.statusCode, 200)
54
+ resolve()
55
+ }
56
+ )
57
+ }
58
+ )
59
+ })
60
+ })
61
+ })
62
+
63
+ await executionFlow()
64
+
65
+ target.close()
66
+ })
@@ -0,0 +1,18 @@
1
+ 'use strict'
2
+
3
+ const test = require('tap').test
4
+ const filterPseudoHeaders = require('../lib/utils').filterPseudoHeaders
5
+
6
+ test('filterPseudoHeaders', t => {
7
+ t.plan(1)
8
+ const headers = {
9
+ accept: '*/*',
10
+ 'Content-Type': 'text/html; charset=UTF-8',
11
+ ':method': 'GET'
12
+ }
13
+
14
+ t.strictSame(filterPseudoHeaders(headers), {
15
+ accept: '*/*',
16
+ 'content-type': 'text/html; charset=UTF-8'
17
+ })
18
+ })
package/types/index.d.ts CHANGED
@@ -30,68 +30,77 @@ import {
30
30
  SecureClientSessionOptions,
31
31
  } from "http2";
32
32
  import { Pool } from 'undici'
33
- type QueryStringFunction = (search: string | undefined, reqUrl: string) => string;
34
- export interface FastifyReplyFromHooks {
35
- queryString?: { [key: string]: unknown } | QueryStringFunction;
36
- contentType?: string;
37
- onResponse?: (
38
- request: FastifyRequest<RequestGenericInterface, RawServerBase>,
39
- reply: FastifyReply<RawServerBase>,
40
- res: RawReplyDefaultExpression<RawServerBase>
41
- ) => void;
42
- onError?: (
43
- reply: FastifyReply<RawServerBase>,
44
- error: { error: Error }
45
- ) => void;
46
- body?: unknown;
47
- rewriteHeaders?: (
48
- headers: Http2IncomingHttpHeaders | IncomingHttpHeaders,
49
- req?: Http2ServerRequest | IncomingMessage
50
- ) => Http2IncomingHttpHeaders | IncomingHttpHeaders;
51
- rewriteRequestHeaders?: (
52
- req: Http2ServerRequest | IncomingMessage,
53
- headers: Http2IncomingHttpHeaders | IncomingHttpHeaders
54
- ) => Http2IncomingHttpHeaders | IncomingHttpHeaders;
55
- getUpstream?: (
56
- req: Http2ServerRequest | IncomingMessage,
57
- base: string
58
- ) => string;
59
- }
60
33
 
61
34
  declare module "fastify" {
62
35
  interface FastifyReply {
63
36
  from(
64
37
  source?: string,
65
- opts?: FastifyReplyFromHooks
66
- ): void;
38
+ opts?: fastifyReplyFrom.FastifyReplyFromHooks
39
+ ): this;
67
40
  }
68
41
  }
69
42
 
70
- interface Http2Options {
71
- sessionTimeout?: number;
72
- requestTimeout?: number;
73
- sessionOptions?: ClientSessionOptions | SecureClientSessionOptions;
74
- requestOptions?: ClientSessionRequestOptions;
75
- }
43
+ type FastifyReplyFrom = FastifyPluginCallback<fastifyReplyFrom.FastifyReplyFromOptions>
76
44
 
77
- interface HttpOptions {
78
- agentOptions?: AgentOptions | SecureAgentOptions;
79
- requestOptions?: RequestOptions | SecureRequestOptions;
80
- agents?: { 'http:': Agent, 'https:': SecureAgent }
81
- }
45
+ declare namespace fastifyReplyFrom {
46
+ type QueryStringFunction = (search: string | undefined, reqUrl: string) => string;
47
+ export interface FastifyReplyFromHooks {
48
+ queryString?: { [key: string]: unknown } | QueryStringFunction;
49
+ contentType?: string;
50
+ onResponse?: (
51
+ request: FastifyRequest<RequestGenericInterface, RawServerBase>,
52
+ reply: FastifyReply<RawServerBase>,
53
+ res: RawReplyDefaultExpression<RawServerBase>
54
+ ) => void;
55
+ onError?: (
56
+ reply: FastifyReply<RawServerBase>,
57
+ error: { error: Error }
58
+ ) => void;
59
+ body?: unknown;
60
+ rewriteHeaders?: (
61
+ headers: Http2IncomingHttpHeaders | IncomingHttpHeaders,
62
+ req?: Http2ServerRequest | IncomingMessage
63
+ ) => Http2IncomingHttpHeaders | IncomingHttpHeaders;
64
+ rewriteRequestHeaders?: (
65
+ req: Http2ServerRequest | IncomingMessage,
66
+ headers: Http2IncomingHttpHeaders | IncomingHttpHeaders
67
+ ) => Http2IncomingHttpHeaders | IncomingHttpHeaders;
68
+ getUpstream?: (
69
+ req: Http2ServerRequest | IncomingMessage,
70
+ base: string
71
+ ) => string;
72
+ }
73
+
74
+ interface Http2Options {
75
+ sessionTimeout?: number;
76
+ requestTimeout?: number;
77
+ sessionOptions?: ClientSessionOptions | SecureClientSessionOptions;
78
+ requestOptions?: ClientSessionRequestOptions;
79
+ }
80
+
81
+ interface HttpOptions {
82
+ agentOptions?: AgentOptions | SecureAgentOptions;
83
+ requestOptions?: RequestOptions | SecureRequestOptions;
84
+ agents?: { 'http:': Agent, 'https:': SecureAgent }
85
+ }
86
+
87
+ export interface FastifyReplyFromOptions {
88
+ base?: string;
89
+ cacheURLs?: number;
90
+ disableCache?: boolean;
91
+ http?: HttpOptions;
92
+ http2?: Http2Options | boolean;
93
+ undici?: Pool.Options;
94
+ contentTypesToEncode?: string[];
95
+ retryMethods?: (HTTPMethods | 'TRACE')[];
96
+ maxRetriesOn503?: number;
97
+ disableRequestLogging?: boolean;
98
+ globalAgent?: boolean;
99
+ }
82
100
 
83
- export interface FastifyReplyFromOptions {
84
- base?: string;
85
- cacheURLs?: number;
86
- disableCache?: boolean;
87
- http?: HttpOptions;
88
- http2?: Http2Options | boolean;
89
- undici?: Pool.Options;
90
- contentTypesToEncode?: string[];
91
- retryMethods?: (HTTPMethods | 'TRACE')[];
92
- maxRetriesOn503?: number;
93
- disableRequestLogging?: boolean;
101
+ export const fastifyReplyFrom: FastifyReplyFrom
102
+ export { fastifyReplyFrom as default }
94
103
  }
95
104
 
96
- declare const fastifyReplyFrom: FastifyPluginCallback<FastifyReplyFromOptions>;
97
- export default fastifyReplyFrom;
105
+ declare function fastifyReplyFrom(...params: Parameters<FastifyReplyFrom>): ReturnType<FastifyReplyFrom>
106
+ export = fastifyReplyFrom
@@ -45,6 +45,7 @@ const fullOptions: FastifyReplyFromOptions = {
45
45
  retryMethods: ['GET', 'HEAD', 'OPTIONS', 'TRACE'],
46
46
  maxRetriesOn503: 10,
47
47
  disableRequestLogging: false,
48
+ globalAgent: false,
48
49
  };
49
50
  tap.autoend(false);
50
51
 
@@ -60,7 +61,7 @@ async function main() {
60
61
  server.register(replyFrom, fullOptions);
61
62
 
62
63
  server.get("/v1", (request, reply) => {
63
- reply.from();
64
+ expectType<FastifyReply>(reply.from());
64
65
  });
65
66
  server.get("/v3", (request, reply) => {
66
67
  reply.from("/v3", {