mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
Refactor cookie handling for TanStack Start integration
- Removed the deprecated tanStackStartServerBrowserStub function from the Vite configuration. - Updated cookie management in the cookie.ts file to support dynamic imports for TanStack Start server APIs. - Enhanced createCookieHelper to conditionally use TanStack Start's cookie methods based on the SSR environment. - Adjusted createTanStackStartCookieHelper to accept the server API as a parameter for better modularity. These changes streamline the integration of TanStack Start, improving cookie management and ensuring compatibility with server-side rendering.
This commit is contained in:
parent
32ab9c37b6
commit
d7f55c1ffd
@ -48,39 +48,6 @@ function stackSdkSourceTransforms(): Plugin {
|
||||
};
|
||||
}
|
||||
|
||||
function tanStackStartServerBrowserStub(): Plugin {
|
||||
const virtualModuleId = "\0tanstack-start-server-browser-stub";
|
||||
|
||||
return {
|
||||
name: "tanstack-start-server-browser-stub",
|
||||
enforce: "pre",
|
||||
resolveId(source, _importer, options) {
|
||||
if (source === "@tanstack/react-start/server" && !options.ssr) {
|
||||
return virtualModuleId;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
load(id) {
|
||||
if (id !== virtualModuleId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return `
|
||||
const throwServerOnly = () => {
|
||||
throw new Error("@tanstack/react-start/server was called from the browser bundle");
|
||||
};
|
||||
|
||||
export const getCookie = throwServerOnly;
|
||||
export const getCookies = throwServerOnly;
|
||||
export const setCookie = throwServerOnly;
|
||||
export const deleteCookie = throwServerOnly;
|
||||
export const getRequestHeader = throwServerOnly;
|
||||
`;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function watchNodeModules(modules: string[]): Plugin {
|
||||
return {
|
||||
name: "watch-node-modules",
|
||||
@ -164,7 +131,6 @@ export default defineConfig({
|
||||
},
|
||||
plugins: [
|
||||
stackSdkSourceTransforms(),
|
||||
tanStackStartServerBrowserStub(),
|
||||
waitForWorkspacePackages(["@stackframe/tanstack-start", "@stackframe/stack-shared", "@stackframe/stack-ui"]),
|
||||
watchNodeModules(["@stackframe/tanstack-start", "@stackframe/stack-shared", "@stackframe/stack-ui"]),
|
||||
tsConfigPaths(),
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { cookies as rscCookies, headers as rscHeaders } from '@stackframe/stack-sc/force-react-server'; // THIS_LINE_PLATFORM next
|
||||
import { getCookie as tssGetCookie, getCookies as tssGetCookies, setCookie as tssSetCookie, deleteCookie as tssDeleteCookie, getRequestHeader as tssGetRequestHeader } from '@tanstack/react-start/server'; // THIS_LINE_PLATFORM tanstack-start
|
||||
import { isBrowserLike } from '@stackframe/stack-shared/dist/utils/env';
|
||||
import { StackAssertionError } from '@stackframe/stack-shared/dist/utils/errors';
|
||||
import Cookies from "js-cookie";
|
||||
@ -68,6 +67,28 @@ import { calculatePKCECodeChallenge, generateRandomCodeVerifier, generateRandomS
|
||||
type SetCookieOptions = { maxAge: number | "session", noOpIfServerComponent?: boolean, domain?: string, secure?: boolean };
|
||||
type DeleteCookieOptions = { noOpIfServerComponent?: boolean, domain?: string };
|
||||
|
||||
// IF_PLATFORM tanstack-start
|
||||
type TanStackStartServerCookieApi = typeof import("@tanstack/react-start/server");
|
||||
const tanStackStartServerCookieApiImportPath = "@tanstack/react-start/server";
|
||||
let tanStackStartServerCookieApiPromise: Promise<TanStackStartServerCookieApi> | null = null;
|
||||
let tanStackStartCookieHelperPromise: Promise<CookieHelper> | null = null;
|
||||
|
||||
declare global {
|
||||
interface ImportMetaEnv {
|
||||
SSR: boolean,
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv,
|
||||
}
|
||||
}
|
||||
|
||||
async function getTanStackStartServerCookieApi(): Promise<TanStackStartServerCookieApi> {
|
||||
tanStackStartServerCookieApiPromise ??= import(tanStackStartServerCookieApiImportPath);
|
||||
return await tanStackStartServerCookieApiPromise;
|
||||
}
|
||||
// END_PLATFORM
|
||||
|
||||
function ensureClient() {
|
||||
if (!isBrowserLike()) {
|
||||
throw new Error("cookieClient functions can only be called in a browser environment, yet window is undefined");
|
||||
@ -116,7 +137,13 @@ export async function createCookieHelper(): Promise<CookieHelper> {
|
||||
await rscHeaders(),
|
||||
);
|
||||
// ELSE_IF_PLATFORM tanstack-start
|
||||
return createTanStackStartCookieHelper();
|
||||
if (import.meta.env.SSR) {
|
||||
const cookieHelperPromise = tanStackStartCookieHelperPromise
|
||||
?? getTanStackStartServerCookieApi().then((api) => createTanStackStartCookieHelper(api));
|
||||
tanStackStartCookieHelperPromise = cookieHelperPromise;
|
||||
return await cookieHelperPromise;
|
||||
}
|
||||
return await createPlaceholderCookieHelper();
|
||||
// ELSE_PLATFORM
|
||||
return await createPlaceholderCookieHelper();
|
||||
// END_PLATFORM
|
||||
@ -127,9 +154,6 @@ export function createCookieHelperSync(): CookieHelper {
|
||||
if (isBrowserLike()) {
|
||||
return createBrowserCookieHelper();
|
||||
}
|
||||
// IF_PLATFORM tanstack-start
|
||||
return createTanStackStartCookieHelper();
|
||||
// ELSE_PLATFORM
|
||||
function throwError(): never {
|
||||
throw new StackAssertionError("Synchronous server cookie helpers are not available on this platform");
|
||||
}
|
||||
@ -140,17 +164,16 @@ export function createCookieHelperSync(): CookieHelper {
|
||||
setOrDelete: throwError,
|
||||
delete: throwError,
|
||||
};
|
||||
// END_PLATFORM
|
||||
}
|
||||
|
||||
// IF_PLATFORM tanstack-start
|
||||
function determineSecureFromTanStackStartContext(): boolean {
|
||||
return tssGetRequestHeader("x-forwarded-proto") === "https"
|
||||
|| (tssGetCookie("stack-is-https") !== undefined);
|
||||
function determineSecureFromTanStackStartContext(api: TanStackStartServerCookieApi): boolean {
|
||||
return api.getRequestHeader("x-forwarded-proto") === "https"
|
||||
|| (api.getCookie("stack-is-https") !== undefined);
|
||||
}
|
||||
|
||||
function refreshTanStackStartIsHttpsCookie() {
|
||||
tssSetCookie("stack-is-https", "true", {
|
||||
function refreshTanStackStartIsHttpsCookie(api: TanStackStartServerCookieApi) {
|
||||
api.setCookie("stack-is-https", "true", {
|
||||
secure: true,
|
||||
maxAge: 60 * 60 * 24 * 365,
|
||||
sameSite: "lax",
|
||||
@ -158,7 +181,7 @@ function refreshTanStackStartIsHttpsCookie() {
|
||||
});
|
||||
}
|
||||
|
||||
function createTanStackStartCookieHelper(): CookieHelper {
|
||||
function createTanStackStartCookieHelper(api: TanStackStartServerCookieApi): CookieHelper {
|
||||
const helper: CookieHelper = {
|
||||
get: (name: string) => {
|
||||
const all = helper.getAll();
|
||||
@ -166,13 +189,13 @@ function createTanStackStartCookieHelper(): CookieHelper {
|
||||
},
|
||||
getAll: () => {
|
||||
// set a helper cookie, see comment in `NextCookieHelper.set` below
|
||||
refreshTanStackStartIsHttpsCookie();
|
||||
return tssGetCookies();
|
||||
refreshTanStackStartIsHttpsCookie(api);
|
||||
return api.getCookies();
|
||||
},
|
||||
set: (name: string, value: string, options: SetCookieOptions) => {
|
||||
validateCookieOptions(name, options);
|
||||
tssSetCookie(name, value, {
|
||||
secure: requiresSecureAttribute(name) || (options.secure ?? determineSecureFromTanStackStartContext()),
|
||||
api.setCookie(name, value, {
|
||||
secure: requiresSecureAttribute(name) || (options.secure ?? determineSecureFromTanStackStartContext(api)),
|
||||
maxAge: options.maxAge === "session" ? undefined : options.maxAge,
|
||||
domain: options.domain,
|
||||
sameSite: "lax",
|
||||
@ -185,8 +208,8 @@ function createTanStackStartCookieHelper(): CookieHelper {
|
||||
},
|
||||
delete: (name: string, options: DeleteCookieOptions) => {
|
||||
validateCookieOptions(name, options);
|
||||
const secure = requiresSecureAttribute(name) || determineSecureFromTanStackStartContext();
|
||||
tssDeleteCookie(name, {
|
||||
const secure = requiresSecureAttribute(name) || determineSecureFromTanStackStartContext(api);
|
||||
api.deleteCookie(name, {
|
||||
secure,
|
||||
domain: options.domain,
|
||||
path: "/",
|
||||
@ -323,7 +346,9 @@ export async function isSecure(): Promise<boolean> {
|
||||
// IF_PLATFORM next
|
||||
return determineSecureFromServerContext(await rscCookies(), await rscHeaders());
|
||||
// ELSE_IF_PLATFORM tanstack-start
|
||||
return determineSecureFromTanStackStartContext();
|
||||
if (import.meta.env.SSR) {
|
||||
return determineSecureFromTanStackStartContext(await getTanStackStartServerCookieApi());
|
||||
}
|
||||
// END_PLATFORM
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ import React, { useCallback, useMemo } from "react"; // THIS_LINE_PLATFORM react
|
||||
import type * as yup from "yup";
|
||||
import { constructRedirectUrl } from "../../../../utils/url";
|
||||
import { getNewOAuthProviderOrScopeUrl, callOAuthCallback } from "../../../auth";
|
||||
import { CookieHelper, createBrowserCookieHelper, createCookieHelper, createCookieHelperSync, createPlaceholderCookieHelper, deleteCookie, deleteCookieClient, isSecure as isSecureCookieContext, saveVerifierAndState, setOrDeleteCookie, setOrDeleteCookieClient } from "../../../cookie";
|
||||
import { CookieHelper, createBrowserCookieHelper, createCookieHelper, createPlaceholderCookieHelper, deleteCookie, deleteCookieClient, isSecure as isSecureCookieContext, saveVerifierAndState, setOrDeleteCookie, setOrDeleteCookieClient } from "../../../cookie";
|
||||
import { envVars } from "../../../env";
|
||||
import { ApiKey, ApiKeyCreationOptions, ApiKeyUpdateOptions, apiKeyCreationOptionsToCrud } from "../../api-keys";
|
||||
import { ConvexCtx, GetCurrentPartialUserOptions, GetCurrentUserOptions, HandlerUrlOptions, HandlerUrls, OAuthScopesOnSignIn, RedirectMethod, RedirectToOptions, RequestLike, ResolvedHandlerUrls, TokenStoreInit, stackAppInternalsSymbol } from "../../common";
|
||||
@ -1031,7 +1031,7 @@ export class _StackClientAppImplIncomplete<HasTokenStore extends boolean, Projec
|
||||
protected _useTokenStore(overrideTokenStoreInit?: TokenStoreInit): Store<TokenObject> {
|
||||
// IF_PLATFORM tanstack-start
|
||||
if (!isBrowserLike()) {
|
||||
return this._getOrCreateTokenStore(createCookieHelperSync(), overrideTokenStoreInit);
|
||||
return this._getOrCreateTokenStore(use(createCookieHelper()), overrideTokenStoreInit);
|
||||
}
|
||||
// END_PLATFORM
|
||||
suspendIfSsr();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user