@fastify/static
Version:
Plugin for serving static files as fast as possible.
229 lines (191 loc) • 6.51 kB
text/typescript
import fastify, { type FastifyInstance, type FastifyPluginAsync, type FastifyReply, type FastifyRequest } from 'fastify'
import { type Stats } from 'node:fs'
import { type Server } from 'node:http'
import { expect } from 'tstyche'
import * as fastifyStaticStar from '..'
import fastifyStatic, {
type FastifyStaticOptions,
fastifyStatic as fastifyStaticNamed
} from '..'
const fastifyStaticCjsImport = fastifyStaticStar
const fastifyStaticCjs = require('..')
const app: FastifyInstance = fastify()
app.register(fastifyStatic, { root: __dirname })
app.register(fastifyStaticNamed, { root: __dirname })
app.register(fastifyStaticCjs, { root: __dirname })
app.register(fastifyStaticCjsImport.default, { root: __dirname })
app.register(fastifyStaticCjsImport.fastifyStatic, { root: __dirname })
app.register(fastifyStaticStar.default, { root: __dirname })
app.register(fastifyStaticStar.fastifyStatic, { root: __dirname })
expect(fastifyStatic).type.toBe<FastifyPluginAsync<FastifyStaticOptions, Server>>()
expect(fastifyStaticNamed).type.toBe<FastifyPluginAsync<FastifyStaticOptions, Server>>()
expect(fastifyStaticCjsImport.default).type.toBe<FastifyPluginAsync<FastifyStaticOptions, Server>>()
expect(fastifyStaticCjsImport.fastifyStatic).type.toBe<FastifyPluginAsync<FastifyStaticOptions, Server>>()
expect(fastifyStaticStar.default).type.toBe<FastifyPluginAsync<FastifyStaticOptions, Server>>()
expect(fastifyStaticStar.fastifyStatic).type.toBe<FastifyPluginAsync<FastifyStaticOptions, Server>>()
expect(fastifyStaticCjs).type.toBe<any>()
const appWithImplicitHttp = fastify()
const options: FastifyStaticOptions = {
acceptRanges: true,
contentType: true,
cacheControl: true,
decorateReply: true,
dotfiles: 'allow',
etag: true,
extensions: ['.js'],
immutable: true,
index: ['1'],
lastModified: true,
maxAge: '',
prefix: '',
prefixAvoidTrailingSlash: false,
root: '',
schemaHide: true,
serve: true,
wildcard: true,
globIgnore: ['**/*.private'],
list: false,
setHeaders: (reply, path, stat) => {
expect(reply).type.toBe<FastifyReply>()
expect(reply.statusCode).type.toBe<number>()
expect(reply.getHeader('X-Test')).type.toBe<ReturnType<FastifyReply['getHeader']>>()
reply.header('X-Test', 'string')
expect(path).type.toBe<string>()
expect(stat).type.toBe<Stats>()
},
preCompressed: false,
allowedPath: (_pathName: string, _root: string, _request: FastifyRequest) => {
return true
},
constraints: {
host: /^.*\.example\.com$/,
version: '1.0.2'
},
logLevel: 'warn',
suppressWarning: true
}
expect<FastifyStaticOptions>()
.type.toBeAssignableFrom({
root: '',
list: {
format: 'json' as const
}
})
expect<FastifyStaticOptions>()
.type.toBeAssignableFrom({
root: '',
list: {
format: 'json' as const,
render: () => ''
}
})
expect<FastifyStaticOptions>()
.type.toBeAssignableFrom({
root: '',
list: {
format: 'html' as const,
render: () => ''
}
})
expect<FastifyStaticOptions>()
.type.toBeAssignableFrom({
root: ['']
})
expect<FastifyStaticOptions>()
.type.toBeAssignableFrom({
root: new URL('file://')
})
expect<FastifyStaticOptions>()
.type.toBeAssignableFrom({ root: [new URL('file://')] })
expect<FastifyStaticOptions>()
.type.toBeAssignableFrom({
serve: true as const,
root: ''
})
expect<FastifyStaticOptions>().type.not.toBeAssignableFrom({
serve: true as const,
})
appWithImplicitHttp
.register(fastifyStatic, options)
.after(() => {
appWithImplicitHttp.get('/', (_request, reply) => {
reply.sendFile('some-file-name')
})
})
const appWithHttp2 = fastify({ http2: true })
appWithHttp2
.register(fastifyStatic, options)
.after(() => {
appWithHttp2.get('/', (_request, reply) => {
reply.sendFile('some-file-name')
})
appWithHttp2.get('/download', (_request, reply) => {
reply.download('some-file-name')
})
appWithHttp2.get('/download/1', (_request, reply) => {
reply.download('some-file-name', { maxAge: '2 days' })
})
appWithHttp2.get('/download/2', (_request, reply) => {
reply.download('some-file-name', 'some-filename', { cacheControl: false, acceptRanges: true })
})
appWithHttp2.get('/download/3', (_request, reply) => {
reply.download('some-file-name', 'some-filename', { contentType: false })
})
})
const multiRootAppWithImplicitHttp = fastify()
options.root = ['']
multiRootAppWithImplicitHttp
.register(fastifyStatic, options)
.after(() => {
multiRootAppWithImplicitHttp.get('/', (_request, reply) => {
reply.sendFile('some-file-name')
})
multiRootAppWithImplicitHttp.get('/', (_request, reply) => {
reply.sendFile('some-file-name', { cacheControl: false, acceptRanges: true })
})
multiRootAppWithImplicitHttp.get('/', (_request, reply) => {
reply.sendFile('some-file-name', 'some-root-name', { cacheControl: false, acceptRanges: true })
})
multiRootAppWithImplicitHttp.get('/', (_request, reply) => {
reply.sendFile('some-file-name', 'some-root-name-2', { contentType: false })
})
multiRootAppWithImplicitHttp.get('/download', (_request, reply) => {
reply.download('some-file-name')
})
multiRootAppWithImplicitHttp.get('/download/1', (_request, reply) => {
reply.download('some-file-name', { maxAge: '2 days' })
})
multiRootAppWithImplicitHttp.get('/download/2', (_request, reply) => {
reply.download('some-file-name', 'some-filename', { cacheControl: false, acceptRanges: true })
})
multiRootAppWithImplicitHttp.get('/download/3', (_request, reply) => {
reply.download('some-file-name', 'some-filename', { contentType: false })
})
})
const noIndexApp = fastify()
options.root = ''
options.index = false
noIndexApp
.register(fastifyStatic, options)
.after(() => {
noIndexApp.get('/', (_request, reply) => {
reply.send('<h1>fastify-static</h1>')
})
})
options.root = new URL('file://')
const URLRootApp = fastify()
URLRootApp.register(fastifyStatic, options)
.after(() => {
URLRootApp.get('/', (_request, reply) => {
reply.send('<h1>fastify-static</h1>')
})
})
const defaultIndexApp = fastify()
options.index = 'index.html' as const
defaultIndexApp
.register(fastifyStatic, options)
.after(() => {
defaultIndexApp.get('/', (_request, reply) => {
reply.send('<h1>fastify-static</h1>')
})
})