fastify / fastify-plugin

Plugin helper for Fastify
MIT License
197 stars 42 forks source link

fn invalid parameters after 4.5.1 update #220

Closed mellinas314 closed 1 year ago

mellinas314 commented 1 year ago

Prerequisites

Fastify version

4.20.0

Plugin version

4.5.1

Node.js version

20

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

13.3

Description

After updating plugin to version 4.5.1, my previously existing project has stopped to work with the following error:

Argument of type '(server: FastifyInstance, _: FastifyPluginOptions, done: (err?: Error | undefined) => void) => Promise<void>' is not assignable to parameter of type 'FastifyPluginAsync<FastifyPluginOptions, RawServerDefault, FastifyTypeProviderDefault, FastifyBaseLogger>'.

I've been loking for some update where this change is described and how to update my code to make it works, but can't find anything (downgrading to version 4.5.0, it works again with no problem), but I can't find what I need to change in my call to fp() to make it works with new version.

Steps to Reproduce

After update to fastify-plugin 4.5.1, just try to call fp() with previous working parameters, like:

 fp(async (server: FastifyInstance, opts: FastifyPluginOptions, done: (err?: Error | undefined) => void)  => {
    ........
    done();
});

and it will return following error:

Argument of type '(server: FastifyInstance, opts: FastifyPluginOptions, done: (err?: Error | undefined) => void) => Promise<void>' is not assignable to parameter of type 'FastifyPluginAsync<FastifyPluginOptions, RawServerDefault, FastifyTypeProviderDefault, FastifyBaseLogger>'.

Expected Behavior

To keep working as previous versions.

Uzlopak commented 1 year ago

You mixed async with callback style. So the typescript compilation error is thrown correctly.

Either use callback style and remove the async or use async and remove the done parameter and its use.

mellinas314 commented 1 year ago

You mixed async with callback style. So the typescript compilation error is thrown correctly.

Either use callback style and remove the async or use async and remove the done parameter and its use.

Absolutely right, thanks for the fast reply! As it was working previously and I was not fully understanding the error message, I open this issue. Sorry for the confusion; i close it as it was my fault :)

Thanks!

Uzlopak commented 1 year ago

Dont worry. I am actually happy for this feedback, as it shows that the changes made for 4.5.1 are working as expected. ;)

lightify97 commented 11 months ago

In the following code I'm not using the async function but still getting the same error:

"use strict";

import { FastifyInstance, FastifyPluginOptions } from "fastify";
import fp from "fastify-plugin";
import { Redis, ReplyError } from "ioredis";

function fastifyKeydbPlugin(
    fastify: FastifyInstance,
    options: FastifyPluginOptions,
    next: Function
) {
    const { namespace, url, closeClient = false, ...redisOptions } = options;

    let client = options.client || null;

    if (namespace) {
        if (!fastify.keydb) {
            fastify.decorate("keydb", Object.create(null));
        }

        if (fastify.keydb[namespace]) {
            return next(
                new Error(
                    `Redis '${namespace}' instance namespace has already been registered`
                )
            );
        }

        const closeNamedInstance = (fastify: FastifyInstance) => {
            return fastify.keydb[namespace].quit();
        };

        if (client) {
            if (closeClient === true) {
                fastify.addHook("onClose", closeNamedInstance);
            }
        } else {
            try {
                if (url) {
                    client = new Redis(url, redisOptions);
                } else {
                    client = new Redis(redisOptions);
                }
            } catch (err) {
                return next(err);
            }

            fastify.addHook("onClose", closeNamedInstance);
        }

        fastify.keydb[namespace] = client;
    } else {
        if (fastify.keydb) {
            return next(new Error("Keydb has already been registered"));
        } else {
            if (client) {
                if (closeClient === true) {
                    fastify.addHook("onClose", close);
                }
            } else {
                try {
                    if (url) {
                        client = new Redis(url, redisOptions);
                    } else {
                        client = new Redis(redisOptions);
                    }
                } catch (err) {
                    return next(err);
                }

                fastify.addHook("onClose", close);
            }

            fastify.decorate("keydb", client);
        }
    }

    // Testing this make the process crash on latest TAP :(
    /* istanbul ignore next */
    const onEnd = function (err: any) {
        client
            .off("ready", onReady)
            .off("error", onError)
            .off("end", onEnd)
            .quit();

        next(err);
    };

    const onReady = function () {
        client.off("end", onEnd).off("error", onError).off("ready", onReady);

        next();
    };

    // Testing this make the process crash on latest TAP :(
    /* istanbul ignore next */
    const onError = function (err: { code: string }) {
        if (err.code === "ENOTFOUND") {
            onEnd(err);
            return;
        }

        // Swallow network errors to allow ioredis
        // to perform reconnection and emit 'end'
        // event if reconnection eventually
        // fails.
        // Any other errors during startup will
        // trigger the 'end' event.
        if (err instanceof ReplyError) {
            onEnd(err);
        }
    };

    // ioredis provides it in a .status property
    if (client.status === "ready") {
        // client is already connected, do not register event handlers
        // call next() directly to avoid ERR_AVVIO_PLUGIN_TIMEOUT
        next();
    } else {
        // ready event can still be emitted
        client.on("end", onEnd).on("error", onError).on("ready", onReady);

        client.ping();
    }
}

function close(fastify: FastifyInstance) {
    return fastify.keydb.quit();
}

const fastifyKeydb = fp(fastifyKeydbPlugin, {
    fastify: "4.x",
    name: "@fastify/redis",
});

export default fastifyKeydb;

This is the error I'm getting.

error TS2345: Argument of type '(fastify: FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>, options: FastifyPluginOptions, next: Function) => any' is not assignable to parameter of type 'FastifyPluginAsync<FastifyPluginOptions, RawServerDefault, FastifyTypeProviderDefault, FastifyBaseLogger>'.
  Target signature provides too few arguments. Expected 3 or more, but got 2.

132 const fastifyKeydb = fp(fastifyKeydbPlugin, {
Eomm commented 11 months ago

@lightify97 I think your issue is due the return next(err);, try this instead:

next(err);
return

If it does not work, please open a new issue with a Minimal, Reproducible Example