11import { betterFetch } from "@better-fetch/fetch" ;
2- import type { betterAuth } from "better-auth" ;
2+ import { betterAuth } from "better-auth" ;
33import { createCookieGetter } from "better-auth/cookies" ;
4+ import type { APIContext , AstroCookies } from "astro" ;
45import { ConvexHttpClient } from "convex/browser" ;
56import type {
67 FunctionReference ,
78 FunctionReturnType ,
89 GenericActionCtx ,
910 GenericDataModel ,
1011} from "convex/server" ;
11- import type { APIContext , AstroCookies } from "astro" ;
12- import { type CreateAuth , getStaticAuth } from "../client" ;
1312import { JWT_COOKIE_NAME } from "../plugins/convex" ;
13+ import { type CreateAuth , getStaticAuth } from "../client" ;
1414
15- type CookieReader = ( name : string ) => string | undefined ;
16- type CookieSource = AstroCookies | CookieReader | undefined ;
1715type AstroRequestContext =
1816 | Pick < APIContext , "request" | "cookies" >
19- | {
20- request : Request ;
21- cookies ?: CookieSource ;
22- } ;
23- type CookieInput =
24- | CookieSource
17+ | { request : Request ; cookies ?: AstroCookies } ;
18+
19+ type CookieSource =
2520 | AstroRequestContext
21+ | AstroCookies
2622 | Request
2723 | Headers
2824 | string
29- | {
30- request ?: Request ;
31- headers ?: Headers | string ;
32- cookies ?: CookieSource | string ;
33- cookie ?: string ;
34- } ;
25+ | undefined ;
3526
3627const safeDecode = ( value : string ) => {
3728 try {
@@ -41,127 +32,74 @@ const safeDecode = (value: string) => {
4132 }
4233} ;
4334
44- const cookieReaderFromString = ( cookieHeader : string ) : CookieReader => {
35+ const isAstroCookies = ( value : unknown ) : value is AstroCookies =>
36+ ! ! value &&
37+ typeof value === "object" &&
38+ "get" in value &&
39+ typeof ( value as { get ?: unknown } ) . get === "function" ;
40+
41+ const readCookieFromHeader = (
42+ cookieHeader : string | null | undefined ,
43+ name : string
44+ ) => {
4545 if ( ! cookieHeader ) {
46- return ( ) => undefined ;
46+ return undefined ;
4747 }
48- const pairs = cookieHeader . split ( / ; \s * / ) . filter ( Boolean ) ;
49- const store = new Map < string , string > ( ) ;
50- for ( const pair of pairs ) {
48+ for ( const pair of cookieHeader . split ( / ; \s * / ) ) {
49+ if ( ! pair ) {
50+ continue ;
51+ }
5152 const separatorIndex = pair . indexOf ( "=" ) ;
5253 if ( separatorIndex === - 1 ) {
5354 continue ;
5455 }
5556 const key = safeDecode ( pair . slice ( 0 , separatorIndex ) . trim ( ) ) ;
56- const value = safeDecode ( pair . slice ( separatorIndex + 1 ) ) ;
57- if ( ! store . has ( key ) ) {
58- store . set ( key , value ) ;
59- }
60- }
61- if ( store . size === 0 ) {
62- return ( ) => undefined ;
63- }
64- return ( name ) => {
65- if ( ! name ) {
66- return undefined ;
57+ if ( key !== name ) {
58+ continue ;
6759 }
68- return store . get ( name ) ;
69- } ;
70- } ;
71-
72- const isAstroCookies = ( source : unknown ) : source is AstroCookies => {
73- if ( ! source || typeof source !== "object" ) {
74- return false ;
75- }
76- return (
77- "get" in source &&
78- typeof ( source as { get ?: unknown } ) . get === "function" &&
79- "has" in source &&
80- typeof ( source as { has ?: unknown } ) . has === "function" &&
81- "merge" in source &&
82- typeof ( source as { merge ?: unknown } ) . merge === "function"
83- ) ;
84- } ;
85-
86- const isHeadersLike = ( source : unknown ) : source is Headers => {
87- return typeof Headers !== "undefined" && source instanceof Headers ;
88- } ;
89-
90- const isRequestLike = ( source : unknown ) : source is Request => {
91- if ( typeof Request !== "undefined" && source instanceof Request ) {
92- return true ;
60+ const rawValue = pair . slice ( separatorIndex + 1 ) ;
61+ return safeDecode ( rawValue ) ;
9362 }
94- if ( ! source || typeof source !== "object" ) {
95- return false ;
96- }
97- return (
98- "headers" in source &&
99- typeof ( source as { headers ?: unknown } ) . headers !== "undefined" &&
100- "method" in source
101- ) ;
63+ return undefined ;
10264} ;
10365
104- const normalizeCookieSource = ( source : CookieInput ) : CookieSource => {
66+ const readCookie = ( source : CookieSource , name : string ) : string | undefined => {
10567 if ( ! source ) {
10668 return undefined ;
10769 }
108- if ( typeof source === "function" ) {
109- return source ;
110- }
111- if ( isAstroCookies ( source ) ) {
112- return source ;
70+ if ( typeof source === "string" ) {
71+ return readCookieFromHeader ( source , name ) ;
11372 }
114- if ( isRequestLike ( source ) ) {
115- return normalizeCookieSource ( ( source as Request ) . headers ) ;
73+ if ( source instanceof Headers ) {
74+ return readCookieFromHeader ( source . get ( "cookie" ) , name ) ;
11675 }
117- if ( isHeadersLike ( source ) ) {
118- const cookieHeader = ( source as Headers ) . get ( "cookie" ) ?? "" ;
119- return cookieHeader ? cookieReaderFromString ( cookieHeader ) : undefined ;
76+ if ( source instanceof Request ) {
77+ return readCookie ( source . headers , name ) ;
12078 }
121- if ( typeof source === "string" ) {
122- return cookieReaderFromString ( source ) ;
79+ if ( isAstroCookies ( source ) ) {
80+ const cookie = source . get ( name ) ;
81+ return typeof cookie ?. value === "string" ? cookie . value : undefined ;
12382 }
124- if ( typeof source === "object" ) {
125- if ( "cookies" in source && source . cookies ) {
126- const normalized = normalizeCookieSource ( source . cookies as CookieInput ) ;
127- if ( normalized ) {
128- return normalized ;
129- }
130- }
131- if ( "request" in source && source . request ) {
132- const normalized = normalizeCookieSource ( source . request as CookieInput ) ;
133- if ( normalized ) {
134- return normalized ;
135- }
136- }
137- if ( "headers" in source && source . headers ) {
138- const normalized = normalizeCookieSource ( source . headers as CookieInput ) ;
139- if ( normalized ) {
140- return normalized ;
141- }
83+ if (
84+ typeof source === "object" &&
85+ source !== null &&
86+ "cookies" in source &&
87+ source . cookies
88+ ) {
89+ const fromStore = readCookie ( source . cookies , name ) ;
90+ if ( fromStore ) {
91+ return fromStore ;
14292 }
143- if ( "cookie" in source && typeof source . cookie === "string" ) {
144- const normalized = normalizeCookieSource ( source . cookie ) ;
145- if ( normalized ) {
146- return normalized ;
147- }
148- }
149- }
150- return undefined ;
151- } ;
152-
153- const createCookieReader = ( source : CookieInput ) : CookieReader => {
154- const normalized = normalizeCookieSource ( source ) ;
155- if ( typeof normalized === "function" ) {
156- return normalized ;
15793 }
158- if ( normalized && typeof normalized . get === "function" ) {
159- return ( name ) => {
160- const cookie = normalized . get ( name ) as { value ?: string } | undefined ;
161- return typeof cookie ?. value === "string" ? cookie . value : undefined ;
162- } ;
94+ if (
95+ typeof source === "object" &&
96+ source !== null &&
97+ "request" in source &&
98+ source . request
99+ ) {
100+ return readCookie ( source . request , name ) ;
163101 }
164- return ( ) => undefined ;
102+ return undefined ;
165103} ;
166104
167105export const getCookieName = < DataModel extends GenericDataModel > (
@@ -174,24 +112,23 @@ export const getCookieName = <DataModel extends GenericDataModel>(
174112
175113export const getToken = < DataModel extends GenericDataModel > (
176114 createAuth : CreateAuth < DataModel > ,
177- cookies ?: CookieInput
115+ cookies ?: CookieSource
178116) => {
179117 const sessionCookieName = getCookieName ( createAuth ) ;
180- const readCookie = createCookieReader ( cookies ) ;
181- const token = readCookie ( sessionCookieName ) ;
118+ const token = readCookie ( cookies , sessionCookieName ) ;
182119
183120 if ( ! token ) {
184121 const isSecure = sessionCookieName . startsWith ( "__Secure-" ) ;
185122 const insecureCookieName = sessionCookieName . replace ( "__Secure-" , "" ) ;
186123 const secureCookieName = isSecure
187124 ? sessionCookieName
188125 : `__Secure-${ insecureCookieName } ` ;
189- const secureToken = readCookie ( secureCookieName ) ;
190- const insecureToken = readCookie ( insecureCookieName ) ;
126+ const secureToken = readCookie ( cookies , secureCookieName ) ;
127+ const insecureToken = readCookie ( cookies , insecureCookieName ) ;
191128
192129 if ( isSecure && insecureToken ) {
193130 console . warn (
194- `Looking for secure cookie ${ sessionCookieName } but found insecure cookie ${ sessionCookieName . replace ( "__Secure-" , "" ) } `
131+ `Looking for secure cookie ${ sessionCookieName } but found insecure cookie ${ insecureCookieName } `
195132 ) ;
196133 }
197134 if ( ! isSecure && secureToken ) {
@@ -206,18 +143,16 @@ export const getToken = <DataModel extends GenericDataModel>(
206143
207144export const setupFetchClient = async < DataModel extends GenericDataModel > (
208145 createAuth : CreateAuth < DataModel > ,
209- cookies ?: CookieInput ,
146+ cookies ?: CookieSource ,
210147 opts ?: { convexUrl ?: string }
211148) => {
212- const readCookie = createCookieReader ( cookies ) ;
213149 const createClient = ( ) => {
214150 const convexUrl = opts ?. convexUrl ?? process . env . VITE_CONVEX_URL ;
215151 if ( ! convexUrl ) {
216152 throw new Error ( "VITE_CONVEX_URL is not set" ) ;
217153 }
218- const sessionCookieName = getCookieName ( createAuth ) ;
219- const token = readCookie ( sessionCookieName ) ;
220154 const client = new ConvexHttpClient ( convexUrl ) ;
155+ const token = getToken ( createAuth , cookies ) ;
221156 if ( token ) {
222157 client . setAuth ( token ) ;
223158 }
@@ -295,9 +230,7 @@ export const getAuth = async <DataModel extends GenericDataModel>(
295230 if ( ! request ) {
296231 throw new Error ( "No request found" ) ;
297232 }
298- const readCookie = createCookieReader ( context ) ;
299- const sessionCookieName = getCookieName ( createAuth ) ;
300- const token = readCookie ( sessionCookieName ) ;
233+ const token = getToken ( createAuth , context ) ;
301234 const { session } = await fetchSession ( request , opts ) ;
302235 return {
303236 userId : session ?. user . id ,
0 commit comments