@fastify/static 6.10.2 → 6.11.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/.eslintrc.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "extends": [
3
+ "eslint:recommended",
4
+ "plugin:@typescript-eslint/eslint-recommended",
5
+ "plugin:@typescript-eslint/recommended",
6
+ "standard"
7
+ ],
8
+ "parser": "@typescript-eslint/parser",
9
+ "plugins": ["@typescript-eslint"],
10
+ "env": { "node": true },
11
+ "parserOptions": {
12
+ "ecmaVersion": 6,
13
+ "sourceType": "module",
14
+ "project": "./tsconfig.eslint.json",
15
+ "createDefaultProgram": true
16
+ },
17
+ "rules": {
18
+ "no-console": "off",
19
+ "@typescript-eslint/indent": ["error", 2],
20
+ "semi": ["error", "never"],
21
+ "import/export": "off" // this errors on multiple exports (overload interfaces)
22
+ },
23
+ "overrides": [
24
+ {
25
+ "files": ["*.d.ts","*.test-d.ts"],
26
+ "rules": {
27
+ "no-use-before-define": "off",
28
+ "no-redeclare": "off",
29
+ "@typescript-eslint/no-explicit-any": "off"
30
+ }
31
+ },
32
+ {
33
+ "files": ["*.test-d.ts"],
34
+ "rules": {
35
+ "@typescript-eslint/no-var-requires": "off",
36
+ "no-unused-vars": "off",
37
+ "n/handle-callback-err": "off",
38
+ "@typescript-eslint/no-empty-function": "off",
39
+ "@typescript-eslint/explicit-function-return-type": "off",
40
+ "@typescript-eslint/no-unused-vars": "off",
41
+ "@typescript-eslint/no-non-null-assertion": "off",
42
+ "@typescript-eslint/no-misused-promises": ["error", {
43
+ "checksVoidReturn": false
44
+ }]
45
+ },
46
+ "globals": {
47
+ "NodeJS": "readonly"
48
+ }
49
+ }
50
+ ]
51
+ }
package/.taprc ADDED
@@ -0,0 +1,2 @@
1
+ files:
2
+ - test/**/*.test.js
package/README.md CHANGED
@@ -452,6 +452,25 @@ If a request matches the URL `prefix` but a file cannot be found for the
452
452
  request, Fastify's 404 handler will be called. You can set a custom 404
453
453
  handler with [`fastify.setNotFoundHandler()`](https://www.fastify.io/docs/latest/Reference/Server/#setnotfoundhandler).
454
454
 
455
+ When registering `@fastify/static` within an encapsulated context, the `wildcard` option may need to be set to `false` in order to support index resolution and nested not-found-handler:
456
+
457
+ ```js
458
+ const app = require('fastify')();
459
+
460
+ app.register((childContext, _, done) => {
461
+ childContext.register(require('@fastify/static'), {
462
+ root: path.join(__dirname, 'docs'), // docs is a folder that contains `index.html` and `404.html`
463
+ wildcard: false
464
+ });
465
+ childContext.setNotFoundHandler((_, reply) => {
466
+ return reply.code(404).type('text/html').sendFile('404.html');
467
+ });
468
+ done();
469
+ }, { prefix: 'docs' });
470
+ ```
471
+
472
+ This code will send the `index.html` for the paths `docs`, `docs/`, and `docs/index.html`. For all other `docs/<undefined-routes>` it will reply with `404.html`.
473
+
455
474
  ### Handling Errors
456
475
 
457
476
  If an error occurs while trying to send a file, the error will be passed
package/index.js CHANGED
@@ -358,7 +358,7 @@ async function fastifyStatic (fastify, opts) {
358
358
  }
359
359
  routes.add(route)
360
360
 
361
- setUpHeadAndGet(fastify, routeOpts, route, '/' + file, rootPath)
361
+ setUpHeadAndGet(routeOpts, route, '/' + file, rootPath)
362
362
 
363
363
  const key = path.posix.basename(route)
364
364
  if (indexes.includes(key) && !indexDirs.has(key)) {
@@ -370,16 +370,16 @@ async function fastifyStatic (fastify, opts) {
370
370
  for (const [dirname, rootPath] of indexDirs.entries()) {
371
371
  const pathname = dirname + (dirname.endsWith('/') ? '' : '/')
372
372
  const file = '/' + pathname.replace(prefix, '')
373
- setUpHeadAndGet(fastify, routeOpts, pathname, file, rootPath)
373
+ setUpHeadAndGet(routeOpts, pathname, file, rootPath)
374
374
 
375
375
  if (opts.redirect === true) {
376
- setUpHeadAndGet(fastify, routeOpts, pathname.replace(/\/$/, ''), file.replace(/\/$/, ''), rootPath)
376
+ setUpHeadAndGet(routeOpts, pathname.replace(/\/$/, ''), file.replace(/\/$/, ''), rootPath)
377
377
  }
378
378
  }
379
379
  }
380
380
  }
381
381
 
382
- function setUpHeadAndGet (fastify, routeOpts, route, file, rootPath) {
382
+ function setUpHeadAndGet (routeOpts, route, file, rootPath) {
383
383
  const toSetUp = {
384
384
  ...routeOpts,
385
385
  method: ['HEAD', 'GET'],
@@ -398,6 +398,7 @@ async function fastifyStatic (fastify, opts) {
398
398
  pumpSendToReply(req, reply, file, rootPath)
399
399
  }
400
400
  }
401
+
401
402
  function normalizeRoot (root) {
402
403
  if (root === undefined) {
403
404
  return root
@@ -475,8 +476,6 @@ function checkPath (fastify, rootPath) {
475
476
  }
476
477
  }
477
478
 
478
- const supportedEncodings = ['br', 'gzip', 'deflate']
479
-
480
479
  function getContentType (path) {
481
480
  const type = send.mime.getType(path) || send.mime.default_type
482
481
 
@@ -504,6 +503,8 @@ function findIndexFile (pathname, root, indexFiles = ['index.html']) {
504
503
  return false
505
504
  }
506
505
 
506
+ const supportedEncodings = ['br', 'gzip', 'deflate']
507
+
507
508
  // Adapted from https://github.com/fastify/fastify-compress/blob/665e132fa63d3bf05ad37df3c20346660b71a857/index.js#L451
508
509
  function getEncodingHeader (headers, checked) {
509
510
  if (!('accept-encoding' in headers)) return
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "name": "@fastify/static",
3
- "version": "6.10.2",
3
+ "version": "6.11.0",
4
4
  "description": "Plugin for serving static files as fast as possible.",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
7
7
  "scripts": {
8
- "lint": "standard | snazzy",
9
- "lint:fix": "standard --fix",
10
- "unit": "tap test/*.test.js",
11
- "typescript": "tsd",
12
- "test": "npm run lint && npm run unit && npm run typescript",
13
- "example": "node example/server.js",
14
- "coverage": "tap --cov --coverage-report=html test",
15
- "coveralls": "tap test/*test.js test/*/*.test.js --cov"
8
+ "coverage": "npm run test:unit -- --coverage-report=html",
9
+ "lint": "npm run lint:javascript && npm run lint:typescript",
10
+ "lint:javascript": "standard | snazzy",
11
+ "lint:fix": "standard --fix && npm run lint:typescript -- --fix",
12
+ "lint:typescript": "eslint -c .eslintrc.json types/**/*.d.ts types/**/*.test-d.ts",
13
+ "test": "npm run test:unit && npm run test:typescript",
14
+ "test:typescript": "tsd",
15
+ "test:unit": "tap",
16
+ "example": "node example/server.js"
16
17
  },
17
18
  "repository": {
18
19
  "type": "git",
@@ -29,20 +30,20 @@
29
30
  },
30
31
  "homepage": "https://github.com/fastify/fastify-static",
31
32
  "dependencies": {
32
- "content-disposition": "^0.5.3",
33
33
  "@fastify/accept-negotiator": "^1.0.0",
34
+ "@fastify/send": "^2.0.0",
35
+ "content-disposition": "^0.5.3",
34
36
  "fastify-plugin": "^4.0.0",
35
37
  "glob": "^8.0.1",
36
38
  "p-limit": "^3.1.0",
37
- "readable-stream": "^4.0.0",
38
- "@fastify/send": "^2.0.0"
39
+ "readable-stream": "^4.0.0"
39
40
  },
40
41
  "devDependencies": {
41
42
  "@fastify/compress": "^6.0.0",
42
43
  "@fastify/pre-commit": "^2.0.2",
43
44
  "@types/node": "^20.1.0",
44
- "@typescript-eslint/eslint-plugin": "^2.29.0",
45
- "@typescript-eslint/parser": "^2.29.0",
45
+ "@typescript-eslint/eslint-plugin": "^6.3.0",
46
+ "@typescript-eslint/parser": "^6.3.0",
46
47
  "concat-stream": "^2.0.0",
47
48
  "coveralls": "^3.0.4",
48
49
  "eslint-plugin-typescript": "^0.14.0",
@@ -54,7 +55,8 @@
54
55
  "snazzy": "^9.0.0",
55
56
  "standard": "^17.0.0",
56
57
  "tap": "^16.0.0",
57
- "tsd": "^0.28.0"
58
+ "tsd": "^0.28.0",
59
+ "typescript": "^5.1.6"
58
60
  },
59
61
  "tsd": {
60
62
  "directory": "test/types"
@@ -0,0 +1 @@
1
+ example
@@ -3756,6 +3756,7 @@ t.test(
3756
3756
  t.end()
3757
3757
  }
3758
3758
  )
3759
+
3759
3760
  t.test(
3760
3761
  'converts URL to path',
3761
3762
  async (t) => {
@@ -3803,3 +3804,39 @@ t.test(
3803
3804
  t.same(response.body, foobarContent)
3804
3805
  }
3805
3806
  )
3807
+
3808
+ t.test(
3809
+ 'serves files with paths that have characters modified by encodeUri when wildcard is false',
3810
+ async (t) => {
3811
+ const aContent = fs.readFileSync(path.join(__dirname, 'static-encode/[...]', 'a .md'), 'utf-8')
3812
+
3813
+ t.plan(4)
3814
+ const pluginOptions = {
3815
+ root: url.pathToFileURL(path.join(__dirname, '/static-encode')),
3816
+ wildcard: false
3817
+ }
3818
+
3819
+ const fastify = Fastify()
3820
+
3821
+ fastify.register(fastifyStatic, pluginOptions)
3822
+ const response = await fastify.inject({
3823
+ method: 'GET',
3824
+ url: '[...]/a .md',
3825
+ headers: {
3826
+ 'accept-encoding': '*, *'
3827
+ }
3828
+ })
3829
+ t.equal(response.statusCode, 200)
3830
+ t.same(response.body, aContent)
3831
+
3832
+ const response2 = await fastify.inject({
3833
+ method: 'GET',
3834
+ url: '%5B...%5D/a%20.md',
3835
+ headers: {
3836
+ 'accept-encoding': '*, *'
3837
+ }
3838
+ })
3839
+ t.equal(response2.statusCode, 200)
3840
+ t.same(response2.body, aContent)
3841
+ }
3842
+ )
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es6",
4
+ "lib": [ "es2015" ],
5
+ "module": "commonjs",
6
+ "noEmit": true,
7
+ "strict": true
8
+ },
9
+ "include": [
10
+ "types/*.test-d.ts",
11
+ "types/*.d.ts"
12
+ ]
13
+ }
package/types/index.d.ts CHANGED
@@ -2,10 +2,10 @@
2
2
  // Leo <https://github.com/leomelzer>
3
3
  /// <reference types="node" />
4
4
 
5
- import {FastifyPluginAsync, FastifyRequest, RouteOptions} from 'fastify';
6
- import { Stats } from 'fs';
5
+ import { FastifyPluginAsync, FastifyRequest, RouteOptions } from 'fastify'
6
+ import { Stats } from 'fs'
7
7
 
8
- declare module "fastify" {
8
+ declare module 'fastify' {
9
9
  interface FastifyReply {
10
10
  sendFile(filename: string, rootPath?: string): FastifyReply;
11
11
  sendFile(filename: string, options?: fastifyStatic.SendOptions): FastifyReply;
@@ -77,7 +77,7 @@ declare namespace fastifyStatic {
77
77
  }
78
78
 
79
79
  export interface FastifyStaticOptions extends SendOptions {
80
- root: string | string[];
80
+ root: string | string[] | URL | URL[];
81
81
  prefix?: string;
82
82
  prefixAvoidTrailingSlash?: boolean;
83
83
  serve?: boolean;
@@ -107,9 +107,9 @@ declare namespace fastifyStatic {
107
107
  constraints?: RouteOptions['constraints'];
108
108
  }
109
109
 
110
- export const fastifyStatic: FastifyStaticPlugin;
110
+ export const fastifyStatic: FastifyStaticPlugin
111
111
 
112
- export { fastifyStatic as default };
112
+ export { fastifyStatic as default }
113
113
  }
114
114
 
115
115
  declare function fastifyStatic(...params: Parameters<FastifyStaticPlugin>): ReturnType<FastifyStaticPlugin>;
@@ -1,34 +1,34 @@
1
1
  import fastify, { FastifyInstance, FastifyPluginAsync, FastifyRequest } from 'fastify'
2
- import { Server } from 'http';
2
+ import { Server } from 'http'
3
3
  import { expectAssignable, expectError, expectType } from 'tsd'
4
- import * as fastifyStaticStar from '..';
4
+ import * as fastifyStaticStar from '..'
5
5
  import fastifyStatic, {
6
6
  FastifyStaticOptions,
7
- fastifyStatic as fastifyStaticNamed,
7
+ fastifyStatic as fastifyStaticNamed
8
8
  } from '..'
9
9
 
10
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<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStatic);
24
- expectType<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStaticNamed);
25
- expectType<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStaticCjsImport.default);
26
- expectType<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStaticCjsImport.fastifyStatic);
27
- expectType<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStaticStar.default);
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<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStatic)
24
+ expectType<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStaticNamed)
25
+ expectType<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStaticCjsImport.default)
26
+ expectType<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStaticCjsImport.fastifyStatic)
27
+ expectType<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStaticStar.default)
28
28
  expectType<FastifyPluginAsync<FastifyStaticOptions, Server>>(
29
- fastifyStaticStar.fastifyStatic
30
- );
31
- expectType<any>(fastifyStaticCjs);
29
+ fastifyStaticStar.fastifyStatic
30
+ )
31
+ expectType<any>(fastifyStaticCjs)
32
32
 
33
33
  const appWithImplicitHttp = fastify()
34
34
  const options: FastifyStaticOptions = {
@@ -54,7 +54,7 @@ const options: FastifyStaticOptions = {
54
54
  },
55
55
  preCompressed: false,
56
56
  allowedPath: (pathName: string, root: string, request: FastifyRequest) => {
57
- return true;
57
+ return true
58
58
  },
59
59
  constraints: {
60
60
  host: /.*\.example\.com/,
@@ -70,7 +70,7 @@ expectError<FastifyStaticOptions>({
70
70
  expectAssignable<FastifyStaticOptions>({
71
71
  root: '',
72
72
  list: {
73
- format: 'json',
73
+ format: 'json'
74
74
  }
75
75
  })
76
76
 
@@ -93,10 +93,22 @@ expectAssignable<FastifyStaticOptions>({
93
93
  expectError<FastifyStaticOptions>({
94
94
  root: '',
95
95
  list: {
96
- format: 'html',
96
+ format: 'html'
97
97
  }
98
98
  })
99
99
 
100
+ expectAssignable<FastifyStaticOptions>({
101
+ root: ['']
102
+ })
103
+
104
+ expectAssignable<FastifyStaticOptions>({
105
+ root: new URL('')
106
+ })
107
+
108
+ expectAssignable<FastifyStaticOptions>({
109
+ root: [new URL('')]
110
+ })
111
+
100
112
  appWithImplicitHttp
101
113
  .register(fastifyStatic, options)
102
114
  .after(() => {
@@ -123,7 +135,7 @@ appWithHttp2
123
135
  })
124
136
 
125
137
  appWithHttp2.get('/download/2', (request, reply) => {
126
- reply.download('some-file-name', 'some-filename' ,{ cacheControl: false, acceptRanges: true })
138
+ reply.download('some-file-name', 'some-filename', { cacheControl: false, acceptRanges: true })
127
139
  })
128
140
  })
129
141
 
@@ -168,7 +180,17 @@ noIndexApp
168
180
  noIndexApp.get('/', (request, reply) => {
169
181
  reply.send('<h1>fastify-static</h1>')
170
182
  })
171
- })
183
+ })
184
+
185
+ options.root = new URL('')
186
+
187
+ const URLRootApp = fastify()
188
+ URLRootApp.register(fastifyStatic, options)
189
+ .after(() => {
190
+ URLRootApp.get('/', (request, reply) => {
191
+ reply.send('<h1>fastify-static</h1>')
192
+ })
193
+ })
172
194
 
173
195
  const defaultIndexApp = fastify()
174
196
  options.index = 'index.html'