kleydon / prisma-session-store

Express session store for Prisma
MIT License
116 stars 18 forks source link

Incompatible instance typing while assigning to express-session's store #105

Open rahadi23 opened 1 year ago

rahadi23 commented 1 year ago

Got an incompatible instance typing while assigning to express-session's store with the 3.1.10 release as follows:

src/main.ts:48:7 - error TS2740: Type 'PrismaSessionStore<"session">' is missing the following properties from type 'Store': regenerate, load, createSession, addListener, and 14 more.

48       store: new PrismaSessionStore(prismaService, {
         ~~~~~

  node_modules/@types/express-session/index.d.ts:94:9
    94         store?: Store | undefined;
               ~~~~~
    The expected type comes from property 'store' which is declared here on type 'SessionOptions'

src/main.ts:

app.use(
  expressSession({
    secret: 'very-confidential-secret',
    resave: false,
    saveUninitialized: false,
    store: new PrismaSessionStore(prismaService, {
      checkPeriod: 2 * 60 * 1000, //ms
      dbRecordIdIsSessionId: true,
      dbRecordIdFunction: undefined,
    }),
  })
);

package.json:

{
  "dependencies": {
    "@quixo3/prisma-session-store": "^3.1.9",
    "express-session": "^1.17.3",
  }
}

These configurations work just fine before with the 3.1.9 release. Is there anything needs to be done or are there any migration steps should be followed in order to make it works with the latest release?

kleydon commented 1 year ago

Hi @rahadi23 - Sorry for the late reply, here.

Is prismaService an instance of PrismaClient? E.g, new PrismaClient(), or prisma imported from context.ts (if you're doing something similar to Prisma's examples on github?)

rahadi23 commented 1 year ago

Hi @kleydon - thank you for the reply.

Sorry for the lack of context. prismaService I used here is a result of extending PrismaClient, since I use NestJS. It is exactly the same as explained here.

Again, this only happen when I upgrade to 3.1.10 (works flawlessly with 3.1.9 with the exactly the same configuration).

kleydon commented 1 year ago

Hmmm... Not sure what is going on.

Here's the diff between 3.1.10 and 3.1.9 on GitHub, in case that helps get to the bottom of this.

In prisma-session-store (v3.1.9 and v3.1.10), the class definition begins with:

`export class PrismaSessionStore<M extends string = 'session'> extends Store`, 

...where Store (imported from express-session) includes all the properties that the error message above suggests are not included (e.g. regenerate, load, createSession, addListener). PrismaSessionStore's constructor (for both v3.1.9 and v3.1.10) doesn't remove or alter these properties, so they should still be included.

Is it possible that in your testing, the version of express-session is changing with the version of prisma-session-store? (If express-session's Store were changing - this might account for the error message...)

Alternatively: Perhaps although there is an error, the error message is misleading - and the issue is really something else?

Another thought: In v3.1.10, two new properties were added to PrismaSessionStore: isSetting and isTouching (see diff above). Maybe typescript is for some reason complaining about this change? One way to quickly test - instead of using:

store: new PrismaSessionStore(...)

You could try:

let altStore = new PrismaSessionStore()
//Remove the recently added properties for testing
delete altStore.isSetting
delete altStore.isTouching
...
store: altStore

This wouldn't work as a final solution - but perhaps it could help with narrowing down whether or not the problem has to do the addition of these two new properties or not?

Also - if you could post a buildable minimal reproduction of what you are seeing, so others could build it and experience the issue directly, this might make it easier for people to debug this in parallel... My time over the near term is a bit limited, but - hopefully this will get solved! I suspect you aren't the only one using this lib with Prisma with NestJS - seems like a really useful/powerful web stack to me.

owensj-basis commented 1 year ago

I'm getting a similar error, this is my setup:

app.use(session({
  secret: 'this-should-be-very-random',
  resave: true,
  saveUninitialized: false,
  store: new PrismaSessionStore(
    new PrismaClient(),
    {
      checkPeriod: 2 * 60 * 1000,  //ms
      dbRecordIdIsSessionId: true,
      dbRecordIdFunction: undefined,
    }
  )
}));

and TypeScript is throwing this error:

Argument of type 'PrismaClient<PrismaClientOptions, never, RejectOnNotFound | RejectPerOperation | undefined>' is not assignable to parameter of type 'IPrisma<"session">'.

  Property 'session' is missing in type 'PrismaClient<PrismaClientOptions, never, RejectOnNotFound | RejectPerOperation | undefined>' but required in type 'Record<"session", { create(args: ICreateArgs): Promise<IPrismaSession>; delete(args: IDeleteArgs): Promise<IPrismaSession>; deleteMany(args?: unknown): Promise<...>; findMany(args?: IFindManyArgs | undefined): Promise<...>; findUnique(args: IFindUniqueArgs): Promise<...>; update(args: IUpdateArgs): Promise<...>; }>'.ts(2345)
kleydon commented 1 year ago

@owensj-basis - thanks for the report.

Any chance you might be willing to post a minimal reproduction and link to it here, so its easier to problem-solve?

PhillJK commented 1 year ago

@owensj-basis I'm facing exactly the same problem. For now, I have fixed it by casting PrismaClient to any. It's not the solution, and I wished I could help, but I'm not particularly good with Typescript.

kleydon commented 1 year ago

Thanks @PhillJK & @owensj-basis!

It is people "weighing in" as they can that enables open source projects like these to keep moving forward.

Any typescript aficionados out there who rely on this library up for taking a look at this?

Thanks,

-K

owensj-basis commented 1 year ago

@owensj-basis I'm facing exactly the same problem. For now, I have fixed it by casting PrismaClient to any. It's not the solution, and I wished I could help, but I'm not particularly good with Typescript.

This was my workaround as well

@kleydon I'll see if I can get a minimal reproduction in a separate repo and post if successful

kleydon commented 1 year ago

@owensj-basis Appreciate it!

(Hope you don't feel obliged; I'm just trying to "lean on" the whole community that uses this lib, to distribute the workload a bit... :)

IonVillarreal commented 1 year ago

Hi, I have the same problem with NestJS, any news?

kleydon commented 1 year ago

@IonVillarreal, not yet; I've not used NestJS, myself thusfar. PR's welcome!

andremarcondesteixeira commented 1 year ago

I'm having the same issue. The only solution I found was to actually stop using the lib and implement the store myself :( Note: I am using Prisma version 4.x

kleydon commented 1 year ago

Hi @andremarcondesteixeira, sorry this lib has been less than helpful for you, at least so far. Curious: If you happen to be using VSCode, and you hover over your own session store implementation, what is the typing that you see for it? (Just wondering if this info might yield clues that suggest a fix for NestJS users...)

IonVillarreal commented 1 year ago

For now, for NestJS, I'm using connect-pg-simple

with a similar setup:

app.use(
    session({
      secret: configService.get('SESSION_SECRET') || '',
      resave: false,
      saveUninitialized: false,
      rolling: true,
      name: 'base.sid',
      cookie: {
        maxAge: 30 * 60 * 1000,
        httpOnly: true,
      },
      store: new (connectPgSimple(session))({
        createTableIfMissing: true,
        schemaName: 'project',
      }),
    })
  )
olalonde commented 1 year ago
Screen Shot 2023-02-28 at 1 15 05 AM

Also getting weird type errors in my editor.

kleydon commented 1 year ago

Hi @olalonde, For context, are you using NestJs? What version of Express / Express Session are you seeing this with? Thanks for posting, -K

olalonde commented 1 year ago

Using Express v5

    "express": "^5.0.0-beta.1",
    "@types/express": "^4.17.17",
    "express-session": "^1.17.3",
    "@types/express-session": "^1.17.6",
ShriPunta commented 11 months ago

Hi @kleydon , Thank you for taking out time to build this library and making it open source! You are saving tons of time for others! I am facing the same issue as above, and I have a very simple REST API with express and express-session. The TS issue goes away by using as any

image

I have followed this code snippet (thanks to @ansemjo) https://github.com/prisma/prisma/issues/10306#issuecomment-1476328622

My session.ts file

import Session from 'express-session';
import { PrismaSessionStore } from "@quixo3/prisma-session-store";
import prisma from '../lib/prisma';
import { SECRETS } from './settings';
// return a session middleware for express
export function getSessionConfig() {
    return Session({
        name: "sfwtid", // name of the cookie
        cookie: {
            maxAge: 7 * 24 * 60 * 60 * 1000, // ms, 7 days
            sameSite: "strict",
            secure: "auto",
        },
        secret: SECRETS.expressSessionSecret!,
        resave: false,
        saveUninitialized: false,
        unset: "destroy",
        store: new PrismaSessionStore(prisma as any, {
            checkPeriod: 10 * 60 * 1000, // ms, 10 minutes
            dbRecordIdIsSessionId: true,
            dbRecordIdFunction: undefined,
        }),
    });
}

My prisma.ts file

import { PrismaClient } from "@prisma/client";
const globalForPrisma = global as unknown as { prisma: PrismaClient };
export const prisma = globalForPrisma.prisma || new PrismaClient();
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
export default prisma;
kleydon commented 11 months ago

Hi Shridhar,

I'm traveling, but will check this out when I can - probably early next week.

Thanks for posting this!

-Krispin

On Jun 18, 2023, at 10:54 AM, Shridhar Puntambekar @.***> wrote:

 Hi @kleydon , Thank you for taking out time to build this library and making it open source! You are saving tons of time for others! I am facing the same issue as above, and I have a very simple REST API with express and express-session. The TS issue goes away by using as any

I have followed this code snippet (thanks to @ansemjo) prisma/prisma#10306 (comment)

My session.ts file

import Session from 'express-session'; import { PrismaSessionStore } from @.**/prisma-session-store"; import prisma from '../lib/prisma'; import { SECRETS } from './settings'; // return a session middleware for express export function getSessionConfig() { return Session({ name: "sfwtid", // name of the cookie cookie: { maxAge: 7 24 60 60 1000, // ms, 7 days sameSite: "strict", secure: "auto", }, secret: SECRETS.expressSessionSecret!, resave: false, saveUninitialized: false, unset: "destroy", store: new PrismaSessionStore(prisma as any, { checkPeriod: 10 60 * 1000, // ms, 10 minutes dbRecordIdIsSessionId: true, dbRecordIdFunction: undefined, }), }); } My prisma.ts file

import { PrismaClient } from @.***/client"; const globalForPrisma = global as unknown as { prisma: PrismaClient }; export const prisma = globalForPrisma.prisma || new PrismaClient(); if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma; export default prisma; — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.

kleydon commented 10 months ago

@ShriPunta

I've just tried the code above (changing ../lib/prisma to ./prisma, to point to prisma.ts in my test project), and I'm able to compile & run (with no vs code errors) without including as any.

jcbdev commented 7 months ago

I only have the issue with the typing error and "session" when the schema is missing the "Session" type or the client has not been generated properly npx prisma generate.

Anyone having this issue I would check the generated "PrismaClient" from the node_modules folder (or wherever you put it) has the the "session" property from the Session model.

all of your models should be a property on the client

const prisma = new PrismaClient();
prisma.session.findOne();
prisma.myOtherType.findAll();

Of course check this is in your schema

model Session {
  id        String   @id
  sid       String   @unique
  data      String
  expiresAt DateTime
}