@fastify/static 8.0.4 → 8.1.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.
@@ -9,5 +9,5 @@ updates:
9
9
  - package-ecosystem: "npm"
10
10
  directory: "/"
11
11
  schedule:
12
- interval: "weekly"
12
+ interval: "monthly"
13
13
  open-pull-requests-limit: 10
package/README.md CHANGED
@@ -115,12 +115,13 @@ fastify.get('/path/without/cache/control', function (req, reply) {
115
115
 
116
116
  #### `root` (required)
117
117
 
118
- The absolute path of the directory that contains the files to serve.
119
- The file to serve will be determined by combining `req.url` with the
120
- provided root directory.
118
+ The absolute path of the directory containing the files to serve.
119
+ The file to serve is determined by combining `req.url` with the
120
+ root directory.
121
121
 
122
- You can also provide an array of directories containing files to serve.
123
- This is useful for serving multiple static directories under a single prefix. Files are served in a "first found, first served" manner, so the order in which you list the directories is important. For best performance, you should always list your main asset directory first. Duplicate paths will raise an error.
122
+ An array of directories can be provided to serve multiple static directories
123
+ under a single prefix. Files are served in a "first found, first served" manner,
124
+ so list directories in order of priority. Duplicate paths will raise an error.
124
125
 
125
126
  #### `prefix`
126
127
 
@@ -132,20 +133,26 @@ A URL path prefix used to create a virtual mount path for the static directory.
132
133
 
133
134
  Default: `{}`
134
135
 
135
- Constraints that will be added to registered routes. See Fastify's documentation for
136
+ Constraints to add to registered routes. See Fastify's documentation for
136
137
  [route constraints](https://fastify.dev/docs/latest/Reference/Routes/#constraints).
137
138
 
139
+ #### `logLevel`
140
+
141
+ Default: `info`
142
+
143
+ Set log level for registered routes.
144
+
138
145
  #### `prefixAvoidTrailingSlash`
139
146
 
140
147
  Default: `false`
141
148
 
142
- If set to false prefix will get trailing "/" at the end. If set to true, prefix will not append "/" to prefix.
149
+ If `false`, the prefix gets a trailing "/". If `true`, no trailing "/" is added to the prefix.
143
150
 
144
151
  #### `schemaHide`
145
152
 
146
153
  Default: `true`
147
154
 
148
- A flag that defines if the fastify route hide-schema attribute is hidden or not
155
+ A flag that defines if the fastify route hide-schema attribute is hidden or not.
149
156
 
150
157
  #### `setHeaders`
151
158
 
@@ -153,7 +160,7 @@ Default: `undefined`
153
160
 
154
161
  A function to set custom headers on the response. Alterations to the headers
155
162
  must be done synchronously. The function is called as `fn(res, path, stat)`,
156
- where the arguments are:
163
+ with the arguments:
157
164
 
158
165
  - `res` The response object.
159
166
  - `path` The path of the file that is being sent.
@@ -166,7 +173,7 @@ The following options are also supported and will be passed directly to the
166
173
 
167
174
  - [`acceptRanges`](https://www.npmjs.com/package/@fastify/send#acceptranges)
168
175
  - [`contentType`](https://www.npmjs.com/package/@fastify/send#contenttype)
169
- - [`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.)
176
+ - [`cacheControl`](https://www.npmjs.com/package/@fastify/send#cachecontrol) - Enable or disable setting Cache-Control response header (defaults to `true`). To provide a custom Cache-Control header, set this option to false
170
177
  - [`dotfiles`](https://www.npmjs.com/package/@fastify/send#dotfiles)
171
178
  - [`etag`](https://www.npmjs.com/package/@fastify/send#etag)
172
179
  - [`extensions`](https://www.npmjs.com/package/@fastify/send#extensions)
@@ -175,7 +182,7 @@ The following options are also supported and will be passed directly to the
175
182
  - [`lastModified`](https://www.npmjs.com/package/@fastify/send#lastmodified)
176
183
  - [`maxAge`](https://www.npmjs.com/package/@fastify/send#maxage)
177
184
 
178
- 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.
185
+ These options can be altered when calling `reply.sendFile('filename.html', options)` or `reply.sendFile('filename.html', 'otherfilename.html', options)` on each response.
179
186
 
180
187
  #### `redirect`
181
188
 
@@ -183,61 +190,56 @@ Default: `false`
183
190
 
184
191
  If set to `true`, `@fastify/static` redirects to the directory with a trailing slash.
185
192
 
186
- This option cannot be set to `true` with `wildcard` set to `false` on a server
187
- with `ignoreTrailingSlash` set to `true`.
193
+ This option cannot be `true` if `wildcard` is `false` and `ignoreTrailingSlash` is `true`.
188
194
 
189
- If this option is set to `false`, then requesting directories without trailing
190
- slash will trigger your app's 404 handler using `reply.callNotFound()`.
195
+ If `false`, requesting directories without a trailing slash triggers the app's 404 handler using `reply.callNotFound()`.
191
196
 
192
197
  #### `wildcard`
193
198
 
194
199
  Default: `true`
195
200
 
196
- If set to `true`, `@fastify/static` adds a wildcard route to serve files.
197
- If set to `false`, `@fastify/static` globs the filesystem for all defined
198
- files in the served folder (`${root}/**/**`), and just creates the routes needed for
199
- those and it will not serve the newly added file on the filesystem.
201
+ If `true`, `@fastify/static` adds a wildcard route to serve files.
202
+ If `false`, it globs the filesystem for all defined files in the
203
+ served folder (`${root}/**/**`) and creates the necessary routes,
204
+ but will not serve newly added files.
200
205
 
201
- The default options of https://www.npmjs.com/package/glob are applied
202
- for getting the file list.
206
+ The default options of [`glob`](https://www.npmjs.com/package/glob)
207
+ are applied for getting the file list.
203
208
 
204
- This option cannot be set to `false` with `redirect` set to `true` on a server
205
- with `ignoreTrailingSlash` set to `true`.
209
+ This option cannot be `false` if `redirect` is `true` and `ignoreTrailingSlash` is `true`.
206
210
 
207
211
  #### `allowedPath`
208
212
 
209
213
  Default: `(pathName, root, request) => true`
210
214
 
211
- This function allows filtering the served files. Also, with the help of the request object a more complex path authentication is possible.
212
- If the function returns `true`, the file will be served.
213
- If the function returns `false`, Fastify's 404 handler will be called.
215
+ This function filters served files. Using the request object, complex path authentication is possible.
216
+ Returning `true` serves the file; returning `false` calls Fastify's 404 handler.
214
217
 
215
218
  #### `index`
216
219
 
217
220
  Default: `undefined`
218
221
 
219
- Under the hood we use [`@fastify/send`](https://www.npmjs.com/package/@fastify/send) lib that by default supports "index.html" files.
220
- To disable this set false or to supply a new index pass a string or an array in preferred order.
222
+ Under the hood, [`@fastify/send`](https://www.npmjs.com/package/@fastify/send) supports "index.html" files by default.
223
+ To disable this, set `false`, or supply a new index by passing a string or an array in preferred order.
221
224
 
222
225
  #### `serveDotFiles`
223
226
 
224
227
  Default: `false`
225
228
 
226
- When `true`, files in hidden directories (e.g. `.foo`) will be served.
229
+ If `true`, serves files in hidden directories (e.g., `.foo`).
227
230
 
228
231
  #### `list`
229
232
 
230
233
  Default: `undefined`
231
234
 
232
- If set, it provides the directory list calling the directory path.
235
+ If set, provides the directory list by calling the directory path.
236
+ Default response is JSON.
233
237
 
234
- Default response is json.
238
+ Multi-root is not supported within the `list` option.
235
239
 
236
- Note:
237
- - Multi-root is not supported within the `list` option.
238
- - If `dotfiles` option value is `deny` or `ignore`, dotfiles will be excluded.
240
+ If `dotfiles` is `deny` or `ignore`, dotfiles are excluded.
239
241
 
240
- **Example:**
242
+ Example:
241
243
 
242
244
  ```js
243
245
  fastify.register(require('@fastify/static'), {
@@ -251,7 +253,7 @@ fastify.register(require('@fastify/static'), {
251
253
  Request
252
254
 
253
255
  ```bash
254
- GET .../public
256
+ GET /public
255
257
  ```
256
258
 
257
259
  Response
@@ -266,17 +268,17 @@ Default: `json`
266
268
 
267
269
  Options: `html`, `json`
268
270
 
269
- Directory list can be also in `html` format; in that case, `list.render` function is required.
271
+ Directory list can be in `html` format; in that case, `list.render` function is required.
270
272
 
271
- You can override the option with URL parameter `format`. Options are `html` and `json`.
273
+ This option can be overridden by the URL parameter `format`. Options are `html` and `json`.
272
274
 
273
275
  ```bash
274
- GET .../public/assets?format=json
276
+ GET /public/assets?format=json
275
277
  ```
276
278
 
277
- will return the response as json independent of `list.format`.
279
+ Returns the response as JSON, regardless of `list.format`.
278
280
 
279
- **Example:**
281
+ Example:
280
282
 
281
283
  ```js
282
284
  fastify.register(require('@fastify/static'), {
@@ -303,7 +305,7 @@ fastify.register(require('@fastify/static'), {
303
305
  Request
304
306
 
305
307
  ```bash
306
- GET .../public
308
+ GET /public
307
309
  ```
308
310
 
309
311
  Response
@@ -327,11 +329,11 @@ Response
327
329
 
328
330
  Default: `['']`
329
331
 
330
- Directory list can respond to different routes, declared in `list.names` options.
332
+ Directory list can respond to different routes declared in `list.names`.
331
333
 
332
- Note: if a file with the same name exists, the actual file is sent.
334
+ > 🛈 Note: If a file with the same name exists, the actual file is sent.
333
335
 
334
- **Example:**
336
+ Example:
335
337
 
336
338
  ```js
337
339
  fastify.register(require('@fastify/static'), {
@@ -345,20 +347,20 @@ fastify.register(require('@fastify/static'), {
345
347
  })
346
348
  ```
347
349
 
348
- Dir list respond with the same content to
350
+ Dir list respond with the same content to:
349
351
 
350
352
  ```bash
351
- GET .../public
352
- GET .../public/
353
- GET .../public/index
354
- GET .../public/index.json
353
+ GET /public
354
+ GET /public/
355
+ GET /public/index
356
+ GET /public/index.json
355
357
  ```
356
358
 
357
359
  #### `list.extendedFolderInfo`
358
360
 
359
361
  Default: `undefined`
360
362
 
361
- If `true` some extended information for folders will be accessible in `list.render` and in the json response.
363
+ If `true`, extended information for folders will be accessible in `list.render` and the JSON response.
362
364
 
363
365
  ```js
364
366
  render(dirs, files) {
@@ -372,7 +374,7 @@ render(dirs, files) {
372
374
  }
373
375
  ```
374
376
 
375
- Warning: This will slightly decrease the performance, especially for deeply nested file structures.
377
+ > ⚠ Warning: This will slightly decrease the performance, especially for deeply nested file structures.
376
378
 
377
379
  #### `list.jsonFormat`
378
380
 
@@ -380,7 +382,7 @@ Default: `names`
380
382
 
381
383
  Options: `names`, `extended`
382
384
 
383
- This option determines the output format when `json` is selected.
385
+ Determines the output format when `json` is selected.
384
386
 
385
387
  `names`:
386
388
  ```json
@@ -404,13 +406,11 @@ This option determines the output format when `json` is selected.
404
406
  "name": "dir1",
405
407
  "stats": {
406
408
  "dev": 2100,
407
- "size": 4096,
408
- ...
409
+ "size": 4096
409
410
  },
410
411
  "extendedInfo": {
411
412
  "fileCount": 4,
412
- "totalSize": 51233,
413
- ...
413
+ "totalSize": 51233
414
414
  }
415
415
  }
416
416
  ],
@@ -419,8 +419,7 @@ This option determines the output format when `json` is selected.
419
419
  "name": "file1.txt",
420
420
  "stats": {
421
421
  "dev": 2200,
422
- "size": 554,
423
- ...
422
+ "size": 554
424
423
  }
425
424
  }
426
425
  ]
@@ -431,9 +430,9 @@ This option determines the output format when `json` is selected.
431
430
 
432
431
  Default: `false`
433
432
 
434
- Try to send the brotli encoded asset first (when supported within the `Accept-Encoding` headers), retry for gzip, and then fall back to the original `pathname`. You may choose to skip compression for smaller files that do not benefit from it.
433
+ First, try to send the brotli encoded asset (if supported by `Accept-Encoding` headers), then gzip, and finally the original `pathname`. Skip compression for smaller files that do not benefit from it.
435
434
 
436
- Assume this structure with the compressed asset as a sibling of the un-compressed counterpart:
435
+ Assume this structure with the compressed asset as a sibling of the uncompressed counterpart:
437
436
 
438
437
  ```
439
438
  ./public
@@ -447,20 +446,19 @@ Assume this structure with the compressed asset as a sibling of the un-compresse
447
446
 
448
447
  #### Disable serving
449
448
 
450
- If you would just like to use the reply decorator and not serve whole directories automatically, you can simply pass the option `{ serve: false }`. This will prevent the plugin from serving everything under `root`.
449
+ To use only the reply decorator without serving directories, pass `{ serve: false }`.
450
+ This prevents the plugin from serving everything under `root`.
451
451
 
452
452
  #### Disabling reply decorator
453
453
 
454
- The reply object is decorated with a `sendFile` function by default. If you want to
455
- disable this, pass the option `{ decorateReply: false }`. If @fastify/static is
456
- registered to multiple prefixes in the same route only one can initialize reply
457
- decorators.
454
+ The reply object is decorated with a `sendFile` function by default. To disable this,
455
+ pass `{ decorateReply: false }`. If `@fastify/static` is registered to multiple prefixes
456
+ in the same route, only one can initialize reply decorators.
458
457
 
459
458
  #### Handling 404s
460
459
 
461
- If a request matches the URL `prefix` but a file cannot be found for the
462
- request, Fastify's 404 handler will be called. You can set a custom 404
463
- handler with [`fastify.setNotFoundHandler()`](https://fastify.dev/docs/latest/Reference/Server/#setnotfoundhandler).
460
+ If a request matches the URL `prefix` but no file is found, Fastify's 404
461
+ handler is called. Set a custom 404 handler with [`fastify.setNotFoundHandler()`](https://fastify.dev/docs/latest/Reference/Server/#setnotfoundhandler).
464
462
 
465
463
  When registering `@fastify/static` within an encapsulated context, the `wildcard` option may need to be set to `false` to support index resolution and nested not-found-handler:
466
464
 
@@ -483,13 +481,12 @@ This code will send the `index.html` for the paths `docs`, `docs/`, and `docs/in
483
481
 
484
482
  ### Handling Errors
485
483
 
486
- If an error occurs while trying to send a file, the error will be passed
487
- to Fastify's error handler. You can set a custom error handler with
488
- [`fastify.setErrorHandler()`](https://fastify.dev/docs/latest/Reference/Server/#seterrorhandler).
484
+ If an error occurs while sending a file, it is passed to Fastify's error handler.
485
+ Set a custom handler with [`fastify.setErrorHandler()`](https://fastify.dev/docs/latest/Reference/Server/#seterrorhandler).
489
486
 
490
487
  ### Payload `stream.path`
491
488
 
492
- If you need to access the file path inside the `onSend` hook, you can use `payload.path`.
489
+ Access the file path inside the `onSend` hook using `payload.path`.
493
490
 
494
491
  ```js
495
492
  fastify.addHook('onSend', function (req, reply, payload, next) {
package/index.js CHANGED
@@ -64,6 +64,7 @@ async function fastifyStatic (fastify, opts) {
64
64
  schema: {
65
65
  hide: opts.schemaHide !== undefined ? opts.schemaHide : true
66
66
  },
67
+ logLevel: opts.logLevel,
67
68
  errorHandler (error, request, reply) {
68
69
  if (error?.code === 'ERR_STREAM_PREMATURE_CLOSE') {
69
70
  reply.request.raw.destroy()
@@ -108,7 +109,7 @@ async function fastifyStatic (fastify, opts) {
108
109
 
109
110
  if (opts.serve !== false) {
110
111
  if (opts.wildcard && typeof opts.wildcard !== 'boolean') {
111
- throw new Error('"wildcard" option must be a boolean')
112
+ throw new TypeError('"wildcard" option must be a boolean')
112
113
  }
113
114
  if (opts.wildcard === undefined || opts.wildcard === true) {
114
115
  fastify.route({
package/lib/dirList.js CHANGED
@@ -108,7 +108,7 @@ const dirList = {
108
108
  */
109
109
  send: async function ({ reply, dir, options, route, prefix, dotfiles }) {
110
110
  if (reply.request.query.format === 'html' && typeof options.render !== 'function') {
111
- throw new Error('The `list.render` option must be a function and is required with the URL parameter `format=html`')
111
+ throw new TypeError('The `list.render` option must be a function and is required with the URL parameter `format=html`')
112
112
  }
113
113
 
114
114
  let entries
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastify/static",
3
- "version": "8.0.4",
3
+ "version": "8.1.0",
4
4
  "description": "Plugin for serving static files as fast as possible.",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
@@ -3492,3 +3492,124 @@ test('respect the .type when using with sendFile with contentType disabled', asy
3492
3492
  t.assert.deepStrictEqual(response.headers.get('content-length'), contentLength)
3493
3493
  t.assert.deepStrictEqual(await response.text(), fooContent)
3494
3494
  })
3495
+
3496
+ test('register /static/ with custom log level', async t => {
3497
+ t.plan(9)
3498
+
3499
+ const pluginOptions = {
3500
+ root: path.join(__dirname, '/static'),
3501
+ prefix: '/static/',
3502
+ logLevel: 'warn'
3503
+ }
3504
+ const fastify = Fastify({
3505
+ logger: {
3506
+ stream: {
3507
+ write: (logLine) => {
3508
+ if (logLine.includes('"msg":"incoming request"')) {
3509
+ console.warn(logLine)
3510
+ throw new Error('Should never reach this point since log level is set at WARN!! Unexpected log line: ' + logLine)
3511
+ }
3512
+ },
3513
+ },
3514
+ },
3515
+ })
3516
+ fastify.register(fastifyStatic, pluginOptions)
3517
+
3518
+ t.after(() => fastify.close())
3519
+
3520
+ await fastify.listen({ port: 0 })
3521
+ fastify.server.unref()
3522
+
3523
+ await t.test('/static/index.html', async (t) => {
3524
+ t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT)
3525
+
3526
+ const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/index.html')
3527
+ t.assert.ok(response.ok)
3528
+ t.assert.deepStrictEqual(response.status, 200)
3529
+ t.assert.deepStrictEqual(await response.text(), indexContent)
3530
+ genericResponseChecks(t, response)
3531
+ })
3532
+
3533
+ await t.test('/static/index.html', async t => {
3534
+ t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT)
3535
+ const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/index.html', { method: 'HEAD' })
3536
+ t.assert.ok(response.ok)
3537
+ t.assert.deepStrictEqual(response.status, 200)
3538
+ t.assert.deepStrictEqual(await response.text(), '')
3539
+ genericResponseChecks(t, response)
3540
+ })
3541
+
3542
+ await t.test('/static/index.css', async (t) => {
3543
+ t.plan(2 + GENERIC_RESPONSE_CHECK_COUNT)
3544
+ const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/index.css')
3545
+ t.assert.ok(response.ok)
3546
+ t.assert.deepStrictEqual(response.status, 200)
3547
+ genericResponseChecks(t, response)
3548
+ })
3549
+
3550
+ await t.test('/static/', async (t) => {
3551
+ t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT)
3552
+ const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/')
3553
+
3554
+ t.assert.ok(response.ok)
3555
+ t.assert.deepStrictEqual(response.status, 200)
3556
+ t.assert.deepStrictEqual(await response.text(), indexContent)
3557
+ genericResponseChecks(t, response)
3558
+ })
3559
+
3560
+ await t.test('/static/deep/path/for/test/purpose/foo.html', async (t) => {
3561
+ t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT)
3562
+ const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/deep/path/for/test/purpose/foo.html')
3563
+
3564
+ t.assert.ok(response.ok)
3565
+ t.assert.deepStrictEqual(response.status, 200)
3566
+ t.assert.deepStrictEqual(await response.text(), deepContent)
3567
+ genericResponseChecks(t, response)
3568
+ })
3569
+ await t.test('/static/deep/path/for/test/', async (t) => {
3570
+ t.plan(3 + GENERIC_RESPONSE_CHECK_COUNT)
3571
+ const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/deep/path/for/test/')
3572
+
3573
+ t.assert.ok(response.ok)
3574
+ t.assert.deepStrictEqual(response.status, 200)
3575
+ t.assert.deepStrictEqual(await response.text(), innerIndex)
3576
+ genericResponseChecks(t, response)
3577
+ })
3578
+
3579
+ await t.test('/static/this/path/for/test', async (t) => {
3580
+ t.plan(2 + GENERIC_ERROR_RESPONSE_CHECK_COUNT)
3581
+ const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/this/path/for/test')
3582
+
3583
+ t.assert.ok(!response.ok)
3584
+ t.assert.deepStrictEqual(response.status, 404)
3585
+ genericErrorResponseChecks(t, response)
3586
+ })
3587
+
3588
+ await t.test('/static/this/path/doesnt/exist.html', async (t) => {
3589
+ t.plan(2 + GENERIC_ERROR_RESPONSE_CHECK_COUNT)
3590
+ const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/this/path/doesnt/exist.html')
3591
+
3592
+ t.assert.ok(!response.ok)
3593
+ t.assert.deepStrictEqual(response.status, 404)
3594
+ genericErrorResponseChecks(t, response)
3595
+ })
3596
+
3597
+ await t.test('304', async t => {
3598
+ t.plan(5 + GENERIC_RESPONSE_CHECK_COUNT)
3599
+ const response = await fetch('http://localhost:' + fastify.server.address().port + '/static/index.html')
3600
+
3601
+ t.assert.ok(response.ok)
3602
+ t.assert.deepStrictEqual(response.status, 200)
3603
+ t.assert.deepStrictEqual(await response.text(), indexContent)
3604
+ genericResponseChecks(t, response)
3605
+
3606
+ const response2 = await fetch('http://localhost:' + fastify.server.address().port + '/static/index.html', {
3607
+ headers: {
3608
+ 'if-none-match': response.headers.get('etag')
3609
+ },
3610
+ cache: 'no-cache'
3611
+ })
3612
+ t.assert.ok(!response2.ok)
3613
+ t.assert.deepStrictEqual(response2.status, 304)
3614
+ })
3615
+ })
package/types/index.d.ts CHANGED
@@ -114,6 +114,7 @@ declare namespace fastifyStatic {
114
114
  lastModified?: boolean;
115
115
  maxAge?: string | number;
116
116
  constraints?: RouteOptions['constraints'];
117
+ logLevel?: RouteOptions['logLevel'];
117
118
  }
118
119
 
119
120
  export const fastifyStatic: FastifyStaticPlugin
@@ -68,7 +68,8 @@ const options: FastifyStaticOptions = {
68
68
  constraints: {
69
69
  host: /.*\.example\.com/,
70
70
  version: '1.0.2'
71
- }
71
+ },
72
+ logLevel: 'warn'
72
73
  }
73
74
 
74
75
  expectError<FastifyStaticOptions>({
@@ -1 +0,0 @@
1
- /none
@@ -1 +0,0 @@
1
- ../origin