#Error with Fastify instance and session types

35 messages · Page 1 of 1 (latest)

covert estuary
#

When I try to use Fastify with Nest, I get a type compatibility error

#

Code:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ConfigService } from '@nestjs/config';
import { VersioningType } from '@nestjs/common';
import {
  FastifyAdapter,
  NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { FastifyInstance } from 'fastify';
import secureSession from '@fastify/secure-session';
import * as passport from 'passport';

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
  );
  const fastifyInstance: FastifyInstance = app.getHttpAdapter().getInstance();
  fastifyInstance
    .addHook('onRequest', async (req, res) => {
      req.socket['encrypted'] = process.env.NODE_ENV === 'production';
      res.header('X-Powered-By', 'CyberSecurity');
    })
    .decorateReply('setHeader', function (name: string, value: unknown) {
      this.header(name, value);
    })
    .decorateReply('end', function () {
      this.send('');
    });
  const configService = app.get(ConfigService);
  const port = configService.get<string>('PORT', '');

  // Throttler - Protection
  app.enableCors({
    origin: '*',
    methods: 'GET, HEAD, PUT, PATCH, POST, DELETE',
    allowedHeaders: 'Content-Type, Authorization',
    credentials: true,
  });

  app.enableVersioning({
    type: VersioningType.URI,
    defaultVersion: '1',
  });

  await app.register(secureSession, {
    sessionName: configService.get<string>('SESSION_NAME', ''),
    cookieName: configService.get<string>('SESSION_COOKIE', ''),
    expiry: configService.get<string>('SESSION_EXPIRATION_TIME', ''),
    cookie: {
      path: '/',
    },
    secret: configService.get<string>('SESSION_SECRET', ''),
    salt: configService.get<string>('SESSION_SALT', ''),
  });

  app.use(passport.initialize());
  app.use(passport.session());

  await app.listen(port);
}
bootstrap();
#

Error:

src/main.ts:18:9 - error TS2740: Type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>' is missing the following properties from type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>': serializeCookie, parseCookie, createSecureSession, decodeSecureSession, and 3 more.

18   const fastifyInstance: FastifyInstance = app.getHttpAdapter().getInstance();
           ~~~~~~~~~~~~~~~
src/main.ts:57:22 - error TS2345: Argument of type 'FastifySecureSession' is not assignable to parameter of type 'FastifyPluginCallback<SecureSessionPluginOptions | (SecureSessionPluginOptions & Required<Pick<SecureSessionPluginOptions, "sessionName">>)[]> | FastifyPluginAsync<...> | Promise<...> | Promise<...>'.
  Type 'FastifySecureSession' is not assignable to type 'FastifyPluginCallback<SecureSessionPluginOptions | (SecureSessionPluginOptions & Required<Pick<SecureSessionPluginOptions, "sessionName">>)[]>'.       
    Types of parameters 'instance' and 'instance' are incompatible.
      Type 'import("H:/xampp/htdocs/devdj/sso/node-sso/server/node_modules/@nestjs/platform-fastify/node_modules/fastify/types/instance").FastifyInstance<import("H:/xampp/htdocs/devdj/sso/node-sso/server/node_modules/@nestjs/platform-fastify/node_modules/fastify/types/utils").RawServerDefault, import("http").IncomingMessage, im...' is not assignable to type 'import("H:/xampp/htdocs/devdj/sso/node-sso/server/node_modules/fastify/types/instance").FastifyInstance<import("H:/xampp/htdocs/devdj/sso/node-sso/server/node_modules/fastify/types/utils").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, import("H:/xamp...'.

57   await app.register(secureSession, {
#

Node Packages:

"dependencies": {
    "@fastify/secure-session": "^7.5.1",
    "@nestjs/class-validator": "^0.13.4",
    "@nestjs/common": "^10.3.9",
    "@nestjs/config": "^3.2.2",
    "@nestjs/core": "^10.3.9",
    "@nestjs/jwt": "^10.2.0",
    "@nestjs/passport": "^10.0.3",
    "@nestjs/platform-express": "^10.3.9",
    "@nestjs/platform-fastify": "^10.3.9",
    "@nestjs/typeorm": "^10.0.2",
    "@types/bcrypt": "^5.0.2",
    "bcrypt": "^5.1.1",
    "fastify": "^4.28.0",
    "joi": "^17.13.3",
    "passport": "^0.7.0",
    "passport-local": "^1.0.0",
    "pg": "^8.12.0",
    "reflect-metadata": "^0.1.13",
    "rxjs": "^7.2.0",
    "typeorm": "^0.3.20"
  },
  "devDependencies": {
    "@nestjs/cli": "^10.3.2",
    "@nestjs/schematics": "^10.1.1",
    "@nestjs/testing": "^10.3.9",
    "@types/express": "^4.17.13",
    "@types/jest": "29.5.1",
    "@types/node": "18.16.12",
    "@types/passport": "^1.0.16",
    "@types/supertest": "^2.0.11",
    "@typescript-eslint/eslint-plugin": "^5.0.0",
    "@typescript-eslint/parser": "^5.0.0",
    "eslint": "^8.0.1",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-prettier": "^4.0.0",
    "jest": "29.5.0",
    "prettier": "^2.3.2",
    "source-map-support": "^0.5.20",
    "supertest": "^6.1.3",
    "ts-jest": "29.1.0",
    "ts-loader": "^9.2.3",
    "ts-node": "^10.0.0",
    "tsconfig-paths": "4.2.0",
    "typescript": "^5.0.0"
  },
covert estuary
#

Config

# Session - Config
SESSION_NAME = "auth-session"
SESSION_COOKIE = "auth-sid"
SESSION_EXPIRATION_TIME = 90 * 24 * 60 * 60 # 90 days
SESSION_SECRET = ""
SESSION_SALT = ""

App Module:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TypeOrmConfigService } from './config/typeorm.config';
import { join } from 'path';
import { envSchema } from './config/env.schema';
import { PassportModule } from '@nestjs/passport';
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      ignoreEnvFile: !!process.env.CI,
      envFilePath: join(__dirname, '..', '.env'),
      validationSchema: envSchema,
    }),
    TypeOrmModule.forRootAsync({
      useClass: TypeOrmConfigService,
    }),
    PassportModule.registerAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => ({
        defaultStrategy: configService.get('jwt.defaultStrategy'),
      }),
    }),
    AuthModule,
    UsersModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
gentle horizon
#

can't you drop the explicit type for that variable fastifyInstance?

#

I do managed to reproduce the same error here but I wondering if it's expected or not..

#

I guess you can see the reason on this by running npm ls fastify
You'll probably see 2 versions of fastify instead of one, which may lead to such type incompatibility errors as each interface has come from different versions of fastify

covert estuary
gentle horizon
#

I'll open a new issue tomorrow to suggest a minor improvement that should allow you to use the latest version of fastify with no worries

covert estuary
#

Any updates?

gentle horizon
covert estuary
#

So, the only solution is to use an older version of Fastify or remove the types?

covert estuary
# gentle horizon https://github.com/nestjs/nest/issues/13720#issuecomment-2199494358

I see that the version in the adapter has been changed to 28.0. I installed it, but it still doesn't solve the problem. If I understand correctly, all types, even those for the request, should be imported from Fastify and not from @nestjs/common. So why don't you make it so that the types are provided by your package instead of requiring an additional installation of Fastify for the types? Since @nestjs/platform-fastify includes Fastify, you could export the types so they are available globally.

gentle horizon
gentle horizon
#

It’s just a matter of having the exact same module. So run npm ls fastity and see if all of occurrences are dedup

covert estuary
#

I have the same version, and the type error still occurs.

gentle horizon
#

that's why then

covert estuary
#

But package @nestjs/platform-fastify uses version 4.28.0

gentle horizon
#

that will only work when you have the exact the same version, as I said

#

I'd suggest you to pin fastify's version
but you'll have to make it in sync with the version from @nestjs/platform-fastify

#

so I guess the best approach would be removing fastify from your hard deps

covert estuary
#

But that's the version I have installed, 4.28.0, because that's what I have in my package.json.

gentle horizon
#

looks like you don't know how semver ranges works

stoic helmBOT
#

This post has been marked as resolved. :white_check_mark:
Please read through the conversation and resolution, if you are having the same issue. If you were the original author of the post and the issue is still fresh (within a few days) and you are still have having trouble, continue to reply here. If you are not the original author of the post or the post has aged, start a new thread linking this one as relevant to your problem, providing as much additional information as possible.

covert estuary
#

Thanks, it works, but if I uninstall Fastify, I won't be able to use the types for the request.

covert estuary
gentle horizon
#

but you can

#

fasitfy is a hard dep of @nestjs/platform-fastify

#

I know that this is not the best DX but it's a way to awalys use the right version of fastify