diff --git a/docs/start/config.json b/docs/start/config.json
index e93688eb91..ae401d3f6f 100644
--- a/docs/start/config.json
+++ b/docs/start/config.json
@@ -101,6 +101,10 @@
"label": "Environment Functions",
"to": "framework/react/guide/environment-functions"
},
+ {
+ "label": "Cookies",
+ "to": "framework/react/guide/cookies"
+ },
{
"label": "Middleware",
"to": "framework/react/guide/middleware"
@@ -238,6 +242,10 @@
"label": "Environment Functions",
"to": "framework/solid/guide/environment-functions"
},
+ {
+ "label": "Cookies",
+ "to": "framework/solid/guide/cookies"
+ },
{
"label": "Middleware",
"to": "framework/solid/guide/middleware"
diff --git a/docs/start/framework/react/guide/cookies.md b/docs/start/framework/react/guide/cookies.md
new file mode 100644
index 0000000000..517d883d59
--- /dev/null
+++ b/docs/start/framework/react/guide/cookies.md
@@ -0,0 +1,65 @@
+---
+id: cookies
+title: Cookies
+---
+
+Start ships two ways to read and write cookies:
+
+- **Server-only**: `getCookie`/`setCookie`/`getCookies`/`deleteCookie` from `@tanstack/react-start/server`. These only work inside an active server request (a server function, request middleware, or a server route) and throw otherwise.
+- **Isomorphic**: `getCookie`/`setCookie` from the root of `@tanstack/react-start`. The same call works on the server _and_ in the browser — pick this when a component or a shared helper needs to read/write a cookie regardless of which side it renders on.
+
+## Isomorphic `getCookie`/`setCookie`
+
+```tsx
+import { getCookie, setCookie } from '@tanstack/react-start'
+```
+
+These are built with [`createIsomorphicFn`](./environment-functions): on the server they delegate to the same request-scoped cookie handling as the `/server` versions; in the browser they read/write `document.cookie` directly.
+
+```tsx
+import * as React from 'react'
+import { getCookie, setCookie } from '@tanstack/react-start'
+
+export const getServerNow = createServerFn().handler(async () => {
+ // Runs on the server: reads the incoming request's `Cookie` header.
+ const theme = getCookie('theme') ?? 'light'
+ return theme
+})
+
+function ThemeToggle() {
+ const [theme, setTheme] = React.useState(() => getCookie('theme') ?? 'light')
+
+ return (
+
+ )
+}
+```
+
+## `HttpOnly` only works on the server
+
+`setCookie`'s `options` accept the same [`CookieSerializeOptions`](https://github.com/unjs/cookie-es) as the server-only version, including `httpOnly`. But `HttpOnly` is a protection against client-side JavaScript reading the cookie — so it can only be set from the server.
+
+If `setCookie` runs in the browser (the client branch) with `httpOnly: true`, the browser doesn't just ignore the flag — it silently discards the entire cookie write. `setCookie` logs a `console.warn` in development to help catch this, but there's no way to recover the write: if a cookie needs `HttpOnly`, set it from a server function or request middleware, not from client code.
+
+```tsx
+// ❌ Runs in the browser: the cookie is never actually set.
+setCookie('session', token, { httpOnly: true })
+
+// ✅ Runs on the server: `HttpOnly` is honored.
+export const login = createServerFn().handler(async () => {
+ setCookie('session', token, { httpOnly: true })
+})
+```
+
+## When to use the server-only versions instead
+
+Reach for `getCookie`/`setCookie`/`getCookies`/`deleteCookie` from `@tanstack/react-start/server` when the code only ever runs on the server (a server function handler, request middleware, or a server route) and you don't need it to also work in the browser — for example, reading a locale cookie inside request middleware, as shown in [Hydration Errors](./hydration-errors). Calling the server-only versions from client code throws instead of silently doing something unexpected.
diff --git a/docs/start/framework/react/guide/hydration-errors.md b/docs/start/framework/react/guide/hydration-errors.md
index fe0596684a..3342b1ccdc 100644
--- a/docs/start/framework/react/guide/hydration-errors.md
+++ b/docs/start/framework/react/guide/hydration-errors.md
@@ -133,4 +133,4 @@ export const Route = createFileRoute('/unstable')({
- **Use Selective SSR** when server HTML cannot be stable
- **Avoid blind suppression**; use `suppressHydrationWarning` sparingly
-See also: [Execution Model](./execution-model.md), [Code Execution Patterns](./code-execution-patterns.md), [Selective SSR](./selective-ssr.md), [Server Functions](./server-functions.md)
+See also: [Execution Model](./execution-model.md), [Code Execution Patterns](./code-execution-patterns.md), [Selective SSR](./selective-ssr.md), [Server Functions](./server-functions.md), [Cookies](./cookies.md)
diff --git a/docs/start/framework/solid/guide/cookies.md b/docs/start/framework/solid/guide/cookies.md
new file mode 100644
index 0000000000..6c0ef1a25b
--- /dev/null
+++ b/docs/start/framework/solid/guide/cookies.md
@@ -0,0 +1,65 @@
+---
+id: cookies
+title: Cookies
+---
+
+Start ships two ways to read and write cookies:
+
+- **Server-only**: `getCookie`/`setCookie`/`getCookies`/`deleteCookie` from `@tanstack/solid-start/server`. These only work inside an active server request (a server function, request middleware, or a server route) and throw otherwise.
+- **Isomorphic**: `getCookie`/`setCookie` from the root of `@tanstack/solid-start`. The same call works on the server _and_ in the browser — pick this when a component or a shared helper needs to read/write a cookie regardless of which side it renders on.
+
+## Isomorphic `getCookie`/`setCookie`
+
+```tsx
+import { getCookie, setCookie } from '@tanstack/solid-start'
+```
+
+These are built with [`createIsomorphicFn`](./environment-functions): on the server they delegate to the same request-scoped cookie handling as the `/server` versions; in the browser they read/write `document.cookie` directly.
+
+```tsx
+import { createSignal } from 'solid-js'
+import { getCookie, setCookie } from '@tanstack/solid-start'
+
+export const getServerNow = createServerFn().handler(async () => {
+ // Runs on the server: reads the incoming request's `Cookie` header.
+ const theme = getCookie('theme') ?? 'light'
+ return theme
+})
+
+function ThemeToggle() {
+ const [theme, setTheme] = createSignal(getCookie('theme') ?? 'light')
+
+ return (
+
+ )
+}
+```
+
+## `HttpOnly` only works on the server
+
+`setCookie`'s `options` accept the same [`CookieSerializeOptions`](https://github.com/unjs/cookie-es) as the server-only version, including `httpOnly`. But `HttpOnly` is a protection against client-side JavaScript reading the cookie — so it can only be set from the server.
+
+If `setCookie` runs in the browser (the client branch) with `httpOnly: true`, the browser doesn't just ignore the flag — it silently discards the entire cookie write. `setCookie` logs a `console.warn` in development to help catch this, but there's no way to recover the write: if a cookie needs `HttpOnly`, set it from a server function or request middleware, not from client code.
+
+```tsx
+// ❌ Runs in the browser: the cookie is never actually set.
+setCookie('session', token, { httpOnly: true })
+
+// ✅ Runs on the server: `HttpOnly` is honored.
+export const login = createServerFn().handler(async () => {
+ setCookie('session', token, { httpOnly: true })
+})
+```
+
+## When to use the server-only versions instead
+
+Reach for `getCookie`/`setCookie`/`getCookies`/`deleteCookie` from `@tanstack/solid-start/server` when the code only ever runs on the server (a server function handler, request middleware, or a server route) and you don't need it to also work in the browser — for example, reading a locale cookie inside request middleware, as shown in [Hydration Errors](./hydration-errors). Calling the server-only versions from client code throws instead of silently doing something unexpected.
diff --git a/docs/start/framework/solid/guide/hydration-errors.md b/docs/start/framework/solid/guide/hydration-errors.md
index 75e44280c9..2a49fdeaee 100644
--- a/docs/start/framework/solid/guide/hydration-errors.md
+++ b/docs/start/framework/solid/guide/hydration-errors.md
@@ -126,4 +126,4 @@ export const Route = createFileRoute('/unstable')({
- **Use ``/``** for inherently dynamic UI
- **Use Selective SSR** when server HTML cannot be stable
-See also: [Execution Model](./execution-model.md), [Code Execution Patterns](./code-execution-patterns.md), [Selective SSR](./selective-ssr.md), [Server Functions](./server-functions.md)
+See also: [Execution Model](./execution-model.md), [Code Execution Patterns](./code-execution-patterns.md), [Selective SSR](./selective-ssr.md), [Server Functions](./server-functions.md), [Cookies](./cookies.md)
diff --git a/packages/react-start/package.json b/packages/react-start/package.json
index b037e44f8f..a2e192c155 100644
--- a/packages/react-start/package.json
+++ b/packages/react-start/package.json
@@ -25,7 +25,9 @@
],
"scripts": {
"clean": "rimraf ./dist && rimraf ./coverage",
- "test": "pnpm test:build",
+ "test": "pnpm test:build && pnpm test:unit",
+ "test:unit": "vitest",
+ "test:unit:dev": "vitest --watch",
"test:build": "publint --strict && attw --ignore-rules no-resolution --pack .",
"build": "vite build && vite build -c vite.config.server-entry.ts"
},
diff --git a/packages/react-start/src/cookies.ts b/packages/react-start/src/cookies.ts
new file mode 100644
index 0000000000..037e04b5d6
--- /dev/null
+++ b/packages/react-start/src/cookies.ts
@@ -0,0 +1,33 @@
+import { createCookieFns } from '@tanstack/start-client-core/cookies'
+import {
+ getCookie as getServerCookie,
+ setCookie as setServerCookie,
+} from '@tanstack/start-server-core'
+
+const cookieFns = createCookieFns({
+ getCookie: getServerCookie,
+ setCookie: setServerCookie,
+})
+
+/**
+ * Get a cookie value by name. Works on both the server (reads the current
+ * request's `Cookie` header) and the client (reads `document.cookie`).
+ * @param name Name of the cookie to get
+ * @returns Value of the cookie, or `undefined` if not present
+ * ```ts
+ * const authorization = getCookie('Authorization')
+ * ```
+ */
+export const getCookie = cookieFns.getCookie
+
+/**
+ * Set a cookie value by name. Works on both the server (sets a `Set-Cookie`
+ * header on the current response) and the client (writes `document.cookie`).
+ * @param name Name of the cookie to set
+ * @param value Value of the cookie to set
+ * @param options Options for serializing the cookie
+ * ```ts
+ * setCookie('Authorization', '1234567')
+ * ```
+ */
+export const setCookie = cookieFns.setCookie
diff --git a/packages/react-start/src/index.ts b/packages/react-start/src/index.ts
index 6ea839a967..c6c32a9952 100644
--- a/packages/react-start/src/index.ts
+++ b/packages/react-start/src/index.ts
@@ -1,4 +1,5 @@
export { useServerFn } from './useServerFn'
+export { getCookie, setCookie } from './cookies'
export * from '@tanstack/start-client-core'
// Explicit re-exports shadow `export *` above so these public-API names are
// registered on the namespace at link time (via Vite SSR's `defineExport`
diff --git a/packages/react-start/tests/cookies.test.ts b/packages/react-start/tests/cookies.test.ts
new file mode 100644
index 0000000000..2e1dcc2e00
--- /dev/null
+++ b/packages/react-start/tests/cookies.test.ts
@@ -0,0 +1,39 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest'
+
+const getServerCookieMock = vi.fn<(name: string) => string | undefined>()
+const setServerCookieMock = vi.fn()
+
+vi.mock('@tanstack/start-server-core', () => ({
+ getCookie: getServerCookieMock,
+ setCookie: setServerCookieMock,
+}))
+
+const { getCookie, setCookie } = await import('../src/cookies')
+
+// The cookie logic itself (client-side parsing/serialization, the httpOnly
+// warning, and createCookieFns' delegation behavior) is covered by
+// start-client-core's own tests. This only verifies that this package wires
+// its getCookie/setCookie up to the right start-server-core functions.
+describe('getCookie/setCookie', () => {
+ beforeEach(() => {
+ getServerCookieMock.mockReset()
+ setServerCookieMock.mockReset()
+ })
+
+ it('delegates getCookie to start-server-core', () => {
+ getServerCookieMock.mockReturnValue('server-value')
+
+ expect(getCookie('token')).toBe('server-value')
+ expect(getServerCookieMock).toHaveBeenCalledExactlyOnceWith('token')
+ })
+
+ it('delegates setCookie to start-server-core', () => {
+ setCookie('token', 'abc123', { path: '/' })
+
+ expect(setServerCookieMock).toHaveBeenCalledExactlyOnceWith(
+ 'token',
+ 'abc123',
+ { path: '/' },
+ )
+ })
+})
diff --git a/packages/solid-start/package.json b/packages/solid-start/package.json
index 4b11e9a219..20d0b576a9 100644
--- a/packages/solid-start/package.json
+++ b/packages/solid-start/package.json
@@ -25,7 +25,9 @@
],
"scripts": {
"clean": "rimraf ./dist && rimraf ./coverage",
- "test": "pnpm test:build",
+ "test": "pnpm test:build && pnpm test:unit",
+ "test:unit": "vitest",
+ "test:unit:dev": "vitest --watch",
"test:build": "publint --strict && attw --ignore-rules no-resolution --pack .",
"build": "vite build && vite build -c vite.config.server-entry.ts"
},
diff --git a/packages/solid-start/src/cookies.ts b/packages/solid-start/src/cookies.ts
new file mode 100644
index 0000000000..037e04b5d6
--- /dev/null
+++ b/packages/solid-start/src/cookies.ts
@@ -0,0 +1,33 @@
+import { createCookieFns } from '@tanstack/start-client-core/cookies'
+import {
+ getCookie as getServerCookie,
+ setCookie as setServerCookie,
+} from '@tanstack/start-server-core'
+
+const cookieFns = createCookieFns({
+ getCookie: getServerCookie,
+ setCookie: setServerCookie,
+})
+
+/**
+ * Get a cookie value by name. Works on both the server (reads the current
+ * request's `Cookie` header) and the client (reads `document.cookie`).
+ * @param name Name of the cookie to get
+ * @returns Value of the cookie, or `undefined` if not present
+ * ```ts
+ * const authorization = getCookie('Authorization')
+ * ```
+ */
+export const getCookie = cookieFns.getCookie
+
+/**
+ * Set a cookie value by name. Works on both the server (sets a `Set-Cookie`
+ * header on the current response) and the client (writes `document.cookie`).
+ * @param name Name of the cookie to set
+ * @param value Value of the cookie to set
+ * @param options Options for serializing the cookie
+ * ```ts
+ * setCookie('Authorization', '1234567')
+ * ```
+ */
+export const setCookie = cookieFns.setCookie
diff --git a/packages/solid-start/src/index.ts b/packages/solid-start/src/index.ts
index bc5560978d..c0772acf46 100644
--- a/packages/solid-start/src/index.ts
+++ b/packages/solid-start/src/index.ts
@@ -1,4 +1,5 @@
export { useServerFn } from './useServerFn'
+export { getCookie, setCookie } from './cookies'
export * from '@tanstack/start-client-core'
// Explicit re-exports shadow `export *` above so these public-API names are
// registered on the namespace at link time (via Vite SSR's `defineExport`
diff --git a/packages/solid-start/tests/cookies.test.ts b/packages/solid-start/tests/cookies.test.ts
new file mode 100644
index 0000000000..2e1dcc2e00
--- /dev/null
+++ b/packages/solid-start/tests/cookies.test.ts
@@ -0,0 +1,39 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest'
+
+const getServerCookieMock = vi.fn<(name: string) => string | undefined>()
+const setServerCookieMock = vi.fn()
+
+vi.mock('@tanstack/start-server-core', () => ({
+ getCookie: getServerCookieMock,
+ setCookie: setServerCookieMock,
+}))
+
+const { getCookie, setCookie } = await import('../src/cookies')
+
+// The cookie logic itself (client-side parsing/serialization, the httpOnly
+// warning, and createCookieFns' delegation behavior) is covered by
+// start-client-core's own tests. This only verifies that this package wires
+// its getCookie/setCookie up to the right start-server-core functions.
+describe('getCookie/setCookie', () => {
+ beforeEach(() => {
+ getServerCookieMock.mockReset()
+ setServerCookieMock.mockReset()
+ })
+
+ it('delegates getCookie to start-server-core', () => {
+ getServerCookieMock.mockReturnValue('server-value')
+
+ expect(getCookie('token')).toBe('server-value')
+ expect(getServerCookieMock).toHaveBeenCalledExactlyOnceWith('token')
+ })
+
+ it('delegates setCookie to start-server-core', () => {
+ setCookie('token', 'abc123', { path: '/' })
+
+ expect(setServerCookieMock).toHaveBeenCalledExactlyOnceWith(
+ 'token',
+ 'abc123',
+ { path: '/' },
+ )
+ })
+})
diff --git a/packages/start-client-core/package.json b/packages/start-client-core/package.json
index edbff306fa..5eab7153a2 100644
--- a/packages/start-client-core/package.json
+++ b/packages/start-client-core/package.json
@@ -60,6 +60,12 @@
"default": "./dist/esm/client-rpc/index.js"
}
},
+ "./cookies": {
+ "import": {
+ "types": "./dist/esm/cookies.d.ts",
+ "default": "./dist/esm/cookies.js"
+ }
+ },
"./hydration": {
"import": {
"types": "./dist/esm/hydration.d.ts",
@@ -109,6 +115,7 @@
"@tanstack/router-core": "workspace:*",
"@tanstack/start-fn-stubs": "workspace:*",
"@tanstack/start-storage-context": "workspace:*",
+ "cookie-es": "^3.0.0",
"seroval": "^1.5.4"
},
"devDependencies": {
diff --git a/packages/start-client-core/src/cookies.ts b/packages/start-client-core/src/cookies.ts
new file mode 100644
index 0000000000..7ef6635e9b
--- /dev/null
+++ b/packages/start-client-core/src/cookies.ts
@@ -0,0 +1,58 @@
+import { createIsomorphicFn } from '@tanstack/start-fn-stubs'
+import { parse, serialize } from 'cookie-es'
+import type { CookieSerializeOptions } from 'cookie-es'
+
+export type GetCookieFn = (name: string) => string | undefined
+export type SetCookieFn = (
+ name: string,
+ value: string,
+ options?: CookieSerializeOptions,
+) => void
+
+// Exported (but not part of any package's public entry) so they can be unit
+// tested directly, since `createIsomorphicFn`'s uncompiled runtime fallback
+// always resolves to the `.server()` implementation once one is registered,
+// making the `.client()` branch unreachable through `createCookieFns`'s
+// output outside of a Start-compiled bundle.
+export function getClientCookie(name: string): string | undefined {
+ return parse(document.cookie)[name]
+}
+
+export function setClientCookie(
+ name: string,
+ value: string,
+ options?: CookieSerializeOptions,
+): void {
+ if (options?.httpOnly && process.env.NODE_ENV !== 'production') {
+ console.warn(
+ '`setCookie` was called with `httpOnly: true` in the browser. Browsers silently discard cookies written via `document.cookie` when `HttpOnly` is set, so this cookie will NOT be set.',
+ )
+ }
+ document.cookie = serialize(name, value, options)
+}
+
+/**
+ * Build isomorphic `getCookie`/`setCookie` functions from a server-side
+ * cookie implementation. On the server, calls delegate to the given
+ * implementations (e.g. the request-scoped `getCookie`/`setCookie` from
+ * `@tanstack/start-server-core`); in the browser, they read/write
+ * `document.cookie` directly.
+ *
+ * The server implementation is injected as a parameter rather than imported
+ * directly: `@tanstack/start-server-core` depends on this package, so a
+ * static import in the other direction would be a circular package
+ * dependency.
+ */
+export function createCookieFns(server: {
+ getCookie: GetCookieFn
+ setCookie: SetCookieFn
+}): { getCookie: GetCookieFn; setCookie: SetCookieFn } {
+ return {
+ getCookie: createIsomorphicFn()
+ .server(server.getCookie)
+ .client(getClientCookie),
+ setCookie: createIsomorphicFn()
+ .server(server.setCookie)
+ .client(setClientCookie),
+ }
+}
diff --git a/packages/start-client-core/tests/cookies.test.ts b/packages/start-client-core/tests/cookies.test.ts
new file mode 100644
index 0000000000..2f63a7129a
--- /dev/null
+++ b/packages/start-client-core/tests/cookies.test.ts
@@ -0,0 +1,119 @@
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+import {
+ createCookieFns,
+ getClientCookie,
+ setClientCookie,
+} from '../src/cookies'
+
+function clearDocumentCookies() {
+ document.cookie.split(';').forEach((cookie) => {
+ const name = cookie.split('=')[0]?.trim()
+ if (name) {
+ document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`
+ }
+ })
+}
+
+describe('createCookieFns (uncompiled createIsomorphicFn runtime fallback)', () => {
+ const getServerCookieMock = vi.fn<(name: string) => string | undefined>()
+ const setServerCookieMock = vi.fn()
+
+ beforeEach(() => {
+ getServerCookieMock.mockReset()
+ setServerCookieMock.mockReset()
+ })
+
+ // Outside of a Start-compiled bundle, createIsomorphicFn's runtime fallback
+ // always resolves to the `.server()` implementation once one is
+ // registered (see packages/start-fn-stubs/src/createIsomorphicFn.ts), so
+ // calling the returned getCookie/setCookie here exercises the server
+ // delegation, not the client branch.
+ it('delegates getCookie to the provided server implementation', () => {
+ getServerCookieMock.mockReturnValue('server-value')
+ const { getCookie } = createCookieFns({
+ getCookie: getServerCookieMock,
+ setCookie: setServerCookieMock,
+ })
+
+ expect(getCookie('token')).toBe('server-value')
+ expect(getServerCookieMock).toHaveBeenCalledExactlyOnceWith('token')
+ })
+
+ it('delegates setCookie to the provided server implementation', () => {
+ const { setCookie } = createCookieFns({
+ getCookie: getServerCookieMock,
+ setCookie: setServerCookieMock,
+ })
+
+ setCookie('token', 'abc123', { path: '/' })
+
+ expect(setServerCookieMock).toHaveBeenCalledExactlyOnceWith(
+ 'token',
+ 'abc123',
+ { path: '/' },
+ )
+ })
+})
+
+describe('getClientCookie', () => {
+ afterEach(() => {
+ clearDocumentCookies()
+ })
+
+ it('reads a cookie value from document.cookie', () => {
+ document.cookie = 'token=abc123'
+
+ expect(getClientCookie('token')).toBe('abc123')
+ })
+
+ it('returns undefined for a cookie that is not present', () => {
+ expect(getClientCookie('missing')).toBeUndefined()
+ })
+})
+
+describe('setClientCookie', () => {
+ afterEach(() => {
+ clearDocumentCookies()
+ vi.unstubAllEnvs()
+ vi.restoreAllMocks()
+ })
+
+ it('writes the cookie to document.cookie', () => {
+ setClientCookie('token', 'abc123', { path: '/' })
+
+ expect(getClientCookie('token')).toBe('abc123')
+ })
+
+ it('warns in development when httpOnly is set, since browsers silently discard the cookie', () => {
+ vi.stubEnv('NODE_ENV', 'development')
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
+
+ setClientCookie('token', 'abc123', { httpOnly: true })
+
+ expect(warnSpy).toHaveBeenCalledExactlyOnceWith(
+ expect.stringContaining('HttpOnly'),
+ )
+ // Per the WHATWG cookie spec, browsers discard the entire cookie (not
+ // just the HttpOnly attribute) when it's set via `document.cookie` with
+ // `HttpOnly` present.
+ expect(getClientCookie('token')).toBeUndefined()
+ })
+
+ it('does not warn when httpOnly is not set', () => {
+ vi.stubEnv('NODE_ENV', 'development')
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
+
+ setClientCookie('token', 'abc123')
+
+ expect(warnSpy).not.toHaveBeenCalled()
+ })
+
+ it('does not warn in production even when httpOnly is set', () => {
+ vi.stubEnv('NODE_ENV', 'production')
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
+
+ setClientCookie('token', 'abc123', { httpOnly: true })
+
+ expect(warnSpy).not.toHaveBeenCalled()
+ })
+})
diff --git a/packages/start-client-core/vite.config.ts b/packages/start-client-core/vite.config.ts
index 71e163a1ed..1ddcd93779 100644
--- a/packages/start-client-core/vite.config.ts
+++ b/packages/start-client-core/vite.config.ts
@@ -25,6 +25,7 @@ export default defineConfig(({ command }) =>
'./src/index.tsx',
'./src/client/index.ts',
'./src/client-rpc/index.ts',
+ './src/cookies.ts',
'./src/hydration/constants.ts',
'./src/hydration.ts',
'./src/hydration/runtime.ts',
diff --git a/packages/vue-start/package.json b/packages/vue-start/package.json
index 5afd0d06a5..3c670fa74c 100644
--- a/packages/vue-start/package.json
+++ b/packages/vue-start/package.json
@@ -25,7 +25,9 @@
],
"scripts": {
"clean": "rimraf ./dist && rimraf ./coverage",
- "test": "pnpm test:build",
+ "test": "pnpm test:build && pnpm test:unit",
+ "test:unit": "vitest",
+ "test:unit:dev": "vitest --watch",
"test:build": "publint --strict && attw --ignore-rules no-resolution --pack .",
"build": "vite build && vite build -c vite.config.server-entry.ts"
},
diff --git a/packages/vue-start/src/cookies.ts b/packages/vue-start/src/cookies.ts
new file mode 100644
index 0000000000..037e04b5d6
--- /dev/null
+++ b/packages/vue-start/src/cookies.ts
@@ -0,0 +1,33 @@
+import { createCookieFns } from '@tanstack/start-client-core/cookies'
+import {
+ getCookie as getServerCookie,
+ setCookie as setServerCookie,
+} from '@tanstack/start-server-core'
+
+const cookieFns = createCookieFns({
+ getCookie: getServerCookie,
+ setCookie: setServerCookie,
+})
+
+/**
+ * Get a cookie value by name. Works on both the server (reads the current
+ * request's `Cookie` header) and the client (reads `document.cookie`).
+ * @param name Name of the cookie to get
+ * @returns Value of the cookie, or `undefined` if not present
+ * ```ts
+ * const authorization = getCookie('Authorization')
+ * ```
+ */
+export const getCookie = cookieFns.getCookie
+
+/**
+ * Set a cookie value by name. Works on both the server (sets a `Set-Cookie`
+ * header on the current response) and the client (writes `document.cookie`).
+ * @param name Name of the cookie to set
+ * @param value Value of the cookie to set
+ * @param options Options for serializing the cookie
+ * ```ts
+ * setCookie('Authorization', '1234567')
+ * ```
+ */
+export const setCookie = cookieFns.setCookie
diff --git a/packages/vue-start/src/index.ts b/packages/vue-start/src/index.ts
index 21b3b5b003..14715dc3b5 100644
--- a/packages/vue-start/src/index.ts
+++ b/packages/vue-start/src/index.ts
@@ -1,4 +1,5 @@
export { useServerFn } from './useServerFn'
+export { getCookie, setCookie } from './cookies'
export * from '@tanstack/start-client-core'
// Explicit re-exports shadow `export *` above so these public-API names are
// registered on the namespace at link time (via Vite SSR's `defineExport`
diff --git a/packages/vue-start/tests/cookies.test.ts b/packages/vue-start/tests/cookies.test.ts
new file mode 100644
index 0000000000..2e1dcc2e00
--- /dev/null
+++ b/packages/vue-start/tests/cookies.test.ts
@@ -0,0 +1,39 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest'
+
+const getServerCookieMock = vi.fn<(name: string) => string | undefined>()
+const setServerCookieMock = vi.fn()
+
+vi.mock('@tanstack/start-server-core', () => ({
+ getCookie: getServerCookieMock,
+ setCookie: setServerCookieMock,
+}))
+
+const { getCookie, setCookie } = await import('../src/cookies')
+
+// The cookie logic itself (client-side parsing/serialization, the httpOnly
+// warning, and createCookieFns' delegation behavior) is covered by
+// start-client-core's own tests. This only verifies that this package wires
+// its getCookie/setCookie up to the right start-server-core functions.
+describe('getCookie/setCookie', () => {
+ beforeEach(() => {
+ getServerCookieMock.mockReset()
+ setServerCookieMock.mockReset()
+ })
+
+ it('delegates getCookie to start-server-core', () => {
+ getServerCookieMock.mockReturnValue('server-value')
+
+ expect(getCookie('token')).toBe('server-value')
+ expect(getServerCookieMock).toHaveBeenCalledExactlyOnceWith('token')
+ })
+
+ it('delegates setCookie to start-server-core', () => {
+ setCookie('token', 'abc123', { path: '/' })
+
+ expect(setServerCookieMock).toHaveBeenCalledExactlyOnceWith(
+ 'token',
+ 'abc123',
+ { path: '/' },
+ )
+ })
+})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7a7c3a7348..efbb5044d4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -78,7 +78,7 @@ importers:
version: 1.26.2(eslint@9.22.0(jiti@2.7.0))(ts-api-utils@2.4.0(typescript@6.0.2))(typescript@6.0.2)
'@nx/devkit':
specifier: 22.7.5
- version: 22.7.5(nx@22.7.5(@swc-node/register@1.11.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@swc/core@1.15.33(@swc/helpers@0.5.23))(@swc/types@0.1.26)(typescript@6.0.2))(@swc/core@1.15.33(@swc/helpers@0.5.23)))
+ version: 22.7.5(nx@22.7.5(@swc-node/register@1.11.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@swc/core@1.15.33(@swc/helpers@0.5.23))(@swc/types@0.1.26)(typescript@6.0.2))(@swc/core@1.15.33(@swc/helpers@0.5.23))(debug@4.4.3))
'@playwright/test':
specifier: ^1.57.0
version: 1.58.0
@@ -138,7 +138,7 @@ importers:
version: 4.0.3
nx:
specifier: 22.7.5
- version: 22.7.5(@swc-node/register@1.11.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@swc/core@1.15.33(@swc/helpers@0.5.23))(@swc/types@0.1.26)(typescript@6.0.2))(@swc/core@1.15.33(@swc/helpers@0.5.23))
+ version: 22.7.5(@swc-node/register@1.11.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@swc/core@1.15.33(@swc/helpers@0.5.23))(@swc/types@0.1.26)(typescript@6.0.2))(@swc/core@1.15.33(@swc/helpers@0.5.23))(debug@4.4.3)
prettier:
specifier: ^3.8.0
version: 3.8.1
@@ -281,7 +281,7 @@ importers:
devDependencies:
'@codspeed/vitest-plugin':
specifier: ^5.5.0
- version: 5.5.0(tinybench@2.9.0)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))(vitest@4.1.4)
+ version: 5.5.0(debug@4.4.3)(tinybench@2.9.0)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))(vitest@4.1.4)
'@platformatic/flame':
specifier: ^1.6.0
version: 1.6.0
@@ -342,7 +342,7 @@ importers:
devDependencies:
'@codspeed/vitest-plugin':
specifier: ^5.5.0
- version: 5.5.0(tinybench@2.9.0)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))(vitest@4.1.4)
+ version: 5.5.0(debug@4.4.3)(tinybench@2.9.0)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))(vitest@4.1.4)
'@datadog/pprof':
specifier: ^5.13.2
version: 5.13.2
@@ -415,7 +415,7 @@ importers:
devDependencies:
'@codspeed/vitest-plugin':
specifier: ^5.5.0
- version: 5.5.0(tinybench@2.9.0)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))(vitest@4.1.4)
+ version: 5.5.0(debug@4.4.3)(tinybench@2.9.0)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))(vitest@4.1.4)
'@datadog/pprof':
specifier: ^5.13.2
version: 5.13.2
@@ -476,7 +476,7 @@ importers:
devDependencies:
'@codspeed/vitest-plugin':
specifier: ^5.5.0
- version: 5.5.0(tinybench@2.9.0)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))(vitest@4.1.4)
+ version: 5.5.0(debug@4.4.3)(tinybench@2.9.0)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))(vitest@4.1.4)
'@vitejs/plugin-react':
specifier: ^6.0.1
version: 6.0.1(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))
@@ -9807,7 +9807,7 @@ importers:
version: 0.5.20(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))
nitro:
specifier: npm:nitro-nightly@latest
- version: nitro-nightly@3.0.260522-beta(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(@netlify/blobs@10.1.0)(chokidar@5.0.0)(dotenv@17.4.2)(giget@2.0.0)(jiti@2.7.0)(lru-cache@11.5.1)(mysql2@3.15.3)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))
+ version: nitro-nightly@4.0.0-20251010-091516-7cafddba(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(@netlify/blobs@10.1.0)(chokidar@4.0.3)(ioredis@5.9.2)(lru-cache@11.5.1)(mysql2@3.15.3)(rolldown@1.0.2)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))
tailwindcss:
specifier: ^4.1.18
version: 4.2.2
@@ -13287,6 +13287,9 @@ importers:
'@tanstack/start-storage-context':
specifier: workspace:*
version: link:../start-storage-context
+ cookie-es:
+ specifier: ^3.0.0
+ version: 3.1.1
seroval:
specifier: ^1.5.4
version: 1.5.4
@@ -21793,21 +21796,6 @@ packages:
miniflare:
optional: true
- env-runner@0.1.9:
- resolution: {integrity: sha512-W9AiZlPx0uXtghAJiTBkeZOgyQdecVvoln3cHoOEZswPq0cVMi+WBhUQjdUn+JcZFAFgOt+i5fcO7C2zniZoCg==}
- hasBin: true
- peerDependencies:
- '@netlify/runtime': ^4.1.23
- '@vercel/queue': ^0.2.0
- miniflare: ^4.20260515.0
- peerDependenciesMeta:
- '@netlify/runtime':
- optional: true
- '@vercel/queue':
- optional: true
- miniflare:
- optional: true
-
envinfo@7.14.0:
resolution: {integrity: sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==}
engines: {node: '>=4'}
@@ -22586,18 +22574,17 @@ packages:
crossws:
optional: true
- h3@2.0.1-rc.20:
- resolution: {integrity: sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg==}
+ h3@2.0.1-rc.2:
+ resolution: {integrity: sha512-2vS7OETzPDzGQxmmcs6ttu7p0NW25zAdkPXYOr43dn4GZf81uUljJvupa158mcpUGpsQUqIy4O4THWUQT1yVeA==}
engines: {node: '>=20.11.1'}
- hasBin: true
peerDependencies:
crossws: ^0.4.1
peerDependenciesMeta:
crossws:
optional: true
- h3@2.0.1-rc.22:
- resolution: {integrity: sha512-Esv0DMIuPkCTSWCA0vO73vcTqwzH1wjSrAO1TXNu/K3up1sZHa9EKMapbmxCDYBeymC3fVTk4qxp7ogQWQ+KgA==}
+ h3@2.0.1-rc.20:
+ resolution: {integrity: sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg==}
engines: {node: '>=20.11.1'}
hasBin: true
peerDependencies:
@@ -22676,9 +22663,6 @@ packages:
hookable@6.1.0:
resolution: {integrity: sha512-ZoKZSJgu8voGK2geJS+6YtYjvIzu9AOM/KZXsBxr83uhLL++e9pEv/dlgwgy3dvHg06kTz6JOh1hk3C8Ceiymw==}
- hookable@6.1.1:
- resolution: {integrity: sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==}
-
hosted-git-info@7.0.2:
resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==}
engines: {node: ^16.14.0 || >=18.0.0}
@@ -22787,9 +22771,6 @@ packages:
httpxy@0.3.1:
resolution: {integrity: sha512-XjG/CEoofEisMrnFr0D6U6xOZ4mRfnwcYQ9qvvnT4lvnX8BoeA3x3WofB75D+vZwpaobFVkBIHrZzoK40w8XSw==}
- httpxy@0.5.3:
- resolution: {integrity: sha512-SMS9V6Sn7VWaS11lYhoAr0ceoaiolTWf4jYdJn0NJhCdKMu9R2H9Fh0LBDWBHQF6HRLI1PmaePYsjanSpE5PEw==}
-
human-id@4.1.1:
resolution: {integrity: sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==}
hasBin: true
@@ -23875,45 +23856,30 @@ packages:
netlify-redirector@0.5.0:
resolution: {integrity: sha512-4zdzIP+6muqPCuE8avnrgDJ6KW/2+UpHTRcTbMXCIRxiRmyrX+IZ4WSJGZdHPWF3WmQpXpy603XxecZ9iygN7w==}
+ nf3@0.1.12:
+ resolution: {integrity: sha512-qbMXT7RTGh74MYWPeqTIED8nDW70NXOULVHpdWcdZ7IVHVnAsMV9fNugSNnvooipDc1FMOzpis7T9nXJEbJhvQ==}
+
nf3@0.3.11:
resolution: {integrity: sha512-ObKp/SA3f1g1f/OMeDlRWaZmqGgk7A0NnDIbeO7c/MV4r/quMlpP/BsqMGuTi3lUlXbC1On8YH7ICM2u2bIAOw==}
- nf3@0.3.17:
- resolution: {integrity: sha512-N9zEWySuJFw+gR0lhS5863YsvNeudOdqRyFvNb+jMXbeTJOdrjDqkCpDginIZfUm0LzT1t1nCRiDeqQm/8kirQ==}
-
nf3@0.3.6:
resolution: {integrity: sha512-/XRUUILTAyuy1XunyVQuqGp8aEmZ2TfRTn8Rji+FA4xqv20qzL4jV7Reqbuey2XucKgPeRVcEYGScmJM0UnB6Q==}
- nitro-nightly@3.0.260522-beta:
- resolution: {integrity: sha512-Pm0AiQ1nLcreUFZKJcmVI4l9K/ygXoFamIPhc44XJHj9vmt25Rlqjv55frw6sS0L1qHrySpo3xyVVBmR9aTBqA==}
+ nitro-nightly@4.0.0-20251010-091516-7cafddba:
+ resolution: {integrity: sha512-biADkmoR/Nb9OmUURTfDI2BpGo2IMEt2RbsiMhjqdwz2w3tEm+tx0Hd28LXjBCwid+l8jpqyfmpwc8jzwdng3w==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
- '@vercel/queue': ^0.2.0
- dotenv: '*'
- giget: '*'
- jiti: ^2.6.1
- rollup: ^4.60.3
+ rolldown: '*'
vite: ^8.0.14
xml2js: ^0.6.2
- zephyr-agent: ^0.2.0
peerDependenciesMeta:
- '@vercel/queue':
- optional: true
- dotenv:
- optional: true
- giget:
- optional: true
- jiti:
- optional: true
- rollup:
+ rolldown:
optional: true
vite:
optional: true
xml2js:
optional: true
- zephyr-agent:
- optional: true
nitro@3.0.1-alpha.2:
resolution: {integrity: sha512-YviDY5J/trS821qQ1fpJtpXWIdPYiOizC/meHavlm1Hfuhx//H+Egd1+4C5SegJRgtWMnRPW9n//6Woaw81cTQ==}
@@ -24117,9 +24083,6 @@ packages:
ocache@0.1.2:
resolution: {integrity: sha512-lI34wjM7cahEdrq2I5obbF7MEdE97vULf6vNj6ZCzwEadzyXO1w7QOl2qzzG4IL8cyO7wDtXPj9CqW/aG3mn7g==}
- ocache@0.1.4:
- resolution: {integrity: sha512-e7geNdWjxSnvsSgvLuPvgKgu7ubM10ZmTPOgpr7mz2BXYtvjMKTiLhjFi/gWU8chkuP6hNkZBsa9LzOusyaqkQ==}
-
ofetch@1.5.1:
resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==}
@@ -24923,6 +24886,10 @@ packages:
renderkid@3.0.0:
resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==}
+ rendu@0.0.6:
+ resolution: {integrity: sha512-nZ512Dw0MxKiIYfCVv8DPe6ig4m0Qt3FOYBJEXrammjIYBBPuHaudc0AGfYx+iyOw2q0itAtPywiVZXtTFCsig==}
+ hasBin: true
+
repeat-string@1.6.1:
resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==}
engines: {node: '>=0.10'}
@@ -25432,6 +25399,11 @@ packages:
engines: {node: '>=20.16.0'}
hasBin: true
+ srvx@0.8.16:
+ resolution: {integrity: sha512-hmcGW4CgroeSmzgF1Ihwgl+Ths0JqAJ7HwjP2X7e3JzY7u4IydLMcdnlqGQiQGUswz+PO9oh/KtCpOISIvs9QQ==}
+ engines: {node: '>=20.16.0'}
+ hasBin: true
+
stable-hash-x@0.2.0:
resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==}
engines: {node: '>=12.0.0'}
@@ -25843,6 +25815,7 @@ packages:
tsconfck@3.1.4:
resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==}
engines: {node: ^18 || >=20}
+ deprecated: unmaintained
hasBin: true
peerDependencies:
typescript: ^5.0.0
@@ -26005,6 +25978,9 @@ packages:
resolution: {integrity: sha512-uZsKNuzQxDMUY6M3pIMvy5tvlGmtq8XJ2oLAkfRKGNu+1VQAIvLy2xIVG5ATZl5wDXl/tddByAWCizRbOme+TA==}
engines: {node: '>=20.18.1'}
+ unenv@2.0.0-rc.21:
+ resolution: {integrity: sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A==}
+
unenv@2.0.0-rc.24:
resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==}
@@ -26120,32 +26096,32 @@ packages:
uploadthing:
optional: true
- unstorage@2.0.0-alpha.5:
- resolution: {integrity: sha512-Sj8btci21Twnd6M+N+MHhjg3fVn6lAPElPmvFTe0Y/wR0WImErUdA1PzlAaUavHylJ7uDiFwlZDQKm0elG4b7g==}
+ unstorage@2.0.0-alpha.3:
+ resolution: {integrity: sha512-BeoqISVh8jxqnPseHH7/92twe2VkQztrudXg8RFZVbXb4ckkFdpLk1LnNvsUndDltyodBMVxgI6V7JcbJYt2VQ==}
peerDependencies:
- '@azure/app-configuration': ^1.9.0
- '@azure/cosmos': ^4.7.0
- '@azure/data-tables': ^13.3.1
- '@azure/identity': ^4.13.0
- '@azure/keyvault-secrets': ^4.10.0
- '@azure/storage-blob': ^12.29.1
+ '@azure/app-configuration': ^1.8.0
+ '@azure/cosmos': ^4.2.0
+ '@azure/data-tables': ^13.3.0
+ '@azure/identity': ^4.6.0
+ '@azure/keyvault-secrets': ^4.9.0
+ '@azure/storage-blob': ^12.26.0
'@capacitor/preferences': ^6.0.3 || ^7.0.0
- '@deno/kv': '>=0.12.0'
+ '@deno/kv': '>=0.9.0'
'@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
'@planetscale/database': ^1.19.0
- '@upstash/redis': ^1.35.6
- '@vercel/blob': '>=0.27.3'
+ '@upstash/redis': ^1.34.3
+ '@vercel/blob': '>=0.27.1'
'@vercel/functions': ^2.2.12 || ^3.0.0
'@vercel/kv': ^1.0.1
aws4fetch: ^1.0.20
- chokidar: ^4 || ^5
- db0: '>=0.3.4'
- idb-keyval: ^6.2.2
- ioredis: ^5.8.2
+ chokidar: ^4.0.3
+ db0: '>=0.2.1'
+ idb-keyval: ^6.2.1
+ ioredis: ^5.4.2
lru-cache: ^11.2.2
- mongodb: ^6 || ^7
- ofetch: '*'
- uploadthing: ^7.7.4
+ mongodb: ^6.20.0
+ ofetch: ^1.4.1
+ uploadthing: ^7.4.4
peerDependenciesMeta:
'@azure/app-configuration':
optional: true
@@ -26194,20 +26170,20 @@ packages:
uploadthing:
optional: true
- unstorage@2.0.0-alpha.6:
- resolution: {integrity: sha512-w5vLYCJtnSx3OBtDk7cG4c1p3dfAnHA4WSZq9Xsurjbl2wMj7zqfOIjaHQI1Bl7yKzUxXAi+kbMr8iO2RhJmBA==}
+ unstorage@2.0.0-alpha.5:
+ resolution: {integrity: sha512-Sj8btci21Twnd6M+N+MHhjg3fVn6lAPElPmvFTe0Y/wR0WImErUdA1PzlAaUavHylJ7uDiFwlZDQKm0elG4b7g==}
peerDependencies:
- '@azure/app-configuration': ^1.11.0
- '@azure/cosmos': ^4.9.1
- '@azure/data-tables': ^13.3.2
+ '@azure/app-configuration': ^1.9.0
+ '@azure/cosmos': ^4.7.0
+ '@azure/data-tables': ^13.3.1
'@azure/identity': ^4.13.0
'@azure/keyvault-secrets': ^4.10.0
- '@azure/storage-blob': ^12.31.0
- '@capacitor/preferences': ^6 || ^7 || ^8
- '@deno/kv': '>=0.13.0'
+ '@azure/storage-blob': ^12.29.1
+ '@capacitor/preferences': ^6.0.3 || ^7.0.0
+ '@deno/kv': '>=0.12.0'
'@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
'@planetscale/database': ^1.19.0
- '@upstash/redis': ^1.36.2
+ '@upstash/redis': ^1.35.6
'@vercel/blob': '>=0.27.3'
'@vercel/functions': ^2.2.12 || ^3.0.0
'@vercel/kv': ^1.0.1
@@ -26215,8 +26191,8 @@ packages:
chokidar: ^4 || ^5
db0: '>=0.3.4'
idb-keyval: ^6.2.2
- ioredis: ^5.9.3
- lru-cache: ^11.2.6
+ ioredis: ^5.8.2
+ lru-cache: ^11.2.2
mongodb: ^6 || ^7
ofetch: '*'
uploadthing: ^7.7.4
@@ -26268,8 +26244,8 @@ packages:
uploadthing:
optional: true
- unstorage@2.0.0-alpha.7:
- resolution: {integrity: sha512-ELPztchk2zgFJnakyodVY3vJWGW9jy//keJ32IOJVGUMyaPydwcA1FtVvWqT0TNRch9H+cMNEGllfVFfScImog==}
+ unstorage@2.0.0-alpha.6:
+ resolution: {integrity: sha512-w5vLYCJtnSx3OBtDk7cG4c1p3dfAnHA4WSZq9Xsurjbl2wMj7zqfOIjaHQI1Bl7yKzUxXAi+kbMr8iO2RhJmBA==}
peerDependencies:
'@azure/app-configuration': ^1.11.0
'@azure/cosmos': ^4.9.1
@@ -27700,7 +27676,7 @@ snapshots:
'@bramus/specificity@2.4.2':
dependencies:
- css-tree: 3.1.0
+ css-tree: 3.2.1
'@bundled-es-modules/cookie@2.0.1':
dependencies:
@@ -27708,7 +27684,7 @@ snapshots:
'@bundled-es-modules/statuses@1.0.1':
dependencies:
- statuses: 2.0.1
+ statuses: 2.0.2
'@bundled-es-modules/tough-cookie@0.1.6':
dependencies:
@@ -28019,9 +27995,9 @@ snapshots:
'@cloudflare/workerd-windows-64@1.20260317.1':
optional: true
- '@codspeed/core@5.5.0':
+ '@codspeed/core@5.5.0(debug@4.4.3)':
dependencies:
- axios: 1.17.0
+ axios: 1.17.0(debug@4.4.3)
find-up: 6.3.0
form-data: 4.0.5
node-gyp-build: 4.8.4
@@ -28030,9 +28006,9 @@ snapshots:
- debug
- supports-color
- '@codspeed/vitest-plugin@5.5.0(tinybench@2.9.0)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))(vitest@4.1.4)':
+ '@codspeed/vitest-plugin@5.5.0(debug@4.4.3)(tinybench@2.9.0)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))(vitest@4.1.4)':
dependencies:
- '@codspeed/core': 5.5.0
+ '@codspeed/core': 5.5.0(debug@4.4.3)
tinybench: 2.9.0
vite: 8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0)
vitest: 4.1.4(@types/node@25.0.9)(@vitest/ui@4.1.4)(jsdom@29.1.1(@noble/hashes@2.0.1))(msw@2.7.0(@types/node@25.0.9)(typescript@6.0.2))(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0))
@@ -30236,13 +30212,13 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.19.0
- '@nx/devkit@22.7.5(nx@22.7.5(@swc-node/register@1.11.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@swc/core@1.15.33(@swc/helpers@0.5.23))(@swc/types@0.1.26)(typescript@6.0.2))(@swc/core@1.15.33(@swc/helpers@0.5.23)))':
+ '@nx/devkit@22.7.5(nx@22.7.5(@swc-node/register@1.11.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@swc/core@1.15.33(@swc/helpers@0.5.23))(@swc/types@0.1.26)(typescript@6.0.2))(@swc/core@1.15.33(@swc/helpers@0.5.23))(debug@4.4.3))':
dependencies:
'@zkochan/js-yaml': 0.0.7
ejs: 5.0.1
enquirer: 2.3.6
minimatch: 10.2.5
- nx: 22.7.5(@swc-node/register@1.11.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@swc/core@1.15.33(@swc/helpers@0.5.23))(@swc/types@0.1.26)(typescript@6.0.2))(@swc/core@1.15.33(@swc/helpers@0.5.23))
+ nx: 22.7.5(@swc-node/register@1.11.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@swc/core@1.15.33(@swc/helpers@0.5.23))(@swc/types@0.1.26)(typescript@6.0.2))(@swc/core@1.15.33(@swc/helpers@0.5.23))(debug@4.4.3)
semver: 7.8.2
tslib: 2.8.1
yargs-parser: 21.1.1
@@ -33551,7 +33527,7 @@ snapshots:
debug: 4.4.3
minimatch: 10.2.5
semver: 7.8.2
- tinyglobby: 0.2.15
+ tinyglobby: 0.2.16
ts-api-utils: 2.4.0(typescript@6.0.2)
typescript: 6.0.2
transitivePeerDependencies:
@@ -34050,7 +34026,7 @@ snapshots:
'@vue/compiler-core@3.5.25':
dependencies:
- '@babel/parser': 7.28.5
+ '@babel/parser': 7.29.2
'@vue/shared': 3.5.25
entities: 4.5.0
estree-walker: 2.0.2
@@ -34063,14 +34039,14 @@ snapshots:
'@vue/compiler-sfc@3.5.25':
dependencies:
- '@babel/parser': 7.28.5
+ '@babel/parser': 7.29.2
'@vue/compiler-core': 3.5.25
'@vue/compiler-dom': 3.5.25
'@vue/compiler-ssr': 3.5.25
'@vue/shared': 3.5.25
estree-walker: 2.0.2
magic-string: 0.30.21
- postcss: 8.5.8
+ postcss: 8.5.15
source-map-js: 1.2.1
'@vue/compiler-ssr@3.5.25':
@@ -34597,7 +34573,7 @@ snapshots:
aws-ssl-profiles@1.1.2: {}
- axios@1.16.0:
+ axios@1.16.0(debug@4.4.3):
dependencies:
follow-redirects: 1.16.0(debug@4.4.3)
form-data: 4.0.5
@@ -34605,7 +34581,7 @@ snapshots:
transitivePeerDependencies:
- debug
- axios@1.17.0:
+ axios@1.17.0(debug@4.4.3):
dependencies:
follow-redirects: 1.16.0(debug@4.4.3)
form-data: 4.0.5
@@ -35366,6 +35342,11 @@ snapshots:
crossws@0.4.5(srvx@0.11.15):
optionalDependencies:
srvx: 0.11.15
+ optional: true
+
+ crossws@0.4.5(srvx@0.8.16):
+ optionalDependencies:
+ srvx: 0.8.16
css-loader@7.1.2(webpack@5.97.1):
dependencies:
@@ -35826,13 +35807,6 @@ snapshots:
optionalDependencies:
miniflare: 4.20260317.0
- env-runner@0.1.9:
- dependencies:
- crossws: 0.4.5(srvx@0.11.15)
- exsolve: 1.0.8
- httpxy: 0.5.3
- srvx: 0.11.15
-
envinfo@7.14.0: {}
environment@1.1.0: {}
@@ -36946,14 +36920,16 @@ snapshots:
optionalDependencies:
crossws: 0.4.4(srvx@0.11.15)
- h3@2.0.1-rc.20(crossws@0.4.5(srvx@0.11.15)):
+ h3@2.0.1-rc.2(crossws@0.4.5(srvx@0.8.16)):
dependencies:
- rou3: 0.8.1
- srvx: 0.11.15
+ cookie-es: 2.0.0
+ fetchdts: 0.1.7
+ rou3: 0.7.12
+ srvx: 0.8.16
optionalDependencies:
- crossws: 0.4.5(srvx@0.11.15)
+ crossws: 0.4.5(srvx@0.8.16)
- h3@2.0.1-rc.22(crossws@0.4.5(srvx@0.11.15)):
+ h3@2.0.1-rc.20(crossws@0.4.5(srvx@0.11.15)):
dependencies:
rou3: 0.8.1
srvx: 0.11.15
@@ -37014,8 +36990,6 @@ snapshots:
hookable@6.1.0: {}
- hookable@6.1.1: {}
-
hosted-git-info@7.0.2:
dependencies:
lru-cache: 10.4.3
@@ -37166,8 +37140,6 @@ snapshots:
httpxy@0.3.1: {}
- httpxy@0.5.3: {}
-
human-id@4.1.1: {}
human-signals@5.0.0: {}
@@ -37281,7 +37253,7 @@ snapshots:
pathe: 2.0.3
sharp: 0.34.4
svgo: 4.0.0
- ufo: 1.6.1
+ ufo: 1.6.3
unstorage: 1.17.4(@netlify/blobs@10.1.0)(db0@0.3.4(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(mysql2@3.15.3))(ioredis@5.9.2)
xss: 1.0.15
transitivePeerDependencies:
@@ -38241,32 +38213,33 @@ snapshots:
netlify-redirector@0.5.0: {}
- nf3@0.3.11: {}
+ nf3@0.1.12: {}
- nf3@0.3.17: {}
+ nf3@0.3.11: {}
nf3@0.3.6: {}
- nitro-nightly@3.0.260522-beta(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(@netlify/blobs@10.1.0)(chokidar@5.0.0)(dotenv@17.4.2)(giget@2.0.0)(jiti@2.7.0)(lru-cache@11.5.1)(mysql2@3.15.3)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0)):
+ nitro-nightly@4.0.0-20251010-091516-7cafddba(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(@netlify/blobs@10.1.0)(chokidar@4.0.3)(ioredis@5.9.2)(lru-cache@11.5.1)(mysql2@3.15.3)(rolldown@1.0.2)(vite@8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0)):
dependencies:
consola: 3.4.2
- crossws: 0.4.5(srvx@0.11.15)
+ cookie-es: 2.0.0
+ crossws: 0.4.5(srvx@0.8.16)
db0: 0.3.4(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(mysql2@3.15.3)
- env-runner: 0.1.9
- h3: 2.0.1-rc.22(crossws@0.4.5(srvx@0.11.15))
- hookable: 6.1.1
- nf3: 0.3.17
- ocache: 0.1.4
- ofetch: 2.0.0-alpha.3
+ esbuild: 0.25.10
+ fetchdts: 0.1.7
+ h3: 2.0.1-rc.2(crossws@0.4.5(srvx@0.8.16))
+ jiti: 2.7.0
+ nf3: 0.1.12
+ ofetch: 1.5.1
ohash: 2.0.11
- rolldown: 1.0.2
- srvx: 0.11.15
- unenv: 2.0.0-rc.24
- unstorage: 2.0.0-alpha.7(@netlify/blobs@10.1.0)(chokidar@5.0.0)(db0@0.3.4(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(mysql2@3.15.3))(lru-cache@11.5.1)(ofetch@2.0.0-alpha.3)
+ rendu: 0.0.6
+ rollup: 4.56.0
+ srvx: 0.8.16
+ undici: 7.27.2
+ unenv: 2.0.0-rc.21
+ unstorage: 2.0.0-alpha.3(@netlify/blobs@10.1.0)(chokidar@4.0.3)(db0@0.3.4(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(mysql2@3.15.3))(ioredis@5.9.2)(lru-cache@11.5.1)(ofetch@1.5.1)
optionalDependencies:
- dotenv: 17.4.2
- giget: 2.0.0
- jiti: 2.7.0
+ rolldown: 1.0.2
vite: 8.0.14(@types/node@25.0.9)(esbuild@0.27.4)(jiti@2.7.0)(sass@1.97.2)(terser@5.37.0)(tsx@4.20.3)(yaml@2.9.0)
transitivePeerDependencies:
- '@azure/app-configuration'
@@ -38280,7 +38253,6 @@ snapshots:
- '@electric-sql/pglite'
- '@libsql/client'
- '@netlify/blobs'
- - '@netlify/runtime'
- '@planetscale/database'
- '@upstash/redis'
- '@vercel/blob'
@@ -38293,7 +38265,6 @@ snapshots:
- idb-keyval
- ioredis
- lru-cache
- - miniflare
- mongodb
- mysql2
- sqlite3
@@ -38585,7 +38556,7 @@ snapshots:
nwsapi@2.2.16: {}
- nx@22.7.5(@swc-node/register@1.11.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@swc/core@1.15.33(@swc/helpers@0.5.23))(@swc/types@0.1.26)(typescript@6.0.2))(@swc/core@1.15.33(@swc/helpers@0.5.23)):
+ nx@22.7.5(@swc-node/register@1.11.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@swc/core@1.15.33(@swc/helpers@0.5.23))(@swc/types@0.1.26)(typescript@6.0.2))(@swc/core@1.15.33(@swc/helpers@0.5.23))(debug@4.4.3):
dependencies:
'@emnapi/core': 1.4.5
'@emnapi/runtime': 1.4.5
@@ -38600,7 +38571,7 @@ snapshots:
ansi-styles: 4.3.0
argparse: 2.0.1
asynckit: 0.4.0
- axios: 1.16.0
+ axios: 1.16.0(debug@4.4.3)
balanced-match: 4.0.3
base64-js: 1.5.1
bl: 4.1.0
@@ -38751,10 +38722,6 @@ snapshots:
dependencies:
ohash: 2.0.11
- ocache@0.1.4:
- dependencies:
- ohash: 2.0.11
-
ofetch@1.5.1:
dependencies:
destr: 2.0.5
@@ -39697,6 +39664,11 @@ snapshots:
lodash: 4.17.21
strip-ansi: 6.0.1
+ rendu@0.0.6:
+ dependencies:
+ cookie-es: 2.0.0
+ srvx: 0.8.16
+
repeat-string@1.6.1: {}
require-directory@2.1.1: {}
@@ -40329,6 +40301,8 @@ snapshots:
srvx@0.11.15: {}
+ srvx@0.8.16: {}
+
stable-hash-x@0.2.0: {}
stack-trace@0.0.10: {}
@@ -40850,6 +40824,14 @@ snapshots:
undici@7.27.2: {}
+ unenv@2.0.0-rc.21:
+ dependencies:
+ defu: 6.1.4
+ exsolve: 1.0.8
+ ohash: 2.0.11
+ pathe: 2.0.3
+ ufo: 1.6.3
+
unenv@2.0.0-rc.24:
dependencies:
pathe: 2.0.3
@@ -40951,24 +40933,25 @@ snapshots:
db0: 0.3.4(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(mysql2@3.15.3)
ioredis: 5.9.2
- unstorage@2.0.0-alpha.5(@netlify/blobs@10.1.0)(chokidar@5.0.0)(db0@0.3.4(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(mysql2@3.15.3))(ioredis@5.9.2)(lru-cache@11.5.1)(ofetch@2.0.0-alpha.3):
+ unstorage@2.0.0-alpha.3(@netlify/blobs@10.1.0)(chokidar@4.0.3)(db0@0.3.4(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(mysql2@3.15.3))(ioredis@5.9.2)(lru-cache@11.5.1)(ofetch@1.5.1):
optionalDependencies:
'@netlify/blobs': 10.1.0
- chokidar: 5.0.0
+ chokidar: 4.0.3
db0: 0.3.4(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(mysql2@3.15.3)
ioredis: 5.9.2
lru-cache: 11.5.1
- ofetch: 2.0.0-alpha.3
+ ofetch: 1.5.1
- unstorage@2.0.0-alpha.6(@netlify/blobs@10.1.0)(chokidar@5.0.0)(db0@0.3.4(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(mysql2@3.15.3))(lru-cache@11.5.1)(ofetch@2.0.0-alpha.3):
+ unstorage@2.0.0-alpha.5(@netlify/blobs@10.1.0)(chokidar@5.0.0)(db0@0.3.4(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(mysql2@3.15.3))(ioredis@5.9.2)(lru-cache@11.5.1)(ofetch@2.0.0-alpha.3):
optionalDependencies:
'@netlify/blobs': 10.1.0
chokidar: 5.0.0
db0: 0.3.4(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(mysql2@3.15.3)
+ ioredis: 5.9.2
lru-cache: 11.5.1
ofetch: 2.0.0-alpha.3
- unstorage@2.0.0-alpha.7(@netlify/blobs@10.1.0)(chokidar@5.0.0)(db0@0.3.4(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(mysql2@3.15.3))(lru-cache@11.5.1)(ofetch@2.0.0-alpha.3):
+ unstorage@2.0.0-alpha.6(@netlify/blobs@10.1.0)(chokidar@5.0.0)(db0@0.3.4(@electric-sql/pglite@0.3.2)(@libsql/client@0.15.15)(mysql2@3.15.3))(lru-cache@11.5.1)(ofetch@2.0.0-alpha.3):
optionalDependencies:
'@netlify/blobs': 10.1.0
chokidar: 5.0.0