You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ctx in queries is often being used as inputs when some are defined in the middlewares.
This is not taken in account with experimental app dir support, as the cacheTag only caches the inputs, but never the context.
Therefore, I am suffering a bug when a query that just uses ctx to retrieve user-specific data from ctx.session, is being cached with no inputs [], and I am able to see the cached data of another user.
Introduction
Experimental tRPC's NextJS AppRouter layout support involves caching of query inputs, and is implemented in the next way:
While it works for most of the cases, problems arise when your query logic depends on trpc's middlewares.
Here's an example implementation of a protected procedure taken from the tRPC's documentation:
import{initTRPC,TRPCError}from'@trpc/server';exportconstt=initTRPC.context<Context>().create();// you can reuse this for any procedureexportconstprotectedProcedure=t.procedure.use(asyncfunctionisAuthed(opts,){const{ ctx }=opts;// `ctx.user` is nullableif(!ctx.user){// ^?thrownewTRPCError({code: 'UNAUTHORIZED'});}returnopts.next({ctx: {// ✅ user value is known to be non-null nowuser: ctx.user,// ^?},});});t.router({// this is accessible for everyonehello: t.procedure.input(z.string().nullish()).query((opts)=>`hello ${opts.input??opts.ctx.user?.name??'world'}`),admin: t.router({// this is accessible only to adminssecret: protectedProcedure.query((opts)=>{return{secret: 'sauce',};}),}),});
As you can see, the ctx.user?.name in this example is implicitly becoming an input, because you use it in the query implementation, yet it's not being included in the cacheKey!
In this particular case, which is taken from the docs, the consequence is that the first user querying the hello query, would make it cache the response hello alice (i.e), then when the second user queries the same procedure (bob i.e.), he would see hello alice as it was cached with a cacheKey of [] as inputs to the functions simply don't exist.
Describe the solution you'd like to see
contextCache or similar to be implemented in the options of experimental_nextCacheLink to specify which fields from the context should be cached, to still make use of caching.
This would also involve changing the way the cacheTag is generated. Specifically, it would need to have the cachedContextValues (or similar) as input, to pass the values that should be cached.
Also, due to the nature of NextJS caching, the cacheTag should not be longer than 256 characters, therefore the cacheTag should rely on a hash of all inputs, instead of passing the stringified data.
This change allows a user to specify `contextCache` method in the
`experimental_nextCacheLink`, which lets one select the values
from the context that should be considered when a `cacheTag` is
generated.
It also changes the way `cacheTag` is generated, taking care of
the fact that the `cacheTag` cannot be longer then 256 characters,
thus instead of stringifying input values, it will form a sha-256 hash
of those.
Implements trpc#5455
Describe the feature you'd like to request
TLDR
ctx
in queries is often being used as inputs when some are defined in the middlewares.This is not taken in account with experimental app dir support, as the
cacheTag
only caches the inputs, but never the context.Therefore, I am suffering a bug when a query that just uses
ctx
to retrieve user-specific data fromctx.session
, is being cached with no inputs[]
, and I am able to see the cached data of another user.Introduction
Experimental tRPC's NextJS AppRouter layout support involves caching of query inputs, and is implemented in the next way:
trpc/packages/next/src/app-dir/links/nextCache.ts
Lines 34 to 43 in b72c7aa
Problem
While it works for most of the cases, problems arise when your query logic depends on trpc's
middleware
s.Here's an example implementation of a protected procedure taken from the tRPC's documentation:
As you can see, the
ctx.user?.name
in this example is implicitly becoming an input, because you use it in the query implementation, yet it's not being included in thecacheKey
!In this particular case, which is taken from the docs, the consequence is that the first user querying the
hello
query, would make it cache the responsehello alice
(i.e), then when the second user queries the same procedure (bob i.e.), he would seehello alice
as it was cached with acacheKey
of[]
as inputs to the functions simply don't exist.Describe the solution you'd like to see
contextCache
or similar to be implemented in the options ofexperimental_nextCacheLink
to specify which fields from the context should be cached, to still make use of caching.This would also involve changing the way the
cacheTag
is generated. Specifically, it would need to have thecachedContextValues
(or similar) as input, to pass the values that should be cached.Also, due to the nature of NextJS caching, the
cacheTag
should not be longer than 256 characters, therefore thecacheTag
should rely on a hash of all inputs, instead of passing the stringified data.A hacky patch is implemented at #5447
Describe alternate solutions
Additional information
Discussions ref: #5447
👨👧👦 Contributing
Funding
The text was updated successfully, but these errors were encountered: