@fastify/static 6.1.0 → 6.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
@@ -190,7 +190,9 @@ If set, it provide the directory list calling the directory path.
190
190
 
191
191
  Default response is json.
192
192
 
193
- Note: Multi-root is not supported within the `list` option.
193
+ Note:
194
+ - Multi-root is not supported within the `list` option.
195
+ - If `dotfiles` option value is `deny` or `ignore`, dotfiles will be excluded.
194
196
 
195
197
  **Example:**
196
198
 
package/index.d.ts CHANGED
@@ -8,91 +8,108 @@ import { Stats } from 'fs';
8
8
  declare module "fastify" {
9
9
  interface FastifyReply {
10
10
  sendFile(filename: string, rootPath?: string): FastifyReply;
11
- sendFile(filename: string, options?: SendOptions): FastifyReply;
12
- sendFile(filename: string, rootPath?: string, options?: SendOptions): FastifyReply;
13
- download(filepath: string, options?: SendOptions): FastifyReply;
11
+ sendFile(filename: string, options?: fastifyStatic.SendOptions): FastifyReply;
12
+ sendFile(filename: string, rootPath?: string, options?: fastifyStatic.SendOptions): FastifyReply;
13
+ download(filepath: string, options?: fastifyStatic.SendOptions): FastifyReply;
14
14
  download(filepath: string, filename?: string): FastifyReply;
15
- download(filepath: string, filename?: string, options?: SendOptions): FastifyReply;
15
+ download(filepath: string, filename?: string, options?: fastifyStatic.SendOptions): FastifyReply;
16
16
  }
17
17
  }
18
18
 
19
- interface ExtendedInformation {
20
- fileCount: number;
21
- totalFileCount: number;
22
- folderCount: number;
23
- totalFolderCount: number;
24
- totalSize: number;
25
- lastModified: number;
26
- }
19
+ type FastifyStaticPlugin = FastifyPluginCallback<NonNullable<fastifyStatic.FastifyStaticOptions>>;
27
20
 
28
- interface ListDir {
29
- href: string;
30
- name: string;
31
- stats: Stats;
32
- extendedInfo?: ExtendedInformation;
33
- }
21
+ declare namespace fastifyStatic {
22
+ export interface ExtendedInformation {
23
+ fileCount: number;
24
+ totalFileCount: number;
25
+ folderCount: number;
26
+ totalFolderCount: number;
27
+ totalSize: number;
28
+ lastModified: number;
29
+ }
34
30
 
35
- interface ListFile {
36
- href: string;
37
- name: string;
38
- stats: Stats;
39
- }
31
+ export interface ListDir {
32
+ href: string;
33
+ name: string;
34
+ stats: Stats;
35
+ extendedInfo?: ExtendedInformation;
36
+ }
40
37
 
41
- interface ListRender {
42
- (dirs: ListDir[], files: ListFile[]): string;
43
- }
38
+ export interface ListFile {
39
+ href: string;
40
+ name: string;
41
+ stats: Stats;
42
+ }
44
43
 
45
- interface ListOptions {
46
- format: 'json' | 'html';
47
- names: string[];
48
- render: ListRender;
49
- extendedFolderInfo?: boolean;
50
- jsonFormat?: 'names' | 'extended';
51
- }
44
+ export interface ListRender {
45
+ (dirs: ListDir[], files: ListFile[]): string;
46
+ }
52
47
 
53
- // Passed on to `send`
54
- interface SendOptions {
55
- acceptRanges?: boolean;
56
- cacheControl?: boolean;
57
- dotfiles?: 'allow' | 'deny' | 'ignore';
58
- etag?: boolean;
59
- extensions?: string[];
60
- immutable?: boolean;
61
- index?: string[] | string | false;
62
- lastModified?: boolean;
63
- maxAge?: string | number;
64
- }
48
+ export interface ListOptions {
49
+ names?: string[];
50
+ extendedFolderInfo?: boolean;
51
+ jsonFormat?: 'names' | 'extended';
52
+ }
65
53
 
66
- export interface FastifyStaticOptions extends SendOptions {
67
- root: string | string[];
68
- prefix?: string;
69
- prefixAvoidTrailingSlash?: boolean;
70
- serve?: boolean;
71
- decorateReply?: boolean;
72
- schemaHide?: boolean;
73
- setHeaders?: (...args: any[]) => void;
74
- redirect?: boolean;
75
- wildcard?: boolean;
76
- list?: boolean | ListOptions;
77
- allowedPath?: (pathName: string, root?: string) => boolean;
78
- /**
79
- * @description
80
- * Opt-in to looking for pre-compressed files
81
- */
82
- preCompressed?: boolean;
54
+ export interface ListOptionsJsonFormat extends ListOptions {
55
+ format: 'json';
56
+ // Required when the URL parameter `format=html` exists
57
+ render?: ListRender;
58
+ }
59
+
60
+ export interface ListOptionsHtmlFormat extends ListOptions {
61
+ format: 'html';
62
+ render: ListRender;
63
+ }
83
64
 
84
65
  // Passed on to `send`
85
- acceptRanges?: boolean;
86
- cacheControl?: boolean;
87
- dotfiles?: 'allow' | 'deny' | 'ignore';
88
- etag?: boolean;
89
- extensions?: string[];
90
- immutable?: boolean;
91
- index?: string[] | string | false;
92
- lastModified?: boolean;
93
- maxAge?: string | number;
66
+ export interface SendOptions {
67
+ acceptRanges?: boolean;
68
+ cacheControl?: boolean;
69
+ dotfiles?: 'allow' | 'deny' | 'ignore';
70
+ etag?: boolean;
71
+ extensions?: string[];
72
+ immutable?: boolean;
73
+ index?: string[] | string | false;
74
+ lastModified?: boolean;
75
+ maxAge?: string | number;
76
+ }
77
+
78
+ export interface FastifyStaticOptions extends SendOptions {
79
+ root: string | string[];
80
+ prefix?: string;
81
+ prefixAvoidTrailingSlash?: boolean;
82
+ serve?: boolean;
83
+ decorateReply?: boolean;
84
+ schemaHide?: boolean;
85
+ setHeaders?: (...args: any[]) => void;
86
+ redirect?: boolean;
87
+ wildcard?: boolean;
88
+ list?: boolean | ListOptionsJsonFormat | ListOptionsHtmlFormat;
89
+ allowedPath?: (pathName: string, root?: string) => boolean;
90
+ /**
91
+ * @description
92
+ * Opt-in to looking for pre-compressed files
93
+ */
94
+ preCompressed?: boolean;
95
+
96
+ // Passed on to `send`
97
+ acceptRanges?: boolean;
98
+ cacheControl?: boolean;
99
+ dotfiles?: 'allow' | 'deny' | 'ignore';
100
+ etag?: boolean;
101
+ extensions?: string[];
102
+ immutable?: boolean;
103
+ index?: string[] | string | false;
104
+ lastModified?: boolean;
105
+ maxAge?: string | number;
106
+ }
107
+
108
+ export const fastifyStatic: FastifyStaticPlugin;
109
+
110
+ export { fastifyStatic as default };
94
111
  }
95
112
 
96
- export declare const fastifyStatic: FastifyPluginCallback<FastifyStaticOptions>
113
+ declare function fastifyStatic(...params: Parameters<FastifyStaticPlugin>): ReturnType<FastifyStaticPlugin>;
97
114
 
98
- export default fastifyStatic;
115
+ export = fastifyStatic;
package/index.js CHANGED
@@ -9,7 +9,7 @@ const contentDisposition = require('content-disposition')
9
9
  const fp = require('fastify-plugin')
10
10
  const util = require('util')
11
11
  const globPromise = util.promisify(glob)
12
- const encodingNegotiator = require('encoding-negotiator')
12
+ const encodingNegotiator = require('@fastify/accept-negotiator')
13
13
 
14
14
  const dirList = require('./lib/dirList')
15
15
 
@@ -161,7 +161,8 @@ async function fastifyStatic (fastify, opts) {
161
161
  dir: path,
162
162
  options: opts.list,
163
163
  route: pathname,
164
- prefix
164
+ prefix,
165
+ dotfiles: opts.dotfiles
165
166
  }).catch((err) => reply.send(err))
166
167
  return
167
168
  }
@@ -194,7 +195,7 @@ async function fastifyStatic (fastify, opts) {
194
195
 
195
196
  stream.on('error', function (err) {
196
197
  if (err.code === 'ENOENT') {
197
- // when preCompress is enabled and the path is a directoy without a trailing shash
198
+ // when preCompress is enabled and the path is a directory without a trailing slash
198
199
  if (opts.preCompressed && encoding) {
199
200
  const indexPathname = findIndexFile(pathname, options.root, options.index)
200
201
  if (indexPathname) {
@@ -217,7 +218,8 @@ async function fastifyStatic (fastify, opts) {
217
218
  dir: dirList.path(opts.root, pathname),
218
219
  options: opts.list,
219
220
  route: pathname,
220
- prefix
221
+ prefix,
222
+ dotfiles: opts.dotfiles
221
223
  }).catch((err) => reply.send(err))
222
224
  return
223
225
  }
@@ -492,7 +494,7 @@ function getEncodingExtension (encoding) {
492
494
 
493
495
  function getRedirectUrl (url) {
494
496
  let i = 0
495
- // we detech how many slash before a valid path
497
+ // we detect how many slash before a valid path
496
498
  for (i; i < url.length; i++) {
497
499
  if (url[i] !== '/' && url[i] !== '\\') break
498
500
  }
package/lib/dirList.js CHANGED
@@ -8,12 +8,16 @@ const dirList = {
8
8
  /**
9
9
  * get files and dirs from dir, or error
10
10
  * @param {string} dir full path fs dir
11
- * @param {function(error, entries)} callback
11
+ * @param {(boolean | ListOptionsJsonFormat | ListOptionsHtmlFormat)} options
12
+ * @param {string} dotfiles
12
13
  * note: can't use glob because don't get error on non existing dir
13
14
  */
14
- list: async function (dir, options) {
15
+ list: async function (dir, options, dotfiles) {
15
16
  const entries = { dirs: [], files: [] }
16
- const files = await fs.readdir(dir)
17
+ let files = await fs.readdir(dir)
18
+ if (dotfiles === 'deny' || dotfiles === 'ignore') {
19
+ files = files.filter(f => f.charAt(0) !== '.')
20
+ }
17
21
  if (files.length < 1) {
18
22
  return entries
19
23
  }
@@ -95,13 +99,18 @@ const dirList = {
95
99
  * send dir list content, or 404 on error
96
100
  * @param {Fastify.Reply} reply
97
101
  * @param {string} dir full path fs dir
98
- * @param {ListOptions} options
102
+ * @param {(boolean | ListOptionsJsonFormat | ListOptionsHtmlFormat)} options
99
103
  * @param {string} route request route
104
+ * @param {string} dotfiles
100
105
  */
101
- send: async function ({ reply, dir, options, route, prefix }) {
106
+ send: async function ({ reply, dir, options, route, prefix, dotfiles }) {
107
+ if (reply.request.query.format === 'html' && typeof options.render !== 'function') {
108
+ throw new Error('The `list.render` option must be a function and is required with the URL parameter `format=html`')
109
+ }
110
+
102
111
  let entries
103
112
  try {
104
- entries = await dirList.list(dir, options)
113
+ entries = await dirList.list(dir, options, dotfiles)
105
114
  } catch (error) {
106
115
  return reply.callNotFound()
107
116
  }
@@ -146,7 +155,7 @@ const dirList = {
146
155
  /**
147
156
  * say if the route can be handled by dir list or not
148
157
  * @param {string} route request route
149
- * @param {ListOptions} options
158
+ * @param {(boolean | ListOptionsJsonFormat | ListOptionsHtmlFormat)} options
150
159
  * @return {boolean}
151
160
  */
152
161
  handle: function (route, options) {
@@ -189,6 +198,9 @@ const dirList = {
189
198
  if (options.list.names && !Array.isArray(options.list.names)) {
190
199
  return new TypeError('The `list.names` option must be an array')
191
200
  }
201
+ if (options.list.jsonFormat != null && options.list.jsonFormat !== 'names' && options.list.jsonFormat !== 'extended') {
202
+ return new TypeError('The `list.jsonFormat` option must be name or extended')
203
+ }
192
204
  if (options.list.format === 'html' && typeof options.list.render !== 'function') {
193
205
  return new TypeError('The `list.render` option must be a function and is required with html format')
194
206
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastify/static",
3
- "version": "6.1.0",
3
+ "version": "6.3.1",
4
4
  "description": "Plugin for serving static files as fast as possible.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -30,16 +30,16 @@
30
30
  "homepage": "https://github.com/fastify/fastify-static",
31
31
  "dependencies": {
32
32
  "content-disposition": "^0.5.3",
33
- "encoding-negotiator": "^2.0.1",
34
- "fastify-plugin": "^3.0.0",
33
+ "@fastify/accept-negotiator": "^1.0.0",
34
+ "fastify-plugin": "^4.0.0",
35
35
  "glob": "^8.0.1",
36
36
  "p-limit": "^3.1.0",
37
- "readable-stream": "^3.4.0",
37
+ "readable-stream": "^4.0.0",
38
38
  "send": "^0.18.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@fastify/compress": "^6.0.0",
42
- "@types/node": "^17.0.0",
42
+ "@types/node": "^18.0.0",
43
43
  "@typescript-eslint/eslint-plugin": "^2.29.0",
44
44
  "@typescript-eslint/parser": "^2.29.0",
45
45
  "concat-stream": "^2.0.0",
@@ -53,7 +53,7 @@
53
53
  "snazzy": "^9.0.0",
54
54
  "standard": "^17.0.0",
55
55
  "tap": "^16.0.0",
56
- "tsd": "^0.20.0",
56
+ "tsd": "^0.22.0",
57
57
  "typescript": "^4.0.2"
58
58
  },
59
59
  "tsd": {
@@ -40,7 +40,7 @@ t.test('throws when `root` is an array', t => {
40
40
  t.equal(err.message, 'multi-root with list option is not supported')
41
41
  })
42
42
 
43
- t.test('throws when `list.format option` is invalid', t => {
43
+ t.test('throws when `list.format` option is invalid', t => {
44
44
  t.plan(2)
45
45
 
46
46
  const err = dirList.validateOptions({ list: { format: 'hello' } })
@@ -56,6 +56,14 @@ t.test('throws when `list.names option` is not an array', t => {
56
56
  t.equal(err.message, 'The `list.names` option must be an array')
57
57
  })
58
58
 
59
+ t.test('throws when `list.jsonFormat` option is invalid', t => {
60
+ t.plan(2)
61
+
62
+ const err = dirList.validateOptions({ list: { jsonFormat: 'hello' } })
63
+ t.type(err, TypeError)
64
+ t.equal(err.message, 'The `list.jsonFormat` option must be name or extended')
65
+ })
66
+
59
67
  t.test('throws when `list.format` is html and `list render` is not a function', t => {
60
68
  t.plan(2)
61
69
 
@@ -469,7 +477,103 @@ t.test('dir list json format - extended info', t => {
469
477
  })
470
478
  })
471
479
 
472
- t.test('dir list - url parameter format', t => {
480
+ t.test('json format with url parameter format', t => {
481
+ t.plan(13)
482
+
483
+ const options = {
484
+ root: path.join(__dirname, '/static'),
485
+ prefix: '/public',
486
+ index: false,
487
+ list: {
488
+ format: 'json',
489
+ render (dirs, files) {
490
+ return 'html'
491
+ }
492
+ }
493
+ }
494
+ const route = '/public/'
495
+ const jsonContent = { dirs: ['deep', 'shallow'], files: ['.example', 'a .md', 'foo.html', 'foobar.html', 'index.css', 'index.html'] }
496
+
497
+ helper.arrange(t, options, (url) => {
498
+ simple.concat({
499
+ method: 'GET',
500
+ url: url + route
501
+ }, (err, response, body) => {
502
+ t.error(err)
503
+ t.equal(response.statusCode, 200)
504
+ t.equal(body.toString(), JSON.stringify(jsonContent))
505
+ t.ok(response.headers['content-type'].includes('application/json'))
506
+ })
507
+
508
+ simple.concat({
509
+ method: 'GET',
510
+ url: url + route + '?format=html'
511
+ }, (err, response, body) => {
512
+ t.error(err)
513
+ t.equal(response.statusCode, 200)
514
+ t.equal(body.toString(), 'html')
515
+ t.ok(response.headers['content-type'].includes('text/html'))
516
+ })
517
+
518
+ simple.concat({
519
+ method: 'GET',
520
+ url: url + route + '?format=json'
521
+ }, (err, response, body) => {
522
+ t.error(err)
523
+ t.equal(response.statusCode, 200)
524
+ t.equal(body.toString(), JSON.stringify(jsonContent))
525
+ t.ok(response.headers['content-type'].includes('application/json'))
526
+ })
527
+ })
528
+ })
529
+
530
+ t.test('json format with url parameter format and without render option', t => {
531
+ t.plan(12)
532
+
533
+ const options = {
534
+ root: path.join(__dirname, '/static'),
535
+ prefix: '/public',
536
+ index: false,
537
+ list: {
538
+ format: 'json'
539
+ }
540
+ }
541
+ const route = '/public/'
542
+ const jsonContent = { dirs: ['deep', 'shallow'], files: ['.example', 'a .md', 'foo.html', 'foobar.html', 'index.css', 'index.html'] }
543
+
544
+ helper.arrange(t, options, (url) => {
545
+ simple.concat({
546
+ method: 'GET',
547
+ url: url + route
548
+ }, (err, response, body) => {
549
+ t.error(err)
550
+ t.equal(response.statusCode, 200)
551
+ t.equal(body.toString(), JSON.stringify(jsonContent))
552
+ t.ok(response.headers['content-type'].includes('application/json'))
553
+ })
554
+
555
+ simple.concat({
556
+ method: 'GET',
557
+ url: url + route + '?format=html'
558
+ }, (err, response, body) => {
559
+ t.error(err)
560
+ t.equal(response.statusCode, 500)
561
+ t.equal(JSON.parse(body.toString()).message, 'The `list.render` option must be a function and is required with the URL parameter `format=html`')
562
+ })
563
+
564
+ simple.concat({
565
+ method: 'GET',
566
+ url: url + route + '?format=json'
567
+ }, (err, response, body) => {
568
+ t.error(err)
569
+ t.equal(response.statusCode, 200)
570
+ t.equal(body.toString(), JSON.stringify(jsonContent))
571
+ t.ok(response.headers['content-type'].includes('application/json'))
572
+ })
573
+ })
574
+ })
575
+
576
+ t.test('html format with url parameter format', t => {
473
577
  t.plan(13)
474
578
 
475
579
  const options = {
@@ -484,6 +588,7 @@ t.test('dir list - url parameter format', t => {
484
588
  }
485
589
  }
486
590
  const route = '/public/'
591
+ const jsonContent = { dirs: ['deep', 'shallow'], files: ['.example', 'a .md', 'foo.html', 'foobar.html', 'index.css', 'index.html'] }
487
592
 
488
593
  helper.arrange(t, options, (url) => {
489
594
  simple.concat({
@@ -512,7 +617,7 @@ t.test('dir list - url parameter format', t => {
512
617
  }, (err, response, body) => {
513
618
  t.error(err)
514
619
  t.equal(response.statusCode, 200)
515
- t.ok(body.toString())
620
+ t.equal(body.toString(), JSON.stringify(jsonContent))
516
621
  t.ok(response.headers['content-type'].includes('application/json'))
517
622
  })
518
623
  })
@@ -636,6 +741,90 @@ t.test('serve a non existent dir and get error', t => {
636
741
  })
637
742
  })
638
743
 
744
+ t.test('dir list with dotfiles allow option', t => {
745
+ t.plan(2)
746
+
747
+ const options = {
748
+ root: path.join(__dirname, '/static-dotfiles'),
749
+ prefix: '/public',
750
+ dotfiles: 'allow',
751
+ index: false,
752
+ list: true
753
+ }
754
+ const route = '/public/'
755
+ const content = { dirs: ['dir'], files: ['.aaa', 'test.txt'] }
756
+
757
+ helper.arrange(t, options, (url) => {
758
+ t.test(route, t => {
759
+ t.plan(3)
760
+ simple.concat({
761
+ method: 'GET',
762
+ url: url + route
763
+ }, (err, response, body) => {
764
+ t.error(err)
765
+ t.equal(response.statusCode, 200)
766
+ t.equal(body.toString(), JSON.stringify(content))
767
+ })
768
+ })
769
+ })
770
+ })
771
+
772
+ t.test('dir list with dotfiles deny option', t => {
773
+ t.plan(2)
774
+
775
+ const options = {
776
+ root: path.join(__dirname, '/static-dotfiles'),
777
+ prefix: '/public',
778
+ dotfiles: 'deny',
779
+ index: false,
780
+ list: true
781
+ }
782
+ const route = '/public/'
783
+ const content = { dirs: ['dir'], files: ['test.txt'] }
784
+
785
+ helper.arrange(t, options, (url) => {
786
+ t.test(route, t => {
787
+ t.plan(3)
788
+ simple.concat({
789
+ method: 'GET',
790
+ url: url + route
791
+ }, (err, response, body) => {
792
+ t.error(err)
793
+ t.equal(response.statusCode, 200)
794
+ t.equal(body.toString(), JSON.stringify(content))
795
+ })
796
+ })
797
+ })
798
+ })
799
+
800
+ t.test('dir list with dotfiles ignore option', t => {
801
+ t.plan(2)
802
+
803
+ const options = {
804
+ root: path.join(__dirname, '/static-dotfiles'),
805
+ prefix: '/public',
806
+ dotfiles: 'ignore',
807
+ index: false,
808
+ list: true
809
+ }
810
+ const route = '/public/'
811
+ const content = { dirs: ['dir'], files: ['test.txt'] }
812
+
813
+ helper.arrange(t, options, (url) => {
814
+ t.test(route, t => {
815
+ t.plan(3)
816
+ simple.concat({
817
+ method: 'GET',
818
+ url: url + route
819
+ }, (err, response, body) => {
820
+ t.error(err)
821
+ t.equal(response.statusCode, 200)
822
+ t.equal(body.toString(), JSON.stringify(content))
823
+ })
824
+ })
825
+ })
826
+ })
827
+
639
828
  t.test('dir list error', t => {
640
829
  t.plan(7)
641
830
 
File without changes
File without changes
File without changes
@@ -1642,7 +1642,7 @@ t.test('with fastify-compress', t => {
1642
1642
  })
1643
1643
  })
1644
1644
  t.test('register /static/ with schemaHide true', t => {
1645
- t.plan(5)
1645
+ t.plan(4)
1646
1646
 
1647
1647
  const pluginOptions = {
1648
1648
  root: path.join(__dirname, '/static'),
@@ -1682,7 +1682,7 @@ t.test('register /static/ with schemaHide true', t => {
1682
1682
  })
1683
1683
 
1684
1684
  t.test('register /static/ with schemaHide false', t => {
1685
- t.plan(5)
1685
+ t.plan(4)
1686
1686
 
1687
1687
  const pluginOptions = {
1688
1688
  root: path.join(__dirname, '/static'),
@@ -1722,7 +1722,7 @@ t.test('register /static/ with schemaHide false', t => {
1722
1722
  })
1723
1723
 
1724
1724
  t.test('register /static/ without schemaHide', t => {
1725
- t.plan(5)
1725
+ t.plan(4)
1726
1726
 
1727
1727
  const pluginOptions = {
1728
1728
  root: path.join(__dirname, '/static'),
@@ -2769,7 +2769,7 @@ t.test('inject support', async (t) => {
2769
2769
  })
2770
2770
 
2771
2771
  t.test('routes should use custom errorHandler premature stream close', t => {
2772
- t.plan(5)
2772
+ t.plan(4)
2773
2773
 
2774
2774
  const pluginOptions = {
2775
2775
  root: path.join(__dirname, '/static'),
@@ -2804,7 +2804,7 @@ t.test('routes should use custom errorHandler premature stream close', t => {
2804
2804
  })
2805
2805
 
2806
2806
  t.test('routes should fallback to default errorHandler', t => {
2807
- t.plan(5)
2807
+ t.plan(4)
2808
2808
 
2809
2809
  const pluginOptions = {
2810
2810
  root: path.join(__dirname, '/static'),
@@ -2840,7 +2840,7 @@ t.test('routes should fallback to default errorHandler', t => {
2840
2840
  })
2841
2841
  })
2842
2842
 
2843
- t.test('precent encoded URLs in glob mode', (t) => {
2843
+ t.test('percent encoded URLs in glob mode', (t) => {
2844
2844
  t.plan(4)
2845
2845
 
2846
2846
  const fastify = Fastify({})
@@ -1,6 +1,34 @@
1
- import fastify from 'fastify'
2
- import { expectError } from 'tsd'
3
- import fastifyStatic, { FastifyStaticOptions } from '../..'
1
+ import fastify, { FastifyInstance, FastifyPluginCallback } from 'fastify'
2
+ import { Server } from 'http';
3
+ import { expectAssignable, expectError, expectType } from 'tsd'
4
+ import * as fastifyStaticStar from '../..';
5
+ import fastifyStatic, {
6
+ FastifyStaticOptions,
7
+ fastifyStatic as fastifyStaticNamed,
8
+ } from '../..'
9
+
10
+ import fastifyStaticCjsImport = require('../..');
11
+ const fastifyStaticCjs = require('../..');
12
+
13
+ const app: FastifyInstance = fastify();
14
+
15
+ app.register(fastifyStatic);
16
+ app.register(fastifyStaticNamed);
17
+ app.register(fastifyStaticCjs);
18
+ app.register(fastifyStaticCjsImport.default);
19
+ app.register(fastifyStaticCjsImport.fastifyStatic);
20
+ app.register(fastifyStaticStar.default);
21
+ app.register(fastifyStaticStar.fastifyStatic);
22
+
23
+ expectType<FastifyPluginCallback<FastifyStaticOptions, Server>>(fastifyStatic);
24
+ expectType<FastifyPluginCallback<FastifyStaticOptions, Server>>(fastifyStaticNamed);
25
+ expectType<FastifyPluginCallback<FastifyStaticOptions, Server>>(fastifyStaticCjsImport.default);
26
+ expectType<FastifyPluginCallback<FastifyStaticOptions, Server>>(fastifyStaticCjsImport.fastifyStatic);
27
+ expectType<FastifyPluginCallback<FastifyStaticOptions, Server>>(fastifyStaticStar.default);
28
+ expectType<FastifyPluginCallback<FastifyStaticOptions, Server>>(
29
+ fastifyStaticStar.fastifyStatic
30
+ );
31
+ expectType<any>(fastifyStaticCjs);
4
32
 
5
33
  const appWithImplicitHttp = fastify()
6
34
  const options: FastifyStaticOptions = {
@@ -32,6 +60,36 @@ expectError<FastifyStaticOptions>({
32
60
  wildcard: '**/**'
33
61
  })
34
62
 
63
+ expectAssignable<FastifyStaticOptions>({
64
+ root: '',
65
+ list: {
66
+ format: 'json',
67
+ }
68
+ })
69
+
70
+ expectAssignable<FastifyStaticOptions>({
71
+ root: '',
72
+ list: {
73
+ format: 'json',
74
+ render: () => ''
75
+ }
76
+ })
77
+
78
+ expectAssignable<FastifyStaticOptions>({
79
+ root: '',
80
+ list: {
81
+ format: 'html',
82
+ render: () => ''
83
+ }
84
+ })
85
+
86
+ expectError<FastifyStaticOptions>({
87
+ root: '',
88
+ list: {
89
+ format: 'html',
90
+ }
91
+ })
92
+
35
93
  appWithImplicitHttp
36
94
  .register(fastifyStatic, options)
37
95
  .after(() => {