diff --git a/package.json b/package.json index 2fd9f492..8d74e84a 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@fastify/accept-negotiator": "^2.0.0", "@fastify/send": "^3.1.0", "content-disposition": "^0.5.4", - "fastify-plugin": "^5.0.0", + "fastify-plugin": "git+https://github.com/livingspec/fastify-plugin.git#support-decorators", "fastq": "^1.17.1", "glob": "^11.0.0" }, @@ -42,7 +42,7 @@ "@types/node": "^22.0.0", "concat-stream": "^2.0.0", "eslint": "^9.9.0", - "fastify": "^5.0.0-alpha.4", + "fastify": "git+https://github.com/livingspec/fastify.git#type-improvements", "neostandard": "^0.11.3", "pino": "^9.1.0", "proxyquire": "^2.1.3", diff --git a/types/index.d.ts b/types/index.d.ts index 1af2a6bc..a4d1bdec 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -2,23 +2,38 @@ // Leo /// -import { FastifyPluginAsync, FastifyReply, FastifyRequest, RouteOptions } from 'fastify' +import { + ApplyDecorators, + FastifyPluginAsync, + FastifyReply, + FastifyRequest, + RouteOptions, + AnyFastifyInstance, + UnEncapsulatedPlugin, + FastifyPluginOptions +} from 'fastify' import { Stats } from 'fs' -declare module 'fastify' { - interface FastifyReply { - sendFile(filename: string, rootPath?: string): FastifyReply; - sendFile(filename: string, options?: fastifyStatic.SendOptions): FastifyReply; - sendFile(filename: string, rootPath?: string, options?: fastifyStatic.SendOptions): FastifyReply; - download(filepath: string, options?: fastifyStatic.SendOptions): FastifyReply; - download(filepath: string, filename?: string): FastifyReply; - download(filepath: string, filename?: string, options?: fastifyStatic.SendOptions): FastifyReply; +declare namespace fastifyStatic { + export type FastifyStaticPluginDecorators = { + reply: { + sendFile(filename: string, rootPath?: string): FastifyReply; + sendFile(filename: string, options?: fastifyStatic.SendOptions): FastifyReply; + sendFile(filename: string, rootPath?: string, options?: fastifyStatic.SendOptions): FastifyReply; + download(filepath: string, options?: fastifyStatic.SendOptions): FastifyReply; + download(filepath: string, filename?: string): FastifyReply; + download(filepath: string, filename?: string, options?: fastifyStatic.SendOptions): FastifyReply; + } } -} -type FastifyStaticPlugin = FastifyPluginAsync> + export type FastifyStaticPlugin = UnEncapsulatedPlugin< + FastifyPluginAsync< + NonNullable, + TInstance, + ApplyDecorators + > + > -declare namespace fastifyStatic { export interface SetHeadersResponse { getHeader: FastifyReply['getHeader']; setHeader: FastifyReply['header']; @@ -70,7 +85,7 @@ declare namespace fastifyStatic { } // Passed on to `send` - export interface SendOptions { + export interface SendOptions extends FastifyPluginOptions { acceptRanges?: boolean; cacheControl?: boolean; dotfiles?: 'allow' | 'deny' | 'ignore'; @@ -119,6 +134,6 @@ declare namespace fastifyStatic { export { fastifyStatic as default } } -declare function fastifyStatic (...params: Parameters): ReturnType +declare function fastifyStatic (...params: Parameters): ReturnType export = fastifyStatic diff --git a/types/index.test-d.ts b/types/index.test-d.ts index 75f21be0..d53493d2 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -1,36 +1,41 @@ -import fastify, { FastifyInstance, FastifyPluginAsync, FastifyRequest, FastifyReply } from 'fastify' -import { Server } from 'http' +import fastify, { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify' import { Stats } from 'fs' import { expectAssignable, expectError, expectType } from 'tsd' import * as fastifyStaticStar from '..' import fastifyStatic, { + FastifyStaticPlugin, FastifyStaticOptions, - fastifyStatic as fastifyStaticNamed + fastifyStatic as fastifyStaticNamed, + FastifyStaticPluginDecorators } from '..' +// TODO: remove after we land in fastify-plugin +import { createPlugin } from 'fastify-plugin' import fastifyStaticCjsImport = require('..') const fastifyStaticCjs = require('..') const app: FastifyInstance = fastify() -app.register(fastifyStatic) -app.register(fastifyStaticNamed) -app.register(fastifyStaticCjs) -app.register(fastifyStaticCjsImport.default) -app.register(fastifyStaticCjsImport.fastifyStatic) -app.register(fastifyStaticStar.default) -app.register(fastifyStaticStar.fastifyStatic) - -expectType>(fastifyStatic) -expectType>(fastifyStaticNamed) -expectType>(fastifyStaticCjsImport.default) -expectType>(fastifyStaticCjsImport.fastifyStatic) -expectType>(fastifyStaticStar.default) -expectType>( - fastifyStaticStar.fastifyStatic -) +app.register(fastifyStatic, { root: '/' }) +app.register(fastifyStaticNamed, { root: '/' }) +app.register(fastifyStaticCjs, { root: '/' }) +app.register(fastifyStaticCjsImport.default, { root: '/' }) +app.register(fastifyStaticCjsImport.fastifyStatic, { root: '/' }) +app.register(fastifyStaticStar.default, { root: '/' }) +app.register(fastifyStaticStar.fastifyStatic, { root: '/' }) + +expectType(fastifyStatic) +expectType(fastifyStaticNamed) +expectType(fastifyStaticCjsImport.default) +expectType(fastifyStaticCjsImport.fastifyStatic) +expectType(fastifyStaticStar.default) +expectType(fastifyStaticStar.fastifyStatic) expectType(fastifyStaticCjs) +// make sure instance properties are preserved +const serverWithHttp2 = fastify({ http2: true }) +expectAssignable(serverWithHttp2.register(fastifyStatic, { root: '/' })) + const appWithImplicitHttp = fastify() const options: FastifyStaticOptions = { acceptRanges: true, @@ -119,8 +124,12 @@ expectAssignable({ appWithImplicitHttp .register(fastifyStatic, options) - .after(() => { - appWithImplicitHttp.get('/', (request, reply) => { + .after((err, instance) => { + if (err) { + // handle error + } + + instance.get('/', (request, reply) => { reply.sendFile('some-file-name') }) }) @@ -129,20 +138,24 @@ const appWithHttp2 = fastify({ http2: true }) appWithHttp2 .register(fastifyStatic, options) - .after(() => { - appWithHttp2.get('/', (request, reply) => { + .after((err, instance) => { + if (err) { + // handle error + } + + instance.get('/', (request, reply) => { reply.sendFile('some-file-name') }) - appWithHttp2.get('/download', (request, reply) => { + instance.get('/download', (request, reply) => { reply.download('some-file-name') }) - appWithHttp2.get('/download/1', (request, reply) => { + instance.get('/download/1', (request, reply) => { reply.download('some-file-name', { maxAge: '2 days' }) }) - appWithHttp2.get('/download/2', (request, reply) => { + instance.get('/download/2', (request, reply) => { reply.download('some-file-name', 'some-filename', { cacheControl: false, acceptRanges: true }) }) }) @@ -152,28 +165,32 @@ options.root = [''] multiRootAppWithImplicitHttp .register(fastifyStatic, options) - .after(() => { - multiRootAppWithImplicitHttp.get('/', (request, reply) => { + .after((err, instance) => { + if (err) { + // handle error + } + + instance.get('/', (request, reply) => { reply.sendFile('some-file-name') }) - multiRootAppWithImplicitHttp.get('/', (request, reply) => { + instance.get('/', (request, reply) => { reply.sendFile('some-file-name', { cacheControl: false, acceptRanges: true }) }) - multiRootAppWithImplicitHttp.get('/', (request, reply) => { + instance.get('/', (request, reply) => { reply.sendFile('some-file-name', 'some-root-name', { cacheControl: false, acceptRanges: true }) }) - multiRootAppWithImplicitHttp.get('/download', (request, reply) => { + instance.get('/download', (request, reply) => { reply.download('some-file-name') }) - multiRootAppWithImplicitHttp.get('/download/1', (request, reply) => { + instance.get('/download/1', (request, reply) => { reply.download('some-file-name', { maxAge: '2 days' }) }) - multiRootAppWithImplicitHttp.get('/download/2', (request, reply) => { + instance.get('/download/2', (request, reply) => { reply.download('some-file-name', 'some-filename', { cacheControl: false, acceptRanges: true }) }) }) @@ -210,3 +227,13 @@ defaultIndexApp reply.send('

fastify-static

') }) }) + +const pluginWithFastifyStaticDependency = createPlugin((instance) => + instance.get('/', (req, res) => { + expectType(res.sendFile) + expectType(res.download) + }), { dependencies: [fastifyStatic] }) + +expectError(fastify().register(pluginWithFastifyStaticDependency)) + +fastify().register(fastifyStatic, { root: '' }).register(pluginWithFastifyStaticDependency)