@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 CHANGED
@@ -1,51 +1,31 @@
1
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
- }
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
- "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
- }
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://www.fastify.io/docs/latest/Reference/Routes/#constraints).
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://www.fastify.io/docs/latest/Reference/Server/#setnotfoundhandler).
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://www.fastify.io/docs/latest/Reference/Server/#seterrorhandler).
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 { promisify } = require('node:util')
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 winSeparatorRegex = new RegExp(`\\${path.win32.sep}`, 'g')
18
- const backslashRegex = /\\/g
19
- const startForwardSlashRegex = /^\//
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 globPattern = '**/**'
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 files = await globPromise(path.join(rootPath, globPattern).replace(winSeparatorRegex, path.posix.sep), { nodir: true, dot: opts.serveDotFiles })
140
- const indexes = opts.index === undefined ? ['index.html'] : [].concat(opts.index)
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].replace(rootPath.replace(backslashRegex, '/'), '')
144
- .replace(startForwardSlashRegex, '')
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, '/' + file, rootPath)
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 ([...new Set(rootPath)].length !== rootPath.length) {
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 (e) {
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 (error) {
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 (error) {
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 (error) {
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 (error) {
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(/\\/g, '/'),
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": "6.11.2",
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": "^8.0.1",
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.29.0",
58
+ "tsd": "^0.30.0",
58
59
  "typescript": "^5.1.6"
59
60
  },
60
61
  "tsd": {
@@ -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 (typeof reply.sendFile === 'undefined') {
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 (typeof reply.sendFile === 'undefined') {
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 (typeof reply.download === 'undefined') {
1319
+ if (reply.download === undefined) {
1320
1320
  t.equal(reply.download, undefined)
1321
1321
  reply.send('pass')
1322
1322
  } else {
@@ -1,13 +1,10 @@
1
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
- }
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?: (...args: any[]) => void;
93
+ setHeaders?: (res: SetHeadersResponse, path: string, stat: Stats) => void;
87
94
  redirect?: boolean;
88
95
  wildcard?: boolean;
89
96
  list?: boolean | ListOptionsJsonFormat | ListOptionsHtmlFormat;
@@ -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: any, pathName: any) => {
53
- res.setHeader('test', pathName)
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) => {