From 5b00bce87de2d6646b3951b6a2c1ffa6e0ca7576 Mon Sep 17 00:00:00 2001 From: Nemanja Tosic Date: Sun, 8 Sep 2024 13:56:59 +0200 Subject: [PATCH 1/6] drop ambient module --- types/index.d.ts | 42 +++++++++++++++--------- types/index.test-d.ts | 74 ++++++++++++++++++++++++------------------- 2 files changed, 69 insertions(+), 47 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index 1af2a6bc..07a6209f 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -2,23 +2,35 @@ // Leo /// -import { FastifyPluginAsync, FastifyReply, FastifyRequest, RouteOptions } from 'fastify' +import { + FastifyInstance, + FastifyPluginAsync, + FastifyReply, + FastifyRequest, + RouteOptions, + AnyFastifyInstance, + UnEncapsulatedPlugin +} 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; - } -} - -type FastifyStaticPlugin = FastifyPluginAsync> - declare namespace fastifyStatic { + export type FastifyStaticPlugin = UnEncapsulatedPlugin< + FastifyPluginAsync< + NonNullable, + AnyFastifyInstance, + FastifyInstance + > + > + export interface SetHeadersResponse { getHeader: FastifyReply['getHeader']; setHeader: FastifyReply['header']; @@ -119,6 +131,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..52954e23 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -1,9 +1,9 @@ -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 } from '..' @@ -13,22 +13,20 @@ 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) const appWithImplicitHttp = fastify() @@ -119,8 +117,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 +131,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 +158,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 }) }) }) From d4ba889651ab629821a2498679e15fc38f1e9e90 Mon Sep 17 00:00:00 2001 From: Nemanja Tosic Date: Sun, 8 Sep 2024 22:03:38 +0200 Subject: [PATCH 2/6] Use WIP packages --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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", From 0d4a04f85dfebdfdd0c092ec781db65c14307f41 Mon Sep 17 00:00:00 2001 From: Nemanja Tosic Date: Sun, 27 Oct 2024 13:01:34 +0100 Subject: [PATCH 3/6] Add dependencies example --- types/createPlugin.ts | 26 ++++++++++++++++++++++++++ types/index.d.ts | 31 ++++++++++++++++++------------- types/index.test-d.ts | 15 ++++++++++++++- 3 files changed, 58 insertions(+), 14 deletions(-) create mode 100644 types/createPlugin.ts diff --git a/types/createPlugin.ts b/types/createPlugin.ts new file mode 100644 index 00000000..e044a9f1 --- /dev/null +++ b/types/createPlugin.ts @@ -0,0 +1,26 @@ +import { + FastifyPluginCallback, + FastifyPluginAsync, + FastifyPlugin, + ApplyDependencies, + UnEncapsulatedPlugin, + FastifyDependencies, +} from 'fastify' + +export function createPlugin< + TPlugin extends FastifyPluginCallback, + TDependencies extends FastifyDependencies, + TEnhanced extends ApplyDependencies = ApplyDependencies +> (plugin: TEnhanced, options?: { dependencies?: TDependencies }): UnEncapsulatedPlugin +export function createPlugin< + TPlugin extends FastifyPluginAsync, + TDependencies extends FastifyDependencies, + TEnhanced extends ApplyDependencies = ApplyDependencies +> (plugin: TEnhanced, options?: { dependencies?: TDependencies }): UnEncapsulatedPlugin +export function createPlugin< + TPlugin extends FastifyPlugin, + TDependencies extends FastifyDependencies, + TEnhanced extends ApplyDependencies = ApplyDependencies +> (plugin: TEnhanced, options?: { dependencies?: TDependencies }): UnEncapsulatedPlugin { + return plugin as UnEncapsulatedPlugin +} diff --git a/types/index.d.ts b/types/index.d.ts index 07a6209f..ada8c3e7 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -9,25 +9,30 @@ import { FastifyRequest, RouteOptions, AnyFastifyInstance, - UnEncapsulatedPlugin + UnEncapsulatedPlugin, + FastifyPluginOptions } from 'fastify' import { Stats } from 'fs' 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; + } + } + export type FastifyStaticPlugin = UnEncapsulatedPlugin< FastifyPluginAsync< - NonNullable, + // FIXME: fix before landing, POC for now + // NonNullable, + FastifyPluginOptions, AnyFastifyInstance, - FastifyInstance + FastifyInstance > > @@ -82,7 +87,7 @@ declare namespace fastifyStatic { } // Passed on to `send` - export interface SendOptions { + export interface SendOptions extends FastifyPluginOptions { acceptRanges?: boolean; cacheControl?: boolean; dotfiles?: 'allow' | 'deny' | 'ignore'; diff --git a/types/index.test-d.ts b/types/index.test-d.ts index 52954e23..8b41a392 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -5,8 +5,11 @@ 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 './createPlugin' import fastifyStaticCjsImport = require('..') const fastifyStaticCjs = require('..') @@ -220,3 +223,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).register(pluginWithFastifyStaticDependency) From 9c0ef6de592f772463a22ae7de09c69216c04b51 Mon Sep 17 00:00:00 2001 From: Nemanja Tosic Date: Sun, 27 Oct 2024 13:31:49 +0100 Subject: [PATCH 4/6] Address static plugin options fixme --- types/index.d.ts | 4 +--- types/index.test-d.ts | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index ada8c3e7..1b538bd9 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -28,9 +28,7 @@ declare namespace fastifyStatic { export type FastifyStaticPlugin = UnEncapsulatedPlugin< FastifyPluginAsync< - // FIXME: fix before landing, POC for now - // NonNullable, - FastifyPluginOptions, + NonNullable, AnyFastifyInstance, FastifyInstance > diff --git a/types/index.test-d.ts b/types/index.test-d.ts index 8b41a392..e4f06dfb 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -232,4 +232,4 @@ const pluginWithFastifyStaticDependency = createPlugin((instance) => expectError(fastify().register(pluginWithFastifyStaticDependency)) -fastify().register(fastifyStatic).register(pluginWithFastifyStaticDependency) +fastify().register(fastifyStatic, { root: '' }).register(pluginWithFastifyStaticDependency) From c27e7ecd8344cf646e4843beebed7dd3a7d9c0ea Mon Sep 17 00:00:00 2001 From: Nemanja Tosic Date: Wed, 13 Nov 2024 20:23:15 +0100 Subject: [PATCH 5/6] Streamline plugin declaration --- types/index.d.ts | 8 ++++---- types/index.test-d.ts | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index 1b538bd9..a4d1bdec 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -3,7 +3,7 @@ /// import { - FastifyInstance, + ApplyDecorators, FastifyPluginAsync, FastifyReply, FastifyRequest, @@ -26,11 +26,11 @@ declare namespace fastifyStatic { } } - export type FastifyStaticPlugin = UnEncapsulatedPlugin< + export type FastifyStaticPlugin = UnEncapsulatedPlugin< FastifyPluginAsync< NonNullable, - AnyFastifyInstance, - FastifyInstance + TInstance, + ApplyDecorators > > diff --git a/types/index.test-d.ts b/types/index.test-d.ts index e4f06dfb..9d65372b 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -32,6 +32,10 @@ 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, From f6322dd5495fe559fa5d151d93f95aee9f4d4005 Mon Sep 17 00:00:00 2001 From: Nemanja Tosic Date: Wed, 13 Nov 2024 20:54:35 +0100 Subject: [PATCH 6/6] Use createPlugin from fastify-plugin --- types/createPlugin.ts | 26 -------------------------- types/index.test-d.ts | 2 +- 2 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 types/createPlugin.ts diff --git a/types/createPlugin.ts b/types/createPlugin.ts deleted file mode 100644 index e044a9f1..00000000 --- a/types/createPlugin.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { - FastifyPluginCallback, - FastifyPluginAsync, - FastifyPlugin, - ApplyDependencies, - UnEncapsulatedPlugin, - FastifyDependencies, -} from 'fastify' - -export function createPlugin< - TPlugin extends FastifyPluginCallback, - TDependencies extends FastifyDependencies, - TEnhanced extends ApplyDependencies = ApplyDependencies -> (plugin: TEnhanced, options?: { dependencies?: TDependencies }): UnEncapsulatedPlugin -export function createPlugin< - TPlugin extends FastifyPluginAsync, - TDependencies extends FastifyDependencies, - TEnhanced extends ApplyDependencies = ApplyDependencies -> (plugin: TEnhanced, options?: { dependencies?: TDependencies }): UnEncapsulatedPlugin -export function createPlugin< - TPlugin extends FastifyPlugin, - TDependencies extends FastifyDependencies, - TEnhanced extends ApplyDependencies = ApplyDependencies -> (plugin: TEnhanced, options?: { dependencies?: TDependencies }): UnEncapsulatedPlugin { - return plugin as UnEncapsulatedPlugin -} diff --git a/types/index.test-d.ts b/types/index.test-d.ts index 9d65372b..d53493d2 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -9,7 +9,7 @@ import fastifyStatic, { FastifyStaticPluginDecorators } from '..' // TODO: remove after we land in fastify-plugin -import { createPlugin } from './createPlugin' +import { createPlugin } from 'fastify-plugin' import fastifyStaticCjsImport = require('..') const fastifyStaticCjs = require('..')