Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/start-server-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"@tanstack/router-core": "workspace:*",
"@tanstack/start-client-core": "workspace:*",
"@tanstack/start-storage-context": "workspace:*",
"h3-v2": "npm:h3@2.0.1-rc.16",
"h3": "2.0.1-rc.19",
"seroval": "^1.4.2"
},
"devDependencies": {
Expand Down
18 changes: 14 additions & 4 deletions packages/start-server-core/src/request-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
unsealSession as h3_unsealSession,
updateSession as h3_updateSession,
useSession as h3_useSession,
} from 'h3-v2'
} from 'h3'
import type {
RequestHeaderMap,
RequestHeaderName,
Expand Down Expand Up @@ -147,7 +147,6 @@ export function getRequest(): Request {
}

export function getRequestHeaders(): TypedHeaders<RequestHeaderMap> {
// TODO `as any` not needed when fetchdts is updated
return getH3Event().req.headers as any
}

Expand Down Expand Up @@ -284,7 +283,16 @@ export function setResponseStatus(code?: number, text?: string): void {
*/
export function getCookies(): Record<string, string> {
const event = getH3Event()
return h3_parseCookies(event)
const cookies = h3_parseCookies(event)
const normalizedCookies: Record<string, string> = {}

for (const [name, value] of Object.entries(cookies)) {
if (value !== undefined) {
normalizedCookies[name] = value
}
}

return normalizedCookies
}

/**
Expand All @@ -296,7 +304,9 @@ export function getCookies(): Record<string, string> {
* ```
*/
export function getCookie(name: string): string | undefined {
return getCookies()[name] || undefined
const event = getH3Event()
const cookies = h3_parseCookies(event)
return cookies[name] || undefined
Comment on lines +307 to +309
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check the file exists and view lines 307-309
wc -l packages/start-server-core/src/request-response.ts
sed -n '305,315p' packages/start-server-core/src/request-response.ts

Repository: TanStack/router

Length of output: 407


🏁 Script executed:

# Let's also look for the getCookie function definition and context
sed -n '305,320p' packages/start-server-core/src/request-response.ts

Repository: TanStack/router

Length of output: 493


🏁 Script executed:

# Search for where h3_parseCookies is imported from
rg "h3_parseCookies" packages/start-server-core/src/request-response.ts -B 5 -A 5

Repository: TanStack/router

Length of output: 1108


🏁 Script executed:

# Check package.json to find h3 version
rg '"h3"' packages/start-server-core/package.json

Repository: TanStack/router

Length of output: 83


🏁 Script executed:

# Search for any tests or usage examples of getCookie with empty values
rg "getCookie" packages/start-server-core --type ts -A 3 -B 1 | head -50

Repository: TanStack/router

Length of output: 1351


🏁 Script executed:

# Check if there are any comments or documentation about cookie behavior
rg "cookie" packages/start-server-core/src/request-response.ts -i -B 2 -A 2

Repository: TanStack/router

Length of output: 3291


🏁 Script executed:

# Search for tests related to getCookie function
find packages/start-server-core -name "*.test.*" -o -name "*.spec.*" | xargs rg "getCookie|cookie" 2>/dev/null | head -30

Repository: TanStack/router

Length of output: 41


🏁 Script executed:

# Check if there's any TypeScript type definition or JSDoc for parseCookies
rg "parseCookies" --type ts -B 5 -A 10 | head -50

Repository: TanStack/router

Length of output: 3939


🌐 Web query:

h3 parseCookies TypeScript return type empty string values

💡 Result:

In the h3 library (unjs/h3), the parseCookies(event) utility parses the Cookie header from the request and returns a Record<string, string> (object mapping cookie names to their values as strings). Cookie values are always strings, including empty strings ("") if the cookie was set with an empty value (e.g., name=; Path=/). This is standard behavior for Cookie header parsing using libraries like cookie (jshttp/cookie), which h3 relies on internally. TypeScript treats Record<string, string> as all values being non-nullable strings, so empty string values are fully compatible—no type errors occur. If no cookies are present, it returns {} (empty object), which is also valid. Examples from h3 docs and source: - parseCookies(event) → { cookieName: "cookieValue" } or { cookieName: "" } - getCookie(event, name) → string | undefined (wrapper around parseCookies) No issues or bugs reported specifically about empty string values in TypeScript context. If experiencing type mismatches, ensure proper typing: const cookies: Record<string, string> = parseCookies(event);. For source confirmation, early h3 versions used parse(req.headers.cookie || '') from 'cookie', returning Record<string, string>. Current versions maintain this signature per docs and utils pages.

Citations:


Preserve empty cookie values in getCookie().

Line 309 uses || undefined, which converts valid empty cookie values ('') into undefined. This loses information about whether a cookie was explicitly set to an empty value versus not being set at all. Return the indexed value directly to preserve this distinction.

Suggested fix
 export function getCookie(name: string): string | undefined {
   const event = getH3Event()
   const cookies = h3_parseCookies(event)
-  return cookies[name] || undefined
+  return cookies[name]
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const event = getH3Event()
const cookies = h3_parseCookies(event)
return cookies[name] || undefined
export function getCookie(name: string): string | undefined {
const event = getH3Event()
const cookies = h3_parseCookies(event)
return cookies[name]
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/start-server-core/src/request-response.ts` around lines 307 - 309,
The getCookie implementation is converting empty-string cookie values to
undefined by using "cookies[name] || undefined"; update getCookie to return the
indexed value directly (i.e., return cookies[name]) so that explicit empty
values are preserved; locate the getCookie function where getH3Event() and
h3_parseCookies(event) are used and remove the "|| undefined" fallback.

}

/**
Expand Down
35 changes: 32 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading