S
SolidJS4mo ago
NitonFx

"use server"; RPC calls cannot access global objects

I dont have a reproduction rn because stackblitz has no solid start option :/ basically i have a global Map<K,V> (export const mymap = ...)and values are inserted using a server route /api/login.ts and on SSR the value from the map is read correctly. But when i have a server rpc call the map appears empty
const someServerSideFunction = async ()=>{
"use server";
return Promise.resolve(mymap.get("abc"));
}
const someServerSideFunction = async ()=>{
"use server";
return Promise.resolve(mymap.get("abc"));
}
I ensured that the map is filled/empty by printint it out with JSON.stringify and console.log. Are these running somewhat in isolation? I printed the stacktrace for both calls and they seem very simmilar!
14 Replies
Madaxen86
Madaxen864mo ago
This is the latest solid-start stackblitz https://start.solidjs.com/ https://start.solid.new/
SolidStart
SolidStart: Fine-Grained Reactivity goes fullstack
SolidStart is a JavaScript Framework designed to build SolidJS apps and deploy them to a variety of providers.
StackBlitz
Solid-start With Tailwindcss Example - StackBlitz
Run official live example code for Solid-start With Tailwindcss, created by Solidjs on StackBlitz
Brendonovich
Brendonovich4mo ago
iirc server functions and ssr run in slightly different environments, i don't think you can rely on constants being shared like that yet
NitonFx
NitonFxOP4mo ago
What would be the best way without a external database be too have a shared cache, map, state or object between these environments then?
Madaxen86
Madaxen864mo ago
Here's a working example with a map: https://stackblitz.com/edit/github-vzswgd?file=src%2Fapp.tsx But you could also use a cookie to store the data to make it available across server and client/browser.
StackBlitz
Solid-start With Tailwindcss Example - StackBlitz
Run official live example code for Solid-start With Tailwindcss, created by Solidjs on StackBlitz
NitonFx
NitonFxOP4mo ago
I dont think i want to share the internal access key in a cookie readable for the user since the mentioned "Map" is a session store but thanks i will take a look at your example
NitonFx
NitonFxOP4mo ago
@Madaxen86 So i saw your example does not use a server route/api route/GET I added such a route and it doesnt work https://stackblitz.com/edit/github-vzswgd-r4ctkn?file=src%2Fapp.tsx
StackBlitz
Solid-start With Tailwindcss Example (forked) - StackBlitz
Run official live example code for Solid-start With Tailwindcss, created by Solidjs on StackBlitz
NitonFx
NitonFxOP4mo ago
So basically what i want to do is having a route /api/login_callback that acts as a oauth callback point. On call i want to store the access tokens inMemory and on subsequent requests (either "use server"; or an api route) i want to look the user up in this in memory store. Yes as soon as i want to scale it i have to replace it with redis or whatever but i dont need that for now.
Madaxen86
Madaxen864mo ago
by using createAsync with a function that uses the "use server" directive an API route will automatically be created. You may have a look at the with-auth example. It uses vinxis session utils to store whatever in a encrypted session cookie which you can get in any server function / action. https://github.com/solidjs/solid-start/tree/main/examples/with-auth
GitHub
solid-start/examples/with-auth at main · solidjs/solid-start
SolidStart, the Solid app framework. Contribute to solidjs/solid-start development by creating an account on GitHub.
NitonFx
NitonFxOP4mo ago
@Madaxen86
by using createAsync with a function that uses the "use server" directive an API route will automatically be created.
But i cannot control the api path its always _server ? My oauth server requires me to have a url /api/login_callback that it can deliver the token to. Or do you mean using an use server function inside the api GET handler so the server RPC calls himself and therefore can access the object/cache/session store bound to the "RPC scope"? Regarding vinxi useSession i tried to but the documentation didn't state at all what the password is how to generate, handle, rotate ... it securely and so on so i was pretty sure its beta feature; especially when its a security related feature. Also i was concerned about "replacability" how easy could i change to store to redis or postgres but i should maybe try it again?
Madaxen86
Madaxen864mo ago
Yeah you can call the function inside an api route which creates the session if you need a specific route for a third party. But that’s a completely different use case than the initial getting data from a map.
NitonFx
NitonFxOP4mo ago
Maybe i am missunderstanding. So here is pseudocode-ish what i tried: src/routes/api/login_callback.ts
import { myglobalmap } from "~/lib/myglobalmap"
export function GET(event: APIEvent) {
const apiKey = completeOAuthHandshake(event);
myglobalmap.set("some-key", apiKey);
setCookie("globalmapkey","some-key");
}
import { myglobalmap } from "~/lib/myglobalmap"
export function GET(event: APIEvent) {
const apiKey = completeOAuthHandshake(event);
myglobalmap.set("some-key", apiKey);
setCookie("globalmapkey","some-key");
}
src/lib/myglobalmap.ts
export const myglobalmap = new Map<string, OAuthKeyset>;
export const myglobalmap = new Map<string, OAuthKeyset>;
src/lib/useThirdPartyApi.ts
import { myglobalmap } from "~/lib/myglobalmap"

function callThirdPartyApi(){
"use server";
var thirdPartyApiKey = myglobalmap.get(getCookie("globalmapkey")).apiKeyXYZ;
return thirdParyClient.call(thirdPartyApiKey);
}
import { myglobalmap } from "~/lib/myglobalmap"

function callThirdPartyApi(){
"use server";
var thirdPartyApiKey = myglobalmap.get(getCookie("globalmapkey")).apiKeyXYZ;
return thirdParyClient.call(thirdPartyApiKey);
}
and in a component you would use callThirdPartyApi() . But callThirdPartyApi() cannot read the value added to the myglobalmap I am not sure how i would apply your cache() and useAction createAction with this. I tried keeping is at short and trimmed down as possible also i wrote the code in discord so many imports missing
Madaxen86
Madaxen864mo ago
Well if you use a cookie you won’t need the map. The cookie is send from the client to the server on every request. You can access it with getCookie in any server function. Make sure to add the httpOnly and secure options. Solids server functions are not much different from Remix‘s for example. The with-auth example is great. It shows how to use vinxi‘s session. The password is just a random string for encryption of the cookie value which is typically an env variable. Regarding the login flow you should probably stick to an example provided by the auth service’s docs. But i don’t think the auth service sends the token to an api route but rather an api route - which is called by the client - should request the token and then pass the token in a httpOnly and secure cookie as a response to the client. If the auth server would sent it to an api the auth server would also get the response.
NitonFx
NitonFxOP3mo ago
You can access it with getCookie in any server function
Yes this works, i store the key to the map in there (a uuid with httpOnly) and both "use server" and api route can use it
But i don’t think the auth service sends the token to an api route but rather an api route - which is called by the client - should request the token and then pass the token in a httpOnly and secure cookie as a response to the client.
Yes and no the server is a OAuth server so he sends me an url which i call with all the security verifiers etc and get the tokens, introspections and so on. But the tokenset and data i get back from the auth server is rly rly big thats why i refrained from storing all that in the cookie (even encrypted) since the cookie would have around ~2kb which is a little bit much?
Regarding the login flow you should probably stick to an example provided by the auth service’s docs.
Thats what i am trying to do. They state that it is best practice to not expose the access and refresh tokens from the response to the client (and if rly neccesary only encrypted which is what vinxis useSession would do if i understand right)
The with-auth example is great. It shows how to use vinxi‘s session. The password is just a random string for encryption of the cookie value which is typically an env variable.
If implementing a shared store/object/map between a "use server" function and an api route as Brendonovitch pointed out is not possible i will have to fall back to this @Brendonovich do you have any (more) information about the isolation you talked about. Are there solid-start primitives to bypass this isolation createServerSideResource() or something like that?
Brendonovich
Brendonovich3mo ago
not much more, sorry. i just know that vinxi builds server functions and api routes as different bundles so sharing across them doesn't really work.
Want results from more Discord servers?
Add your server