elysia icon indicating copy to clipboard operation
elysia copied to clipboard

Types for JWT plugin are not propagated correctly

Open l2ysho opened this issue 1 year ago • 11 comments

It seems my jwtFunc is correctly propagated only to directly chained request handlers, not to plugins or functional callbacks. Is this issue or there is another way how to have correct typing if handlers are in separe files?

const JWTMiddleware = jwt({
  name: 'jwtFunc',
  secret: 'password',
})

/*
* Property 'jwtFunc' does not exist on type '{ body: unknown; query: Record<string, string | null>; params: Record<"name",
* string>; headers: Record<string, string | null>; cookie: Record<string, Cookie<any>>; set: { ...; }; path: string; request:
* Request; store: {}; }'.
*/

const plugin = new Elysia().get('/sign/:name', ({ jwtFunc, params }) =>
  jwtFunc.sign(params)
)

/*
* Property 'jwtFunc' does not exist on type '{ body: unknown; query: Record<string, string | null>; params: Record<"name",
* string>; headers: Record<string, string | null>; cookie: Record<string, Cookie<any>>; set: { ...; }; path: string; request:
* Request; store: {}; }'.
*/

export const functionalCallback = (app: Elysia) =>
  app.get('/sign/:name', ({ jwtFunc, params }) => jwtFunc.sign(params))

const app = new Elysia()
  .use(JWTMiddleware)
  .use(cookie())
  .use(swagger())
  .use(plugin)
  .use(functionalCallback)
  .get('/sign/:name', ({ jwtFunc, params }) => jwtFunc.sign(params)) // this is OK

l2ysho avatar Sep 24 '23 17:09 l2ysho

I'm also getting the same error

sagnax avatar Sep 25 '23 03:09 sagnax

I got the same issue.

kingstonbg avatar Sep 28 '23 08:09 kingstonbg

Same issue here, the example actually raises a TS error on 'jwt' at .get('/sign/:name', async ({ jwt, cookie, setCookie, params }) =>

adicco avatar Sep 28 '23 16:09 adicco

any updates on this yet guys?

hamidabdulmalik avatar Oct 01 '23 00:10 hamidabdulmalik

I think this might be what you're looking for, Dependency Injection

sokhengpory avatar Oct 08 '23 12:10 sokhengpory

A temporary fix is to downgrade Elysia to 0.7.15, seems it got broken in 0.7.16

"dependencies": {
		"@elysiajs/cookie": "^0.7.0",
		"@elysiajs/jwt": "^0.7.0",
		"elysia": "0.7.15"
	}

This works for me

lvlingxiao1 avatar Oct 15 '23 20:10 lvlingxiao1

Same as well with me. Help Salty!!!

mateusavila avatar Oct 26 '23 02:10 mateusavila

It happens to me too but I get why its hard to infer:

You create detached middlewares/plugins/derivations(decide on the name already lol) but the plugin itself is registered on some root app instance.

So the root app is quite aware of the plugins it passes to its context, however, the standalone functions aren't because there's no guarantee for them to be executed in this context, or at least - there's no way to type this kind of guaranty AFAIK.

silicakes avatar Nov 11 '23 15:11 silicakes

This is because the way that Elysia builds type. I had this problem too. The way that i found to fix that is using one root app and set all my functionalities there and export the type of the app, like this:

// server.ts
export const app = new Elysia({ cookie: { secrets: Bun.env.JWT_SECRET } })
    .use(
        jwt({
            name: 'jwt',
            secret: Bun.env.JWT_SECRET || 'super_secret',
            exp: '2d',
        })
    );
    
export type AppType = typeof app;

And in other files, you could use the exported type to type the new Elysia object:

import { AppType } from '@server';
import Elysia from 'elysia';

const plugin: AppType = new Elysia();
plugin.get('/sign/:name', ({ jwt, params }) => jwt.sign(params)); // <-- No type errors here + all infered type features

gabbrieu avatar Nov 16 '23 00:11 gabbrieu

update elysia ^0.7.0 -> ^0.8.0.

ghost avatar Dec 24 '23 05:12 ghost

It seems my jwtFunc is correctly propagated only to directly chained request handlers, not to plugins or functional callbacks. Is this issue or there is another way how to have correct typing if handlers are in separe files?

const JWTMiddleware = jwt({
  name: 'jwtFunc',
  secret: 'password',
})

/*
* Property 'jwtFunc' does not exist on type '{ body: unknown; query: Record<string, string | null>; params: Record<"name",
* string>; headers: Record<string, string | null>; cookie: Record<string, Cookie<any>>; set: { ...; }; path: string; request:
* Request; store: {}; }'.
*/

const plugin = new Elysia().get('/sign/:name', ({ jwtFunc, params }) =>
  jwtFunc.sign(params)
)

/*
* Property 'jwtFunc' does not exist on type '{ body: unknown; query: Record<string, string | null>; params: Record<"name",
* string>; headers: Record<string, string | null>; cookie: Record<string, Cookie<any>>; set: { ...; }; path: string; request:
* Request; store: {}; }'.
*/

export const functionalCallback = (app: Elysia) =>
  app.get('/sign/:name', ({ jwtFunc, params }) => jwtFunc.sign(params))

const app = new Elysia()
  .use(JWTMiddleware)
  .use(cookie())
  .use(swagger())
  .use(plugin)
  .use(functionalCallback)
  .get('/sign/:name', ({ jwtFunc, params }) => jwtFunc.sign(params)) // this is OK

See example in Documentation - Plugin#service-locator

kravetsone avatar Mar 18 '24 16:03 kravetsone

It seems my jwtFunc is correctly propagated only to directly chained request handlers, not to plugins or functional callbacks. Is this issue or there is another way how to have correct typing if handlers are in separe files?

const JWTMiddleware = jwt({
  name: 'jwtFunc',
  secret: 'password',
})

/*
* Property 'jwtFunc' does not exist on type '{ body: unknown; query: Record<string, string | null>; params: Record<"name",
* string>; headers: Record<string, string | null>; cookie: Record<string, Cookie<any>>; set: { ...; }; path: string; request:
* Request; store: {}; }'.
*/

const plugin = new Elysia().get('/sign/:name', ({ jwtFunc, params }) =>
  jwtFunc.sign(params)
)

/*
* Property 'jwtFunc' does not exist on type '{ body: unknown; query: Record<string, string | null>; params: Record<"name",
* string>; headers: Record<string, string | null>; cookie: Record<string, Cookie<any>>; set: { ...; }; path: string; request:
* Request; store: {}; }'.
*/

export const functionalCallback = (app: Elysia) =>
  app.get('/sign/:name', ({ jwtFunc, params }) => jwtFunc.sign(params))

const app = new Elysia()
  .use(JWTMiddleware)
  .use(cookie())
  .use(swagger())
  .use(plugin)
  .use(functionalCallback)
  .get('/sign/:name', ({ jwtFunc, params }) => jwtFunc.sign(params)) // this is OK

See example in Documentation - Plugin#service-locator

Close as unable to reproduce on my end, either it was fixed in previous subsequent version and service locator pattern.

Feels free to open a new issue referencing this one if the problem still persists.

SaltyAom avatar Aug 30 '24 11:08 SaltyAom