Skip to content
This repository has been archived by the owner on Nov 8, 2022. It is now read-only.

provide a custom server context handler to enable authn/authz and other server middlewares #27

Open
acao opened this issue Jul 24, 2022 · 6 comments
Assignees
Labels
enhancement New feature or request

Comments

@acao
Copy link
Contributor

acao commented Jul 24, 2022

We need to be able to allow users to asynchronously build the initial page context before renderPage in each of the dev server, node and cloudflare environments. Something similar to this:

https://github.com/iMrDJAi/vps-nextauth-example/blob/main/server/index.ts

So - I think we can do this with page modules!

export async function render(pageContext: PageContextBuiltIn & PageContext) {
  if (pageContext?.exports?.createServerPageContext) {
    pageContext = await pageContext.exports.createServerPageContext(
      pageContext
    )
  }

  const { initialCompletion, getStoreSource } = renderReact(pageContext)

then the user doesn't need to override _default.page.server.tsx

@acao acao changed the title provide a custom server context handler to enable authn/authz and other server middlewares. provide a custom server context handler to enable authn/authz and other server middlewares Jul 24, 2022
@XiNiHa
Copy link
Owner

XiNiHa commented Jul 24, 2022

Isn't it more convenient to have them in onBeforeRender placed inside _default.page.server.tsx? Can you explain a bit more why are you trying to make the change? Some sample code would be greatly appreciated.

@acao
Copy link
Contributor Author

acao commented Jul 24, 2022

oh that will probably do I think? I was hoping to have access to the request object I forgot to mention, and I overlooked when I edited the original issue and changed the solution (much more context there)

I was hoping to do something like this, where we can handle jwt-style per-request authorization

https://vite-plugin-ssr.com/auth

I was thinking that users might want to be able to handle requests at the server level, attach middlewares, etc, looking something like this:

export const nodeExpressMiddleware = (req, res, pageContext) =>  {
    MyAuthMiddleware(req, res)
   // res so you can set headers/etc here as well
    return pageContext
 }
 
 export const cloudflareMiddleware = (req, res, pageContext) =>  {
   ...
 }
 
// fastify calls them plugins, but same concept
 export const nodeFastifyMiddleware = (req, res, pageContext) =>  {
   ....
 }

if you notice, the cited VPS vite examples each have a custom server that handles this at the middleware level
i was just hoping to make it easy for users to extend the provided vilay servers.

@XiNiHa
Copy link
Owner

XiNiHa commented Jul 24, 2022

Oh right, a middleware API would be very nice to have. I'll look at what NextJS is doing and design the API based on it, with further expansion considered in mind (like isomorphic GraphQL resolver definition)

@XiNiHa XiNiHa self-assigned this Jul 24, 2022
@XiNiHa XiNiHa added the enhancement New feature or request label Jul 24, 2022
@acao
Copy link
Contributor Author

acao commented Jul 24, 2022

nice ok! flarereact & remix have good cloudflare-centric approaches to this as well I think

@acao
Copy link
Contributor Author

acao commented Jul 25, 2022

More than just being able to add middlewares, I also need req and pageContext and to be able to mutate the initial server page context. something like this (for cloudflare at least):

...
export async function render(req: Request, renderVps: typeof renderPage) {
  const cookieHeader = req.headers.get('Cookie')
  let pageContextInit = {
    url: req.url,
    cookies: cookieHeader != null ? cookie.parse(cookieHeader) : undefined,
    userAgent: req.headers.get('User-Agent'),
    fetch,
  };
  // supply this somehow with esbuild/vite config based on whether certain files are present relative to the cli `cwd()`?
  if((globalThis as any)?.onPageContextInit){
    // provide both req and res so that middlewares can be added before returning page context
    // another option - merge the result page context with the init above, a return pattern ala vps methods
    // so you don't accidentally break things, like forget to pass on the `url`. 
    // also if you don't return anything it still works, and you can mount middlewares despite that
    pageContextInit = await (globalThis as any).onPageContextInit(req, res, pageContextInit)
  }

  const pageContext = await renderVps<
    { redirectTo?: string },
    typeof pageContextInit
  >(pageContextInit)
  ...
 }

@acao
Copy link
Contributor Author

acao commented Jul 25, 2022

in my original writeup for this issue i proposed a few options to define this config - simply define a vilay object in package.json, or even cosmic config for .js and .ts config files, or expect a specific path relative to .cwd(), but i think just specifying a specific file relative to the cwd() is fine, and the framework let esbuild/vite handle it with simple logic instead of hoping some weird tree shaking works out with user provided config and dynamic import paths.

letting esbuild/vite load the file as needed without user config outside page modules also lets it remain an internal framework detail, so you are free to introduce upstream optimizations and features to the server stack while still providing a powerful middleware layer. The framework will continue to take care of bundling the server source as well, making those build optimizations and runtime compatibility a built-in framework feature

this config could load from a few places:

  1. .vilay/server/cloudflare.ts or .vilay/server/node.ts?
  2. vilay-server/cloudflare.ts or vilay-server/node.ts?
  3. any other ideas?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants