From 0d62479bcf764d495ff1d69e86820a00f4495211 Mon Sep 17 00:00:00 2001 From: Daniel Choudhury Date: Thu, 4 Jan 2024 14:39:48 +0700 Subject: [PATCH] ServerAuthState types and stuff Inject initial server auth state on ssr --- packages/auth/ambient.d.ts | 2 + .../src/AuthProvider/ServerAuthProvider.tsx | 60 +++++++++++++++++-- packages/auth/src/index.ts | 1 + .../streaming/createReactStreamingHandler.ts | 3 +- packages/vite/src/streaming/streamHelpers.ts | 14 ++--- packages/web/src/apollo/suspense.tsx | 4 +- 6 files changed, 68 insertions(+), 16 deletions(-) diff --git a/packages/auth/ambient.d.ts b/packages/auth/ambient.d.ts index b4e7a73a07c2..afc9ba1e9364 100644 --- a/packages/auth/ambient.d.ts +++ b/packages/auth/ambient.d.ts @@ -22,6 +22,8 @@ declare global { __REDWOOD__APP_TITLE: string } + var __REDWOOD__SERVER__AUTH_STATE__: AuthProviderState + namespace NodeJS { interface Global { /** URL or absolute path to the GraphQL serverless function */ diff --git a/packages/auth/src/AuthProvider/ServerAuthProvider.tsx b/packages/auth/src/AuthProvider/ServerAuthProvider.tsx index 5dc7907f83ba..91725c507a93 100644 --- a/packages/auth/src/AuthProvider/ServerAuthProvider.tsx +++ b/packages/auth/src/AuthProvider/ServerAuthProvider.tsx @@ -1,13 +1,61 @@ +import type { ReactNode } from 'react' import React from 'react' import type { AuthProviderState } from './AuthProviderState' import { defaultAuthProviderState } from './AuthProviderState' -export const ServerAuthContext = React.createContext< - AuthProviderState & { - encryptedSession: string | null - cookieHeader?: string +export type ServerAuthState = AuthProviderState & { + // Used by AuthProvider in getToken. We can probably remove this + encryptedSession?: string | null + cookieHeader?: string +} + +/** + * On the server, it resolve to the defaultAuthProviderState first + */ +export const ServerAuthContext = React.createContext( + globalThis?.__REDWOOD__SERVER__AUTH_STATE__ || { + ...defaultAuthProviderState, + encryptedSession: null, } ->({ ...defaultAuthProviderState, encryptedSession: null }) +) + +/*** + * Note: This only gets rendered on the server and serves two purposes: + * 1) On the server, it sets the auth state + * 2) On the client, it restores the auth state from the initial server render + */ +export const ServerAuthProvider = ({ + value, + children, +}: { + value: ServerAuthState + children?: ReactNode[] +}) => { + // @NOTE: we "Sanitize" to remove encryptedSession and cookieHeader + // not totally necessary, but it's nice to not have them in the DOM + // @MARK: needs discussion! + const stringifiedAuthState = `__REDWOOD__SERVER__AUTH_STATE__ = ${JSON.stringify( + sanitizeServerAuthState(value) + )};` + + return ( + <> +