@fastify/static 8.0.2 → 8.0.3
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/.github/workflows/ci.yml +1 -1
- package/README.md +15 -14
- package/index.js +2 -1
- package/package.json +3 -3
- package/test/content-type.test.js +6 -6
- package/test/static/shallow/no-link +1 -0
- package/test/static-symbolic-link/dir/symlink +1 -0
- package/test/static.test.js +44 -3
- package/types/index.d.ts +2 -0
- package/types/index.test-d.ts +20 -7
package/.github/workflows/ci.yml
CHANGED
package/README.md
CHANGED
|
@@ -153,17 +153,18 @@ where the arguments are:
|
|
|
153
153
|
#### `send` Options
|
|
154
154
|
|
|
155
155
|
The following options are also supported and will be passed directly to the
|
|
156
|
-
[
|
|
157
|
-
|
|
158
|
-
- [`acceptRanges`](https://www.npmjs.com/package/send#acceptranges)
|
|
159
|
-
- [`
|
|
160
|
-
- [`
|
|
161
|
-
- [`
|
|
162
|
-
- [`
|
|
163
|
-
- [`
|
|
164
|
-
- [`
|
|
165
|
-
- [`
|
|
166
|
-
- [`
|
|
156
|
+
[`@fastify/send`](https://www.npmjs.com/package/@fastify/send) module:
|
|
157
|
+
|
|
158
|
+
- [`acceptRanges`](https://www.npmjs.com/package/@fastify/send#acceptranges)
|
|
159
|
+
- [`contentType`](https://www.npmjs.com/package/@fastify/send#contenttype)
|
|
160
|
+
- [`cacheControl`](https://www.npmjs.com/package/@fastify/send#cachecontrol) (Enable or disable setting Cache-Control response header, defaults to true. **Important:** If you want to provide a custom Cache-Control response header, this option must be false.)
|
|
161
|
+
- [`dotfiles`](https://www.npmjs.com/package/@fastify/send#dotfiles)
|
|
162
|
+
- [`etag`](https://www.npmjs.com/package/@fastify/send#etag)
|
|
163
|
+
- [`extensions`](https://www.npmjs.com/package/@fastify/send#extensions)
|
|
164
|
+
- [`immutable`](https://www.npmjs.com/package/@fastify/send#immutable)
|
|
165
|
+
- [`index`](https://www.npmjs.com/package/@fastify/send#index)
|
|
166
|
+
- [`lastModified`](https://www.npmjs.com/package/@fastify/send#lastmodified)
|
|
167
|
+
- [`maxAge`](https://www.npmjs.com/package/@fastify/send#maxage)
|
|
167
168
|
|
|
168
169
|
You're able to alter this options when calling `reply.download('filename.html', options)` or `reply.download('filename.html', 'otherfilename.html', options)` on each response to a request.
|
|
169
170
|
|
|
@@ -198,7 +199,7 @@ with `ignoreTrailingSlash` set to `true`.
|
|
|
198
199
|
|
|
199
200
|
Default: `(pathName, root, request) => true`
|
|
200
201
|
|
|
201
|
-
This function allows filtering the served files. Also, with the help of the request object a more complex path authentication is possible.
|
|
202
|
+
This function allows filtering the served files. Also, with the help of the request object a more complex path authentication is possible.
|
|
202
203
|
If the function returns `true`, the file will be served.
|
|
203
204
|
If the function returns `false`, Fastify's 404 handler will be called.
|
|
204
205
|
|
|
@@ -206,7 +207,7 @@ If the function returns `false`, Fastify's 404 handler will be called.
|
|
|
206
207
|
|
|
207
208
|
Default: `undefined`
|
|
208
209
|
|
|
209
|
-
Under the hood we use [send](https://github.com/pillarjs/send#index) lib that by default supports "index.html" files.
|
|
210
|
+
Under the hood we use [send](https://github.com/pillarjs/send#index) lib that by default supports "index.html" files.
|
|
210
211
|
To disable this set false or to supply a new index pass a string or an array in preferred order.
|
|
211
212
|
|
|
212
213
|
#### `serveDotFiles`
|
|
@@ -469,7 +470,7 @@ app.register((childContext, _, done) => {
|
|
|
469
470
|
}, { prefix: 'docs' });
|
|
470
471
|
```
|
|
471
472
|
|
|
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
|
+
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
474
|
|
|
474
475
|
### Handling Errors
|
|
475
476
|
|
package/index.js
CHANGED
|
@@ -38,6 +38,7 @@ async function fastifyStatic (fastify, opts) {
|
|
|
38
38
|
const sendOptions = {
|
|
39
39
|
root: opts.root,
|
|
40
40
|
acceptRanges: opts.acceptRanges,
|
|
41
|
+
contentType: opts.contentType,
|
|
41
42
|
cacheControl: opts.cacheControl,
|
|
42
43
|
dotfiles: opts.dotfiles,
|
|
43
44
|
etag: opts.etag,
|
|
@@ -472,7 +473,7 @@ function getContentType (path) {
|
|
|
472
473
|
if (!send.isUtf8MimeType(type)) {
|
|
473
474
|
return type
|
|
474
475
|
}
|
|
475
|
-
return `${type}; charset=
|
|
476
|
+
return `${type}; charset=utf-8`
|
|
476
477
|
}
|
|
477
478
|
|
|
478
479
|
function findIndexFile (pathname, root, indexFiles = ['index.html']) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fastify/static",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.3",
|
|
4
4
|
"description": "Plugin for serving static files as fast as possible.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"homepage": "https://github.com/fastify/fastify-static",
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@fastify/accept-negotiator": "^2.0.0",
|
|
33
|
-
"@fastify/send": "^3.
|
|
33
|
+
"@fastify/send": "^3.2.0",
|
|
34
34
|
"content-disposition": "^0.5.4",
|
|
35
35
|
"fastify-plugin": "^5.0.0",
|
|
36
36
|
"fastq": "^1.17.1",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"@types/node": "^22.0.0",
|
|
43
43
|
"concat-stream": "^2.0.0",
|
|
44
44
|
"eslint": "^9.9.0",
|
|
45
|
-
"fastify": "^5.
|
|
45
|
+
"fastify": "^5.1.0",
|
|
46
46
|
"neostandard": "^0.11.3",
|
|
47
47
|
"pino": "^9.1.0",
|
|
48
48
|
"proxyquire": "^2.1.3",
|
|
@@ -33,7 +33,7 @@ test('register /content-type', t => {
|
|
|
33
33
|
url: 'http://localhost:' + fastify.server.address().port + '/content-type/index.html'
|
|
34
34
|
}, (err, response) => {
|
|
35
35
|
t.error(err)
|
|
36
|
-
t.equal(response.headers['content-type'], 'text/html; charset=
|
|
36
|
+
t.equal(response.headers['content-type'], 'text/html; charset=utf-8')
|
|
37
37
|
})
|
|
38
38
|
})
|
|
39
39
|
|
|
@@ -44,7 +44,7 @@ test('register /content-type', t => {
|
|
|
44
44
|
url: 'http://localhost:' + fastify.server.address().port + '/content-type/index.css'
|
|
45
45
|
}, (err, response) => {
|
|
46
46
|
t.error(err)
|
|
47
|
-
t.equal(response.headers['content-type'], 'text/css; charset=
|
|
47
|
+
t.equal(response.headers['content-type'], 'text/css; charset=utf-8')
|
|
48
48
|
})
|
|
49
49
|
})
|
|
50
50
|
|
|
@@ -66,7 +66,7 @@ test('register /content-type', t => {
|
|
|
66
66
|
url: 'http://localhost:' + fastify.server.address().port + '/content-type/test.txt'
|
|
67
67
|
}, (err, response) => {
|
|
68
68
|
t.error(err)
|
|
69
|
-
t.equal(response.headers['content-type'], 'text/plain; charset=
|
|
69
|
+
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
|
|
70
70
|
})
|
|
71
71
|
})
|
|
72
72
|
|
|
@@ -111,7 +111,7 @@ test('register /content-type preCompressed', t => {
|
|
|
111
111
|
}
|
|
112
112
|
}, (err, response) => {
|
|
113
113
|
t.error(err)
|
|
114
|
-
t.equal(response.headers['content-type'], 'text/html; charset=
|
|
114
|
+
t.equal(response.headers['content-type'], 'text/html; charset=utf-8')
|
|
115
115
|
})
|
|
116
116
|
})
|
|
117
117
|
|
|
@@ -125,7 +125,7 @@ test('register /content-type preCompressed', t => {
|
|
|
125
125
|
}
|
|
126
126
|
}, (err, response) => {
|
|
127
127
|
t.error(err)
|
|
128
|
-
t.equal(response.headers['content-type'], 'text/css; charset=
|
|
128
|
+
t.equal(response.headers['content-type'], 'text/css; charset=utf-8')
|
|
129
129
|
})
|
|
130
130
|
})
|
|
131
131
|
|
|
@@ -153,7 +153,7 @@ test('register /content-type preCompressed', t => {
|
|
|
153
153
|
}
|
|
154
154
|
}, (err, response) => {
|
|
155
155
|
t.error(err)
|
|
156
|
-
t.equal(response.headers['content-type'], 'text/plain; charset=
|
|
156
|
+
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
|
|
157
157
|
})
|
|
158
158
|
})
|
|
159
159
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/none
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
../origin
|
package/test/static.test.js
CHANGED
|
@@ -1377,10 +1377,11 @@ t.test('root not found warning', (t) => {
|
|
|
1377
1377
|
})
|
|
1378
1378
|
|
|
1379
1379
|
t.test('send options', (t) => {
|
|
1380
|
-
t.plan(
|
|
1380
|
+
t.plan(12)
|
|
1381
1381
|
const pluginOptions = {
|
|
1382
1382
|
root: path.join(__dirname, '/static'),
|
|
1383
1383
|
acceptRanges: 'acceptRanges',
|
|
1384
|
+
contentType: 'contentType',
|
|
1384
1385
|
cacheControl: 'cacheControl',
|
|
1385
1386
|
dotfiles: 'dotfiles',
|
|
1386
1387
|
etag: 'etag',
|
|
@@ -1396,6 +1397,7 @@ t.test('send options', (t) => {
|
|
|
1396
1397
|
t.equal(pathName, '/index.html')
|
|
1397
1398
|
t.equal(options.root, path.join(__dirname, '/static'))
|
|
1398
1399
|
t.equal(options.acceptRanges, 'acceptRanges')
|
|
1400
|
+
t.equal(options.contentType, 'contentType')
|
|
1399
1401
|
t.equal(options.cacheControl, 'cacheControl')
|
|
1400
1402
|
t.equal(options.dotfiles, 'dotfiles')
|
|
1401
1403
|
t.equal(options.etag, 'etag')
|
|
@@ -4017,7 +4019,7 @@ t.test('content-length in head route should not return zero when using wildcard'
|
|
|
4017
4019
|
}, (err, response, body) => {
|
|
4018
4020
|
t.error(err)
|
|
4019
4021
|
t.equal(response.statusCode, 200)
|
|
4020
|
-
t.equal(response.headers['content-type'], 'text/html; charset=
|
|
4022
|
+
t.equal(response.headers['content-type'], 'text/html; charset=utf-8')
|
|
4021
4023
|
t.equal(response.headers['content-length'], contentLength)
|
|
4022
4024
|
t.equal(body.toString(), '')
|
|
4023
4025
|
})
|
|
@@ -4055,9 +4057,48 @@ t.test('respect the .code when using with sendFile', t => {
|
|
|
4055
4057
|
}, (err, response, body) => {
|
|
4056
4058
|
t.error(err)
|
|
4057
4059
|
t.equal(response.statusCode, 404)
|
|
4058
|
-
t.equal(response.headers['content-type'], 'text/html; charset=
|
|
4060
|
+
t.equal(response.headers['content-type'], 'text/html; charset=utf-8')
|
|
4059
4061
|
t.equal(response.headers['content-length'], contentLength)
|
|
4060
4062
|
t.equal(body.toString(), '')
|
|
4061
4063
|
})
|
|
4062
4064
|
})
|
|
4063
4065
|
})
|
|
4066
|
+
|
|
4067
|
+
t.test('respect the .type when using with sendFile with contentType disabled', t => {
|
|
4068
|
+
t.plan(6)
|
|
4069
|
+
|
|
4070
|
+
const pluginOptions = {
|
|
4071
|
+
root: path.join(__dirname, '/static'),
|
|
4072
|
+
contentType: false
|
|
4073
|
+
}
|
|
4074
|
+
const fastify = Fastify()
|
|
4075
|
+
|
|
4076
|
+
fastify.register(fastifyStatic, pluginOptions)
|
|
4077
|
+
|
|
4078
|
+
fastify.get('/custom', (_, reply) => {
|
|
4079
|
+
return reply.type('text/html; charset=windows-1252').sendFile('foo.html')
|
|
4080
|
+
})
|
|
4081
|
+
|
|
4082
|
+
t.teardown(fastify.close.bind(fastify))
|
|
4083
|
+
|
|
4084
|
+
fastify.listen({ port: 0 }, err => {
|
|
4085
|
+
t.error(err)
|
|
4086
|
+
|
|
4087
|
+
fastify.server.unref()
|
|
4088
|
+
|
|
4089
|
+
const file = fs.readFileSync(path.join(__dirname, '/static/foo.html'))
|
|
4090
|
+
const contentLength = Buffer.byteLength(file).toString()
|
|
4091
|
+
|
|
4092
|
+
simple.concat({
|
|
4093
|
+
method: 'GET',
|
|
4094
|
+
url: 'http://localhost:' + fastify.server.address().port + '/custom',
|
|
4095
|
+
followRedirect: false
|
|
4096
|
+
}, (err, response, body) => {
|
|
4097
|
+
t.error(err)
|
|
4098
|
+
t.equal(response.statusCode, 200)
|
|
4099
|
+
t.equal(response.headers['content-type'], 'text/html; charset=windows-1252')
|
|
4100
|
+
t.equal(response.headers['content-length'], contentLength)
|
|
4101
|
+
t.equal(body.toString(), fooContent)
|
|
4102
|
+
})
|
|
4103
|
+
})
|
|
4104
|
+
})
|
package/types/index.d.ts
CHANGED
|
@@ -72,6 +72,7 @@ declare namespace fastifyStatic {
|
|
|
72
72
|
// Passed on to `send`
|
|
73
73
|
export interface SendOptions {
|
|
74
74
|
acceptRanges?: boolean;
|
|
75
|
+
contentType?: boolean;
|
|
75
76
|
cacheControl?: boolean;
|
|
76
77
|
dotfiles?: 'allow' | 'deny' | 'ignore';
|
|
77
78
|
etag?: boolean;
|
|
@@ -103,6 +104,7 @@ declare namespace fastifyStatic {
|
|
|
103
104
|
|
|
104
105
|
// Passed on to `send`
|
|
105
106
|
acceptRanges?: boolean;
|
|
107
|
+
contentType?: boolean;
|
|
106
108
|
cacheControl?: boolean;
|
|
107
109
|
dotfiles?: 'allow' | 'deny' | 'ignore';
|
|
108
110
|
etag?: boolean;
|
package/types/index.test-d.ts
CHANGED
|
@@ -13,13 +13,13 @@ const fastifyStaticCjs = require('..')
|
|
|
13
13
|
|
|
14
14
|
const app: FastifyInstance = fastify()
|
|
15
15
|
|
|
16
|
-
app.register(fastifyStatic)
|
|
17
|
-
app.register(fastifyStaticNamed)
|
|
18
|
-
app.register(fastifyStaticCjs)
|
|
19
|
-
app.register(fastifyStaticCjsImport.default)
|
|
20
|
-
app.register(fastifyStaticCjsImport.fastifyStatic)
|
|
21
|
-
app.register(fastifyStaticStar.default)
|
|
22
|
-
app.register(fastifyStaticStar.fastifyStatic)
|
|
16
|
+
app.register(fastifyStatic, { root: __dirname })
|
|
17
|
+
app.register(fastifyStaticNamed, { root: __dirname })
|
|
18
|
+
app.register(fastifyStaticCjs, { root: __dirname })
|
|
19
|
+
app.register(fastifyStaticCjsImport.default, { root: __dirname })
|
|
20
|
+
app.register(fastifyStaticCjsImport.fastifyStatic, { root: __dirname })
|
|
21
|
+
app.register(fastifyStaticStar.default, { root: __dirname })
|
|
22
|
+
app.register(fastifyStaticStar.fastifyStatic, { root: __dirname })
|
|
23
23
|
|
|
24
24
|
expectType<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStatic)
|
|
25
25
|
expectType<FastifyPluginAsync<FastifyStaticOptions, Server>>(fastifyStaticNamed)
|
|
@@ -34,6 +34,7 @@ expectType<any>(fastifyStaticCjs)
|
|
|
34
34
|
const appWithImplicitHttp = fastify()
|
|
35
35
|
const options: FastifyStaticOptions = {
|
|
36
36
|
acceptRanges: true,
|
|
37
|
+
contentType: true,
|
|
37
38
|
cacheControl: true,
|
|
38
39
|
decorateReply: true,
|
|
39
40
|
dotfiles: 'allow',
|
|
@@ -145,6 +146,10 @@ appWithHttp2
|
|
|
145
146
|
appWithHttp2.get('/download/2', (request, reply) => {
|
|
146
147
|
reply.download('some-file-name', 'some-filename', { cacheControl: false, acceptRanges: true })
|
|
147
148
|
})
|
|
149
|
+
|
|
150
|
+
appWithHttp2.get('/download/3', (request, reply) => {
|
|
151
|
+
reply.download('some-file-name', 'some-filename', { contentType: false })
|
|
152
|
+
})
|
|
148
153
|
})
|
|
149
154
|
|
|
150
155
|
const multiRootAppWithImplicitHttp = fastify()
|
|
@@ -165,6 +170,10 @@ multiRootAppWithImplicitHttp
|
|
|
165
170
|
reply.sendFile('some-file-name', 'some-root-name', { cacheControl: false, acceptRanges: true })
|
|
166
171
|
})
|
|
167
172
|
|
|
173
|
+
multiRootAppWithImplicitHttp.get('/', (request, reply) => {
|
|
174
|
+
reply.sendFile('some-file-name', 'some-root-name-2', { contentType: false })
|
|
175
|
+
})
|
|
176
|
+
|
|
168
177
|
multiRootAppWithImplicitHttp.get('/download', (request, reply) => {
|
|
169
178
|
reply.download('some-file-name')
|
|
170
179
|
})
|
|
@@ -176,6 +185,10 @@ multiRootAppWithImplicitHttp
|
|
|
176
185
|
multiRootAppWithImplicitHttp.get('/download/2', (request, reply) => {
|
|
177
186
|
reply.download('some-file-name', 'some-filename', { cacheControl: false, acceptRanges: true })
|
|
178
187
|
})
|
|
188
|
+
|
|
189
|
+
multiRootAppWithImplicitHttp.get('/download/3', (request, reply) => {
|
|
190
|
+
reply.download('some-file-name', 'some-filename', { contentType: false })
|
|
191
|
+
})
|
|
179
192
|
})
|
|
180
193
|
|
|
181
194
|
const noIndexApp = fastify()
|