@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 +51 -0
- package/.taprc +2 -0
- package/README.md +19 -0
- package/index.js +7 -6
- package/package.json +17 -15
- package/test/static-encode/[...]/a .md +1 -0
- package/test/static.test.js +37 -0
- package/tsconfig.eslint.json +13 -0
- package/types/index.d.ts +6 -6
- package/types/index.test-d.ts +50 -28
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
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(
|
|
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(
|
|
373
|
+
setUpHeadAndGet(routeOpts, pathname, file, rootPath)
|
|
374
374
|
|
|
375
375
|
if (opts.redirect === true) {
|
|
376
|
-
setUpHeadAndGet(
|
|
376
|
+
setUpHeadAndGet(routeOpts, pathname.replace(/\/$/, ''), file.replace(/\/$/, ''), rootPath)
|
|
377
377
|
}
|
|
378
378
|
}
|
|
379
379
|
}
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
-
function setUpHeadAndGet (
|
|
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.
|
|
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
|
-
"
|
|
9
|
-
"lint
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
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": "^
|
|
45
|
-
"@typescript-eslint/parser": "^
|
|
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
|
package/test/static.test.js
CHANGED
|
@@ -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
|
+
)
|
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
|
|
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>;
|
package/types/index.test-d.ts
CHANGED
|
@@ -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'
|
|
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'
|