@fastify/static 6.11.2 → 7.0.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 +28 -48
- package/README.md +3 -3
- package/index.js +14 -18
- package/lib/dirList.js +4 -4
- package/package.json +5 -4
- package/test/static.test.js +3 -3
- package/tsconfig.eslint.json +9 -12
- package/types/index.d.ts +9 -2
- package/types/index.test-d.ts +11 -3
package/.eslintrc.json
CHANGED
|
@@ -1,51 +1,31 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
}
|
|
2
|
+
"plugins": ["@typescript-eslint"],
|
|
3
|
+
"extends": ["eslint:recommended", "standard"],
|
|
4
|
+
"overrides": [
|
|
5
|
+
{
|
|
6
|
+
"files": ["types/*.test-d.ts", "types/*.d.ts"],
|
|
7
|
+
"parser": "@typescript-eslint/parser",
|
|
8
|
+
"parserOptions": {
|
|
9
|
+
"project": ["./tsconfig.eslint.json"]
|
|
31
10
|
},
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
}
|
|
11
|
+
"extends": [
|
|
12
|
+
"plugin:@typescript-eslint/recommended",
|
|
13
|
+
"plugin:@typescript-eslint/recommended-requiring-type-checking"
|
|
14
|
+
],
|
|
15
|
+
"rules": {
|
|
16
|
+
"no-use-before-define": "off",
|
|
17
|
+
"@typescript-eslint/no-var-requires": "off",
|
|
18
|
+
"@typescript-eslint/no-unused-vars": "off",
|
|
19
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
20
|
+
"@typescript-eslint/no-floating-promises": "off",
|
|
21
|
+
"@typescript-eslint/no-unsafe-assignment": "off",
|
|
22
|
+
"@typescript-eslint/no-unsafe-argument": "off",
|
|
23
|
+
"@typescript-eslint/no-unsafe-member-access": "off",
|
|
24
|
+
"@typescript-eslint/no-unsafe-call": "off",
|
|
25
|
+
"@typescript-eslint/no-misused-promises": ["error", {
|
|
26
|
+
"checksVoidReturn": false
|
|
27
|
+
}]
|
|
49
28
|
}
|
|
50
|
-
|
|
51
|
-
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
package/README.md
CHANGED
|
@@ -124,7 +124,7 @@ A URL path prefix used to create a virtual mount path for the static directory.
|
|
|
124
124
|
Default: `{}`
|
|
125
125
|
|
|
126
126
|
Constraints that will be added to registered routes. See Fastify's documentation for
|
|
127
|
-
[route constraints](https://
|
|
127
|
+
[route constraints](https://fastify.dev/docs/latest/Reference/Routes/#constraints).
|
|
128
128
|
|
|
129
129
|
#### `prefixAvoidTrailingSlash`
|
|
130
130
|
|
|
@@ -450,7 +450,7 @@ decorators.
|
|
|
450
450
|
|
|
451
451
|
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
|
-
handler with [`fastify.setNotFoundHandler()`](https://
|
|
453
|
+
handler with [`fastify.setNotFoundHandler()`](https://fastify.dev/docs/latest/Reference/Server/#setnotfoundhandler).
|
|
454
454
|
|
|
455
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
456
|
|
|
@@ -475,7 +475,7 @@ This code will send the `index.html` for the paths `docs`, `docs/`, and `docs/in
|
|
|
475
475
|
|
|
476
476
|
If an error occurs while trying to send a file, the error will be passed
|
|
477
477
|
to Fastify's error handler. You can set a custom error handler with
|
|
478
|
-
[`fastify.setErrorHandler()`](https://
|
|
478
|
+
[`fastify.setErrorHandler()`](https://fastify.dev/docs/latest/Reference/Server/#seterrorhandler).
|
|
479
479
|
|
|
480
480
|
### Payload `stream.filename`
|
|
481
481
|
|
package/index.js
CHANGED
|
@@ -4,9 +4,7 @@ const { PassThrough } = require('node:stream')
|
|
|
4
4
|
const path = require('node:path')
|
|
5
5
|
const { fileURLToPath } = require('node:url')
|
|
6
6
|
const { statSync } = require('node:fs')
|
|
7
|
-
const {
|
|
8
|
-
const glob = require('glob')
|
|
9
|
-
const globPromise = promisify(glob)
|
|
7
|
+
const { glob } = require('glob')
|
|
10
8
|
const fp = require('fastify-plugin')
|
|
11
9
|
const send = require('@fastify/send')
|
|
12
10
|
const encodingNegotiator = require('@fastify/accept-negotiator')
|
|
@@ -14,12 +12,9 @@ const contentDisposition = require('content-disposition')
|
|
|
14
12
|
|
|
15
13
|
const dirList = require('./lib/dirList')
|
|
16
14
|
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const endForwardSlashRegex = /\/$/
|
|
21
|
-
const doubleForwardSlashRegex = /\/\//g
|
|
22
|
-
const asteriskRegex = /\*/g
|
|
15
|
+
const endForwardSlashRegex = /\/$/u
|
|
16
|
+
const doubleForwardSlashRegex = /\/\//gu
|
|
17
|
+
const asteriskRegex = /\*/gu
|
|
23
18
|
|
|
24
19
|
const supportedEncodings = ['br', 'gzip', 'deflate']
|
|
25
20
|
send.mime.default_type = 'application/octet-stream'
|
|
@@ -129,19 +124,20 @@ async function fastifyStatic (fastify, opts) {
|
|
|
129
124
|
})
|
|
130
125
|
}
|
|
131
126
|
} else {
|
|
132
|
-
const
|
|
127
|
+
const indexes = opts.index === undefined ? ['index.html'] : [].concat(opts.index)
|
|
133
128
|
const indexDirs = new Map()
|
|
134
129
|
const routes = new Set()
|
|
130
|
+
const globPattern = '**/**'
|
|
135
131
|
|
|
136
132
|
const roots = Array.isArray(sendOptions.root) ? sendOptions.root : [sendOptions.root]
|
|
137
133
|
for (let i = 0; i < roots.length; ++i) {
|
|
138
134
|
const rootPath = roots[i]
|
|
139
|
-
const
|
|
140
|
-
const
|
|
135
|
+
const posixRootPath = rootPath.split(path.win32.sep).join(path.posix.sep)
|
|
136
|
+
const files = await glob(`${posixRootPath}/${globPattern}`, { follow: true, nodir: true, dot: opts.serveDotFiles })
|
|
141
137
|
|
|
142
138
|
for (let i = 0; i < files.length; ++i) {
|
|
143
|
-
const file = files[i].
|
|
144
|
-
.replace(
|
|
139
|
+
const file = files[i].split(path.win32.sep).join(path.posix.sep)
|
|
140
|
+
.replace(`${posixRootPath}/`, '')
|
|
145
141
|
const route = (prefix + file).replace(doubleForwardSlashRegex, '/')
|
|
146
142
|
|
|
147
143
|
if (routes.has(route)) {
|
|
@@ -150,7 +146,7 @@ async function fastifyStatic (fastify, opts) {
|
|
|
150
146
|
|
|
151
147
|
routes.add(route)
|
|
152
148
|
|
|
153
|
-
setUpHeadAndGet(routeOpts, route,
|
|
149
|
+
setUpHeadAndGet(routeOpts, route, `/${file}`, rootPath)
|
|
154
150
|
|
|
155
151
|
const key = path.posix.basename(route)
|
|
156
152
|
if (indexes.includes(key) && !indexDirs.has(key)) {
|
|
@@ -436,7 +432,7 @@ function checkRootPathForErrors (fastify, rootPath) {
|
|
|
436
432
|
throw new Error('"root" option array requires one or more paths')
|
|
437
433
|
}
|
|
438
434
|
|
|
439
|
-
if (
|
|
435
|
+
if (new Set(rootPath).size !== rootPath.length) {
|
|
440
436
|
throw new Error(
|
|
441
437
|
'"root" option array contains one or more duplicate paths'
|
|
442
438
|
)
|
|
@@ -498,7 +494,7 @@ function findIndexFile (pathname, root, indexFiles = ['index.html']) {
|
|
|
498
494
|
try {
|
|
499
495
|
const stats = statSync(p)
|
|
500
496
|
return !stats.isDirectory()
|
|
501
|
-
} catch
|
|
497
|
+
} catch {
|
|
502
498
|
return false
|
|
503
499
|
}
|
|
504
500
|
})
|
|
@@ -542,7 +538,7 @@ function getRedirectUrl (url) {
|
|
|
542
538
|
const parsed = new URL(url, 'http://localhost.com/')
|
|
543
539
|
const parsedPathname = parsed.pathname
|
|
544
540
|
return parsedPathname + (parsedPathname[parsedPathname.length - 1] !== '/' ? '/' : '') + (parsed.search || '')
|
|
545
|
-
} catch
|
|
541
|
+
} catch {
|
|
546
542
|
// the try-catch here is actually unreachable, but we keep it for safety and prevent DoS attack
|
|
547
543
|
/* istanbul ignore next */
|
|
548
544
|
const err = new Error(`Invalid redirect URL: ${url}`)
|
package/lib/dirList.js
CHANGED
|
@@ -27,7 +27,7 @@ const dirList = {
|
|
|
27
27
|
let stats
|
|
28
28
|
try {
|
|
29
29
|
stats = await fs.stat(path.join(dir, filename))
|
|
30
|
-
} catch
|
|
30
|
+
} catch {
|
|
31
31
|
return
|
|
32
32
|
}
|
|
33
33
|
const entry = { name: filename, stats }
|
|
@@ -58,7 +58,7 @@ const dirList = {
|
|
|
58
58
|
let stats
|
|
59
59
|
try {
|
|
60
60
|
stats = await fs.stat(filePath)
|
|
61
|
-
} catch
|
|
61
|
+
} catch {
|
|
62
62
|
return
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -112,7 +112,7 @@ const dirList = {
|
|
|
112
112
|
let entries
|
|
113
113
|
try {
|
|
114
114
|
entries = await dirList.list(dir, options, dotfiles)
|
|
115
|
-
} catch
|
|
115
|
+
} catch {
|
|
116
116
|
return reply.callNotFound()
|
|
117
117
|
}
|
|
118
118
|
const format = reply.request.query.format || options.format
|
|
@@ -146,7 +146,7 @@ const dirList = {
|
|
|
146
146
|
route = path.normalize(path.join(route, '..'))
|
|
147
147
|
}
|
|
148
148
|
return {
|
|
149
|
-
href: path.join(prefix, route, entry.name).replace(/\\/
|
|
149
|
+
href: path.join(prefix, route, entry.name).replace(/\\/gu, '/'),
|
|
150
150
|
name: entry.name,
|
|
151
151
|
stats: entry.stats,
|
|
152
152
|
extendedInfo: entry.extendedInfo
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fastify/static",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "Plugin for serving static files as fast as possible.",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"type": "commonjs",
|
|
6
7
|
"types": "types/index.d.ts",
|
|
7
8
|
"scripts": {
|
|
8
9
|
"coverage": "npm run test:unit -- --coverage-report=html",
|
|
@@ -17,7 +18,7 @@
|
|
|
17
18
|
},
|
|
18
19
|
"repository": {
|
|
19
20
|
"type": "git",
|
|
20
|
-
"url": "https://github.com/fastify/fastify-static.git"
|
|
21
|
+
"url": "git+https://github.com/fastify/fastify-static.git"
|
|
21
22
|
},
|
|
22
23
|
"keywords": [
|
|
23
24
|
"fastify",
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
"@fastify/send": "^2.0.0",
|
|
35
36
|
"content-disposition": "^0.5.3",
|
|
36
37
|
"fastify-plugin": "^4.0.0",
|
|
37
|
-
"glob": "^
|
|
38
|
+
"glob": "^10.3.4",
|
|
38
39
|
"p-limit": "^3.1.0"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
|
@@ -54,7 +55,7 @@
|
|
|
54
55
|
"snazzy": "^9.0.0",
|
|
55
56
|
"standard": "^17.0.0",
|
|
56
57
|
"tap": "^16.0.0",
|
|
57
|
-
"tsd": "^0.
|
|
58
|
+
"tsd": "^0.30.0",
|
|
58
59
|
"typescript": "^5.1.6"
|
|
59
60
|
},
|
|
60
61
|
"tsd": {
|
package/test/static.test.js
CHANGED
|
@@ -1000,7 +1000,7 @@ t.test('sendFile disabled', (t) => {
|
|
|
1000
1000
|
fastify.register(fastifyStatic, pluginOptions)
|
|
1001
1001
|
|
|
1002
1002
|
fastify.get('/foo/bar', function (req, reply) {
|
|
1003
|
-
if (
|
|
1003
|
+
if (reply.sendFile === undefined) {
|
|
1004
1004
|
reply.send('pass')
|
|
1005
1005
|
} else {
|
|
1006
1006
|
reply.send('fail')
|
|
@@ -1277,7 +1277,7 @@ t.test('sendFile disabled', (t) => {
|
|
|
1277
1277
|
fastify.register(fastifyStatic, pluginOptions)
|
|
1278
1278
|
|
|
1279
1279
|
fastify.get('/foo/bar', function (req, reply) {
|
|
1280
|
-
if (
|
|
1280
|
+
if (reply.sendFile === undefined) {
|
|
1281
1281
|
reply.send('pass')
|
|
1282
1282
|
} else {
|
|
1283
1283
|
reply.send('fail')
|
|
@@ -1316,7 +1316,7 @@ t.test('download disabled', (t) => {
|
|
|
1316
1316
|
fastify.register(fastifyStatic, pluginOptions)
|
|
1317
1317
|
|
|
1318
1318
|
fastify.get('/foo/bar', function (req, reply) {
|
|
1319
|
-
if (
|
|
1319
|
+
if (reply.download === undefined) {
|
|
1320
1320
|
t.equal(reply.download, undefined)
|
|
1321
1321
|
reply.send('pass')
|
|
1322
1322
|
} else {
|
package/tsconfig.eslint.json
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"types/*.d.ts"
|
|
12
|
-
]
|
|
13
|
-
}
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es6",
|
|
4
|
+
"lib": ["ES2018"],
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"noEmit": true,
|
|
7
|
+
"strict": true
|
|
8
|
+
},
|
|
9
|
+
"include": ["types/*.test-d.ts", "types/*.d.ts"]
|
|
10
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Leo <https://github.com/leomelzer>
|
|
3
3
|
/// <reference types="node" />
|
|
4
4
|
|
|
5
|
-
import { FastifyPluginAsync, FastifyRequest, RouteOptions } from 'fastify'
|
|
5
|
+
import { FastifyPluginAsync, FastifyReply, FastifyRequest, RouteOptions } from 'fastify'
|
|
6
6
|
import { Stats } from 'fs'
|
|
7
7
|
|
|
8
8
|
declare module 'fastify' {
|
|
@@ -19,6 +19,13 @@ declare module 'fastify' {
|
|
|
19
19
|
type FastifyStaticPlugin = FastifyPluginAsync<NonNullable<fastifyStatic.FastifyStaticOptions>>;
|
|
20
20
|
|
|
21
21
|
declare namespace fastifyStatic {
|
|
22
|
+
export interface SetHeadersResponse {
|
|
23
|
+
getHeader: FastifyReply['getHeader'];
|
|
24
|
+
setHeader: FastifyReply['header'];
|
|
25
|
+
readonly filename: string;
|
|
26
|
+
statusCode: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
22
29
|
export interface ExtendedInformation {
|
|
23
30
|
fileCount: number;
|
|
24
31
|
totalFileCount: number;
|
|
@@ -83,7 +90,7 @@ declare namespace fastifyStatic {
|
|
|
83
90
|
serve?: boolean;
|
|
84
91
|
decorateReply?: boolean;
|
|
85
92
|
schemaHide?: boolean;
|
|
86
|
-
setHeaders?: (
|
|
93
|
+
setHeaders?: (res: SetHeadersResponse, path: string, stat: Stats) => void;
|
|
87
94
|
redirect?: boolean;
|
|
88
95
|
wildcard?: boolean;
|
|
89
96
|
list?: boolean | ListOptionsJsonFormat | ListOptionsHtmlFormat;
|
package/types/index.test-d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import fastify, { FastifyInstance, FastifyPluginAsync, FastifyRequest } from 'fastify'
|
|
1
|
+
import fastify, { FastifyInstance, FastifyPluginAsync, FastifyRequest, FastifyReply } from 'fastify'
|
|
2
2
|
import { Server } from 'http'
|
|
3
|
+
import { Stats } from 'fs'
|
|
3
4
|
import { expectAssignable, expectError, expectType } from 'tsd'
|
|
4
5
|
import * as fastifyStaticStar from '..'
|
|
5
6
|
import fastifyStatic, {
|
|
@@ -49,8 +50,15 @@ const options: FastifyStaticOptions = {
|
|
|
49
50
|
serve: true,
|
|
50
51
|
wildcard: true,
|
|
51
52
|
list: false,
|
|
52
|
-
setHeaders: (res
|
|
53
|
-
res.
|
|
53
|
+
setHeaders: (res, path, stat) => {
|
|
54
|
+
expectType<string>(res.filename)
|
|
55
|
+
expectType<number>(res.statusCode)
|
|
56
|
+
expectType<ReturnType<FastifyReply['getHeader']>>(res.getHeader('X-Test'))
|
|
57
|
+
res.setHeader('X-Test', 'string')
|
|
58
|
+
|
|
59
|
+
expectType<string>(path)
|
|
60
|
+
|
|
61
|
+
expectType<Stats>(stat)
|
|
54
62
|
},
|
|
55
63
|
preCompressed: false,
|
|
56
64
|
allowedPath: (pathName: string, root: string, request: FastifyRequest) => {
|