@reckona/mreact-router 0.0.179 → 0.0.180

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cache.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\n\n/**\n * Describes the cache lifetime assigned to a rendered route response.\n */\nexport interface RouteCachePolicy {\n cacheControl: string;\n revalidateSeconds: number;\n}\n\n/**\n * Configures cache-control directives for route response caching.\n */\nexport interface CacheControlOptions {\n maxAge?: number | undefined;\n sMaxAge?: number | undefined;\n staleWhileRevalidate?: boolean | number | undefined;\n}\n\n/**\n * Stores a cached route response body and its expiration metadata.\n */\nexport interface AppRouterCacheEntry {\n body: string;\n cacheControl: string;\n expiresAt: number;\n path: string;\n status: number;\n}\n\n/**\n * Defines the storage interface used by app-router route response caching.\n */\nexport interface AppRouterCache {\n deleteByPath(path: string): void | Promise<void>;\n get(\n key: string,\n now?: number,\n ): AppRouterCacheEntry | undefined | Promise<AppRouterCacheEntry | undefined>;\n set(key: string, entry: AppRouterCacheEntry): void | Promise<void>;\n}\n\n/**\n * Configures the process-local in-memory route cache implementation.\n */\nexport interface MemoryRouteCacheOptions {\n maxEntries?: number;\n sweepIntervalMs?: number;\n}\n\ninterface AppRouterCacheState {\n activeContexts: RouteCacheContext[];\n invalidatedPaths: Set<string>;\n memoryCache: AppRouterCache;\n storage: AsyncLocalStorage<RouteCacheContext>;\n}\n\ninterface RouteCacheContext {\n cache: AppRouterCache;\n cachePolicy?: RouteCachePolicy | undefined;\n revalidatedPaths: Set<string>;\n}\n\nconst cacheState = ((\n globalThis as { __mreactAppRouterCache?: AppRouterCacheState }\n).__mreactAppRouterCache ??= {\n activeContexts: [],\n invalidatedPaths: new Set(),\n memoryCache: createMemoryRouteCache(),\n storage: new AsyncLocalStorage<RouteCacheContext>(),\n});\ncacheState.storage ??= new AsyncLocalStorage<RouteCacheContext>();\n\n/**\n * Creates an in-memory route response cache for app-router rendering.\n *\n * The cache is process-local, evicts expired entries during reads/writes, and is suitable for development, tests, or single-process deployments that do not need shared invalidation.\n */\nexport function createMemoryRouteCache(options: MemoryRouteCacheOptions = {}): AppRouterCache {\n const maxEntries = positiveIntegerOrDefault(options.maxEntries, 10_000);\n const sweepIntervalMs = nonNegativeIntegerOrDefault(options.sweepIntervalMs, 60_000);\n const cachedRoutes = new Map<string, AppRouterCacheEntry>();\n const keysByPath = new Map<string, Set<string>>();\n let nextSweepAt = 0;\n\n function unindexKey(key: string, path: string): void {\n const keys = keysByPath.get(path);\n keys?.delete(key);\n\n if (keys?.size === 0) {\n keysByPath.delete(path);\n }\n }\n\n function deleteEntry(key: string): void {\n const entry = cachedRoutes.get(key);\n cachedRoutes.delete(key);\n\n if (entry !== undefined) {\n unindexKey(key, entry.path);\n }\n }\n\n function indexKey(key: string, path: string): void {\n const keys = keysByPath.get(path);\n\n if (keys === undefined) {\n keysByPath.set(path, new Set([key]));\n return;\n }\n\n keys.add(key);\n }\n\n function sweepExpired(now: number): void {\n for (const [key, entry] of cachedRoutes) {\n if (entry.expiresAt <= now) {\n deleteEntry(key);\n }\n }\n\n nextSweepAt = now + sweepIntervalMs;\n }\n\n function maybeSweepExpired(now: number): void {\n if (sweepIntervalMs === 0 || now >= nextSweepAt) {\n sweepExpired(now);\n }\n }\n\n function evictOldestEntries(): void {\n while (cachedRoutes.size > maxEntries) {\n const oldestKey = cachedRoutes.keys().next().value;\n\n if (oldestKey === undefined) {\n return;\n }\n\n deleteEntry(oldestKey);\n }\n }\n\n return {\n deleteByPath(path) {\n const normalizedPath = normalizeRevalidationPath(path);\n const keys = keysByPath.get(normalizedPath);\n\n if (keys === undefined) {\n return;\n }\n\n for (const key of keys) {\n cachedRoutes.delete(key);\n }\n\n keysByPath.delete(normalizedPath);\n },\n get(key, now = Date.now()) {\n const entry = cachedRoutes.get(key);\n\n if (entry === undefined) {\n return undefined;\n }\n\n if (entry.expiresAt <= now) {\n deleteEntry(key);\n return undefined;\n }\n\n return entry;\n },\n set(key, entry) {\n const now = Date.now();\n maybeSweepExpired(now);\n const previous = cachedRoutes.get(key);\n\n if (previous !== undefined) {\n cachedRoutes.delete(key);\n unindexKey(key, previous.path);\n }\n\n cachedRoutes.set(key, entry);\n indexKey(key, entry.path);\n\n if (cachedRoutes.size > maxEntries) {\n sweepExpired(now);\n evictOldestEntries();\n }\n },\n };\n}\n\nfunction positiveIntegerOrDefault(value: number | undefined, fallback: number): number {\n return value === undefined || !Number.isInteger(value) || value < 1 ? fallback : value;\n}\n\nfunction nonNegativeIntegerOrDefault(value: number | undefined, fallback: number): number {\n return value === undefined || !Number.isInteger(value) || value < 0 ? fallback : value;\n}\n\nexport function routeCachePolicyFromSource(code: string): RouteCachePolicy | undefined {\n const match = /^\\s*export\\s+const\\s+revalidate\\s*=\\s*(?<seconds>\\d+)\\s*;?\\s*$/m.exec(code);\n const seconds = match?.groups?.seconds === undefined ? undefined : Number(match.groups.seconds);\n\n if (seconds === undefined || !Number.isFinite(seconds)) {\n return undefined;\n }\n\n return {\n cacheControl: seconds === 0 ? \"no-store\" : `s-maxage=${seconds}, stale-while-revalidate`,\n revalidateSeconds: seconds,\n };\n}\n\n/**\n * Sets the cache policy for the current app-router render.\n *\n * Call this during a loader or route render to override the response `Cache-Control` policy; it throws outside an active app-router request.\n */\nexport function cacheControl(options: CacheControlOptions): void {\n const activeContext = activeRouteCacheContext();\n\n if (activeContext === undefined) {\n throw new Error(\"cacheControl() must be called during an app router request.\");\n }\n\n activeContext.cachePolicy = routeCachePolicyFromOptions(options);\n}\n\nexport function routeCachePolicyFromOptions(options: CacheControlOptions): RouteCachePolicy {\n const directives: string[] = [];\n const maxAge = cacheControlSeconds(options.maxAge, \"maxAge\");\n const sMaxAge = cacheControlSeconds(options.sMaxAge, \"sMaxAge\");\n\n if (maxAge !== undefined) {\n directives.push(`max-age=${maxAge}`);\n }\n\n if (sMaxAge !== undefined) {\n directives.push(`s-maxage=${sMaxAge}`);\n }\n\n if (options.staleWhileRevalidate !== undefined) {\n directives.push(staleWhileRevalidateDirective(options.staleWhileRevalidate));\n }\n\n if (directives.length === 0) {\n throw new Error(\"cacheControl() requires at least one cache directive.\");\n }\n\n return {\n cacheControl: directives.join(\", \"),\n revalidateSeconds: sMaxAge ?? 0,\n };\n}\n\nexport function cachedRouteResponse(options: {\n cache?: AppRouterCache | undefined;\n key: string;\n now?: number;\n request?: Request | undefined;\n}): Promise<Response | undefined> {\n return Promise.resolve().then(async () => {\n if (requestCarriesCredentials(options.request)) {\n return undefined;\n }\n\n const cache = options.cache ?? cacheState.memoryCache;\n\n await consumeInvalidations(cache);\n const now = options.now ?? Date.now();\n const cached = await cache.get(options.key, now);\n\n if (cached === undefined || cached.expiresAt <= now) {\n return undefined;\n }\n\n return new Response(cached.body, {\n headers: {\n \"cache-control\": cached.cacheControl,\n \"content-type\": \"text/html; charset=utf-8\",\n \"x-mreact-cache\": \"HIT\",\n },\n status: cached.status,\n });\n });\n}\n\nexport async function cacheRouteResponse(options: {\n cache?: AppRouterCache | undefined;\n key: string;\n now?: number;\n path: string;\n policy: RouteCachePolicy | undefined;\n request?: Request | undefined;\n response: Response;\n}): Promise<Response> {\n if (options.policy === undefined) {\n return options.response;\n }\n\n if (options.policy.revalidateSeconds === 0) {\n options.response.headers.set(\"cache-control\", options.policy.cacheControl);\n return options.response;\n }\n\n const body = await options.response.text();\n const cacheControl = options.policy.cacheControl;\n const status = options.response.status;\n const contentType = options.response.headers.get(\"content-type\") ?? \"text/html; charset=utf-8\";\n\n if (\n requestCarriesCredentials(options.request) ||\n options.response.headers.has(\"set-cookie\")\n ) {\n const headers = new Headers(options.response.headers);\n headers.set(\"cache-control\", \"private, no-store\");\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", contentType);\n }\n\n return new Response(body, {\n headers,\n status,\n });\n }\n\n await (options.cache ?? cacheState.memoryCache).set(options.key, {\n body,\n cacheControl,\n expiresAt: (options.now ?? Date.now()) + options.policy.revalidateSeconds * 1000,\n path: normalizeRevalidationPath(options.path),\n status,\n });\n\n return new Response(body, {\n headers: {\n \"cache-control\": cacheControl,\n \"content-type\": contentType,\n \"x-mreact-cache\": \"MISS\",\n },\n status,\n });\n}\n\nfunction requestCarriesCredentials(request: Request | undefined): boolean {\n if (request === undefined) {\n return false;\n }\n\n return request.headers.has(\"authorization\") || request.headers.has(\"cookie\");\n}\n\n/**\n * Invalidates cached route responses for a normalized app-router path.\n *\n * During a request the invalidation is scoped to that route cache context; outside a request it is queued for the next cache access.\n */\nexport function revalidatePath(path: string): void {\n const normalizedPath = normalizeRevalidationPath(path);\n const activeContext = activeRouteCacheContext();\n\n if (activeContext !== undefined) {\n activeContext.revalidatedPaths.add(normalizedPath);\n return;\n }\n\n cacheState.invalidatedPaths.add(normalizedPath);\n}\n\nexport async function consumeInvalidations(\n cache: AppRouterCache = cacheState.memoryCache,\n): Promise<void> {\n if (cacheState.invalidatedPaths.size === 0) {\n return;\n }\n\n for (const path of cacheState.invalidatedPaths) {\n await cache.deleteByPath(path);\n }\n\n cacheState.invalidatedPaths.clear();\n}\n\nexport async function withRouteCacheContext<T>(\n cache: AppRouterCache | undefined,\n fn: () => T | Promise<T>,\n): Promise<{ cachePolicy: RouteCachePolicy | undefined; revalidatedPaths: string[]; value: T }> {\n const context: RouteCacheContext = {\n cache: cache ?? cacheState.memoryCache,\n revalidatedPaths: new Set(),\n };\n\n return cacheState.storage.run(context, async () => {\n const value = await fn();\n const cachePolicy = context.cachePolicy;\n const revalidatedPaths = Array.from(context.revalidatedPaths);\n\n for (const path of revalidatedPaths) {\n await context.cache.deleteByPath(path);\n }\n\n return { cachePolicy, revalidatedPaths, value };\n });\n}\n\nexport function beginRouteCacheContext(cache: AppRouterCache | undefined): {\n readonly cachePolicy: RouteCachePolicy | undefined;\n dispose(): Promise<{ revalidatedPaths: string[] }>;\n} {\n const context: RouteCacheContext = {\n cache: cache ?? cacheState.memoryCache,\n revalidatedPaths: new Set(),\n };\n\n cacheState.activeContexts.push(context);\n\n return {\n get cachePolicy() {\n return context.cachePolicy;\n },\n async dispose() {\n const revalidatedPaths = Array.from(context.revalidatedPaths);\n\n for (const path of revalidatedPaths) {\n await context.cache.deleteByPath(path);\n }\n\n const index = cacheState.activeContexts.lastIndexOf(context);\n if (index !== -1) {\n cacheState.activeContexts.splice(index, 1);\n }\n\n return { revalidatedPaths };\n },\n };\n}\n\nfunction activeRouteCacheContext(): RouteCacheContext | undefined {\n return cacheState.storage.getStore() ?? cacheState.activeContexts.at(-1);\n}\n\n// Host is excluded from the cache key to prevent attacker-supplied Host\n// headers from fragmenting / poisoning the cache (Issue 068). The Vary\n// dimension is the request path + query; same-origin reverse proxies are\n// expected to handle vhost separation at their layer.\nexport function routeCacheKey(appDir: string, routePath: string, url: URL): string {\n return `${appDir}\\0${normalizeRevalidationPath(routePath)}\\0${url.pathname}${url.search}`;\n}\n\nexport function stripRevalidateExport(code: string): string {\n return code.replace(/^\\s*export\\s+const\\s+revalidate\\s*=\\s*\\d+\\s*;?\\s*$/m, \"\");\n}\n\nfunction normalizeRevalidationPath(path: string): string {\n const pathname = path.startsWith(\"/\") ? path : `/${path}`;\n const withoutTrailing = pathname.length > 1 ? pathname.replace(/\\/+$/, \"\") : pathname;\n\n return withoutTrailing === \"\" ? \"/\" : withoutTrailing;\n}\n\nfunction cacheControlSeconds(value: number | undefined, name: string): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new Error(`cacheControl() ${name} must be a non-negative integer.`);\n }\n\n return value;\n}\n\nfunction staleWhileRevalidateDirective(value: boolean | number): string {\n if (value === true) {\n return \"stale-while-revalidate\";\n }\n\n if (value === false) {\n throw new Error(\"cacheControl() staleWhileRevalidate must be true or a non-negative integer.\");\n }\n\n const seconds = cacheControlSeconds(value, \"staleWhileRevalidate\");\n return `stale-while-revalidate=${seconds}`;\n}\n"]}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\n\n/**\n * Describes the cache lifetime assigned to a rendered route response.\n */\nexport interface RouteCachePolicy {\n cacheControl: string;\n revalidateSeconds: number;\n}\n\n/**\n * Configures cache-control directives for route response caching.\n */\nexport interface CacheControlOptions {\n maxAge?: number | undefined;\n sMaxAge?: number | undefined;\n staleWhileRevalidate?: boolean | number | undefined;\n}\n\n/**\n * Stores a cached route response body and its expiration metadata.\n */\nexport interface AppRouterCacheEntry {\n body: string;\n cacheControl: string;\n expiresAt: number;\n path: string;\n status: number;\n}\n\n/**\n * Defines the storage interface used by app-router route response caching.\n */\nexport interface AppRouterCache {\n deleteByPath(path: string): void | Promise<void>;\n get(\n key: string,\n now?: number,\n ): AppRouterCacheEntry | undefined | Promise<AppRouterCacheEntry | undefined>;\n set(key: string, entry: AppRouterCacheEntry): void | Promise<void>;\n}\n\n/**\n * Configures the process-local in-memory route cache implementation.\n */\nexport interface MemoryRouteCacheOptions {\n maxEntries?: number;\n sweepIntervalMs?: number;\n}\n\ninterface AppRouterCacheState {\n activeContexts: RouteCacheContext[];\n invalidatedPaths: Set<string>;\n memoryCache: AppRouterCache;\n storage: AsyncLocalStorage<RouteCacheContext>;\n}\n\ninterface RouteCacheContext {\n cache: AppRouterCache;\n cachePolicy?: RouteCachePolicy | undefined;\n revalidatedPaths: Set<string>;\n}\n\nconst cacheState = ((\n globalThis as { __mreactAppRouterCache?: AppRouterCacheState }\n).__mreactAppRouterCache ??= {\n activeContexts: [],\n invalidatedPaths: new Set(),\n memoryCache: createMemoryRouteCache(),\n storage: new AsyncLocalStorage<RouteCacheContext>(),\n});\ncacheState.storage ??= new AsyncLocalStorage<RouteCacheContext>();\n\n/**\n * Creates an in-memory route response cache for app-router rendering.\n *\n * The cache is process-local, evicts expired entries during reads/writes, and is suitable for development, tests, or single-process deployments that do not need shared invalidation.\n */\nexport function createMemoryRouteCache(options: MemoryRouteCacheOptions = {}): AppRouterCache {\n const maxEntries = positiveIntegerOrDefault(options.maxEntries, 10_000);\n const sweepIntervalMs = nonNegativeIntegerOrDefault(options.sweepIntervalMs, 60_000);\n const cachedRoutes = new Map<string, AppRouterCacheEntry>();\n const keysByPath = new Map<string, Set<string>>();\n let nextSweepAt = 0;\n\n function unindexKey(key: string, path: string): void {\n const keys = keysByPath.get(path);\n keys?.delete(key);\n\n if (keys?.size === 0) {\n keysByPath.delete(path);\n }\n }\n\n function deleteEntry(key: string): void {\n const entry = cachedRoutes.get(key);\n cachedRoutes.delete(key);\n\n if (entry !== undefined) {\n unindexKey(key, entry.path);\n }\n }\n\n function indexKey(key: string, path: string): void {\n const keys = keysByPath.get(path);\n\n if (keys === undefined) {\n keysByPath.set(path, new Set([key]));\n return;\n }\n\n keys.add(key);\n }\n\n function sweepExpired(now: number): void {\n for (const [key, entry] of cachedRoutes) {\n if (entry.expiresAt <= now) {\n deleteEntry(key);\n }\n }\n\n nextSweepAt = now + sweepIntervalMs;\n }\n\n function maybeSweepExpired(now: number): void {\n if (sweepIntervalMs === 0 || now >= nextSweepAt) {\n sweepExpired(now);\n }\n }\n\n function evictOldestEntries(): void {\n while (cachedRoutes.size > maxEntries) {\n const oldestKey = cachedRoutes.keys().next().value;\n\n if (oldestKey === undefined) {\n return;\n }\n\n deleteEntry(oldestKey);\n }\n }\n\n return {\n deleteByPath(path) {\n const normalizedPath = normalizeRevalidationPath(path);\n const keys = keysByPath.get(normalizedPath);\n\n if (keys === undefined) {\n return;\n }\n\n for (const key of keys) {\n cachedRoutes.delete(key);\n }\n\n keysByPath.delete(normalizedPath);\n },\n get(key, now = Date.now()) {\n const entry = cachedRoutes.get(key);\n\n if (entry === undefined) {\n return undefined;\n }\n\n if (entry.expiresAt <= now) {\n deleteEntry(key);\n return undefined;\n }\n\n return entry;\n },\n set(key, entry) {\n const now = Date.now();\n maybeSweepExpired(now);\n const previous = cachedRoutes.get(key);\n\n if (previous !== undefined) {\n cachedRoutes.delete(key);\n unindexKey(key, previous.path);\n }\n\n cachedRoutes.set(key, entry);\n indexKey(key, entry.path);\n\n if (cachedRoutes.size > maxEntries) {\n sweepExpired(now);\n evictOldestEntries();\n }\n },\n };\n}\n\nfunction positiveIntegerOrDefault(value: number | undefined, fallback: number): number {\n return value === undefined || !Number.isInteger(value) || value < 1 ? fallback : value;\n}\n\nfunction nonNegativeIntegerOrDefault(value: number | undefined, fallback: number): number {\n return value === undefined || !Number.isInteger(value) || value < 0 ? fallback : value;\n}\n\nexport function routeCachePolicyFromSource(code: string): RouteCachePolicy | undefined {\n const match = /^\\s*export\\s+const\\s+revalidate\\s*=\\s*(?<seconds>\\d+)\\s*;?\\s*$/m.exec(code);\n const seconds = match?.groups?.seconds === undefined ? undefined : Number(match.groups.seconds);\n\n if (seconds === undefined || !Number.isFinite(seconds)) {\n return undefined;\n }\n\n return {\n cacheControl: seconds === 0 ? \"no-store\" : `s-maxage=${seconds}, stale-while-revalidate`,\n revalidateSeconds: seconds,\n };\n}\n\n/**\n * Sets the cache policy for the current app-router render.\n *\n * Call this during a loader or route render to override the response `Cache-Control` policy; it throws outside an active app-router request.\n */\nexport function cacheControl(options: CacheControlOptions): void {\n const activeContext = activeRouteCacheContext();\n\n if (activeContext === undefined) {\n throw new Error(\"cacheControl() must be called during an app router request.\");\n }\n\n activeContext.cachePolicy = routeCachePolicyFromOptions(options);\n}\n\nexport function routeCachePolicyFromOptions(options: CacheControlOptions): RouteCachePolicy {\n const directives: string[] = [];\n const maxAge = cacheControlSeconds(options.maxAge, \"maxAge\");\n const sMaxAge = cacheControlSeconds(options.sMaxAge, \"sMaxAge\");\n\n if (maxAge !== undefined) {\n directives.push(`max-age=${maxAge}`);\n }\n\n if (sMaxAge !== undefined) {\n directives.push(`s-maxage=${sMaxAge}`);\n }\n\n if (options.staleWhileRevalidate !== undefined) {\n directives.push(staleWhileRevalidateDirective(options.staleWhileRevalidate));\n }\n\n if (directives.length === 0) {\n throw new Error(\"cacheControl() requires at least one cache directive.\");\n }\n\n return {\n cacheControl: directives.join(\", \"),\n revalidateSeconds: sMaxAge ?? 0,\n };\n}\n\nexport function cachedRouteResponse(options: {\n cache?: AppRouterCache | undefined;\n key: string;\n now?: number;\n request?: Request | undefined;\n}): Promise<Response | undefined> {\n return Promise.resolve().then(async () => {\n if (requestCarriesCredentials(options.request)) {\n return undefined;\n }\n\n const cache = options.cache ?? cacheState.memoryCache;\n\n await consumeInvalidations(cache);\n const now = options.now ?? Date.now();\n const cached = await cache.get(options.key, now);\n\n if (cached === undefined || cached.expiresAt <= now) {\n return undefined;\n }\n\n return new Response(cached.body, {\n headers: {\n \"cache-control\": cached.cacheControl,\n \"content-type\": \"text/html; charset=utf-8\",\n \"x-mreact-cache\": \"HIT\",\n },\n status: cached.status,\n });\n });\n}\n\nexport async function cacheRouteResponse(options: {\n cache?: AppRouterCache | undefined;\n key: string;\n now?: number;\n path: string;\n policy: RouteCachePolicy | undefined;\n request?: Request | undefined;\n response: Response;\n}): Promise<Response> {\n if (options.policy === undefined) {\n return options.response;\n }\n\n if (options.policy.revalidateSeconds === 0) {\n options.response.headers.set(\"cache-control\", options.policy.cacheControl);\n return options.response;\n }\n\n const body = await options.response.text();\n const cacheControl = options.policy.cacheControl;\n const status = options.response.status;\n const contentType = options.response.headers.get(\"content-type\") ?? \"text/html; charset=utf-8\";\n\n if (\n requestCarriesCredentials(options.request) ||\n options.response.headers.has(\"set-cookie\")\n ) {\n const headers = new Headers(options.response.headers);\n headers.set(\"cache-control\", \"private, no-store\");\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", contentType);\n }\n\n return new Response(body, {\n headers,\n status,\n });\n }\n\n await (options.cache ?? cacheState.memoryCache).set(options.key, {\n body,\n cacheControl,\n expiresAt: (options.now ?? Date.now()) + options.policy.revalidateSeconds * 1000,\n path: normalizeRevalidationPath(options.path),\n status,\n });\n\n return new Response(body, {\n headers: {\n \"cache-control\": cacheControl,\n \"content-type\": contentType,\n \"x-mreact-cache\": \"MISS\",\n },\n status,\n });\n}\n\nfunction requestCarriesCredentials(request: Request | undefined): boolean {\n if (request === undefined) {\n return false;\n }\n\n if (request.headers.has(\"authorization\") || request.headers.has(\"cookie\")) {\n return true;\n }\n\n for (const name of request.headers.keys()) {\n const lower = name.toLowerCase();\n if (PUBLIC_ROUTE_CACHE_REQUEST_HEADERS.has(lower)) {\n continue;\n }\n\n if (\n lower === \"x-api-key\" ||\n lower === \"cf-access-jwt-assertion\" ||\n lower === \"proxy-authorization\" ||\n lower === \"x-auth-token\" ||\n lower === \"x-authenticated-user\" ||\n lower === \"x-forwarded-user\" ||\n lower === \"x-session-id\" ||\n lower === \"x-user-email\" ||\n lower === \"x-user-id\" ||\n lower.endsWith(\"-api-key\") ||\n lower.endsWith(\"-auth-token\") ||\n lower.endsWith(\"-session-id\") ||\n lower.endsWith(\"-user\") ||\n lower.endsWith(\"-user-email\") ||\n lower.endsWith(\"-user-id\") ||\n lower.includes(\"-jwt-\") ||\n lower.endsWith(\"-jwt\")\n ) {\n return true;\n }\n\n return true;\n }\n\n return false;\n}\n\nconst PUBLIC_ROUTE_CACHE_REQUEST_HEADERS = new Set([\n \"accept\",\n \"accept-encoding\",\n \"accept-language\",\n \"cache-control\",\n \"connection\",\n \"dnt\",\n \"host\",\n \"pragma\",\n \"purpose\",\n \"referer\",\n \"sec-ch-prefers-color-scheme\",\n \"sec-ch-prefers-reduced-motion\",\n \"sec-ch-ua\",\n \"sec-ch-ua-mobile\",\n \"sec-ch-ua-platform\",\n \"sec-fetch-dest\",\n \"sec-fetch-mode\",\n \"sec-fetch-site\",\n \"sec-fetch-user\",\n \"upgrade-insecure-requests\",\n \"user-agent\",\n \"x-mreact-navigation\",\n \"x-mreact-navigation-cache\",\n]);\n\n/**\n * Invalidates cached route responses for a normalized app-router path.\n *\n * During a request the invalidation is scoped to that route cache context; outside a request it is queued for the next cache access.\n */\nexport function revalidatePath(path: string): void {\n const normalizedPath = normalizeRevalidationPath(path);\n const activeContext = activeRouteCacheContext();\n\n if (activeContext !== undefined) {\n activeContext.revalidatedPaths.add(normalizedPath);\n return;\n }\n\n cacheState.invalidatedPaths.add(normalizedPath);\n}\n\nexport async function consumeInvalidations(\n cache: AppRouterCache = cacheState.memoryCache,\n): Promise<void> {\n if (cacheState.invalidatedPaths.size === 0) {\n return;\n }\n\n for (const path of cacheState.invalidatedPaths) {\n await cache.deleteByPath(path);\n }\n\n cacheState.invalidatedPaths.clear();\n}\n\nexport async function withRouteCacheContext<T>(\n cache: AppRouterCache | undefined,\n fn: () => T | Promise<T>,\n): Promise<{ cachePolicy: RouteCachePolicy | undefined; revalidatedPaths: string[]; value: T }> {\n const context: RouteCacheContext = {\n cache: cache ?? cacheState.memoryCache,\n revalidatedPaths: new Set(),\n };\n\n return cacheState.storage.run(context, async () => {\n const value = await fn();\n const cachePolicy = context.cachePolicy;\n const revalidatedPaths = Array.from(context.revalidatedPaths);\n\n for (const path of revalidatedPaths) {\n await context.cache.deleteByPath(path);\n }\n\n return { cachePolicy, revalidatedPaths, value };\n });\n}\n\nexport function beginRouteCacheContext(cache: AppRouterCache | undefined): {\n readonly cachePolicy: RouteCachePolicy | undefined;\n dispose(): Promise<{ revalidatedPaths: string[] }>;\n} {\n const context: RouteCacheContext = {\n cache: cache ?? cacheState.memoryCache,\n revalidatedPaths: new Set(),\n };\n\n cacheState.activeContexts.push(context);\n\n return {\n get cachePolicy() {\n return context.cachePolicy;\n },\n async dispose() {\n const revalidatedPaths = Array.from(context.revalidatedPaths);\n\n for (const path of revalidatedPaths) {\n await context.cache.deleteByPath(path);\n }\n\n const index = cacheState.activeContexts.lastIndexOf(context);\n if (index !== -1) {\n cacheState.activeContexts.splice(index, 1);\n }\n\n return { revalidatedPaths };\n },\n };\n}\n\nfunction activeRouteCacheContext(): RouteCacheContext | undefined {\n return cacheState.storage.getStore() ?? cacheState.activeContexts.at(-1);\n}\n\n// Host is excluded from the cache key to prevent attacker-supplied Host\n// headers from fragmenting / poisoning the cache (Issue 068). The Vary\n// dimension is the request path + query; same-origin reverse proxies are\n// expected to handle vhost separation at their layer.\nexport function routeCacheKey(appDir: string, routePath: string, url: URL): string {\n return `${appDir}\\0${normalizeRevalidationPath(routePath)}\\0${url.pathname}${url.search}`;\n}\n\nexport function stripRevalidateExport(code: string): string {\n return code.replace(/^\\s*export\\s+const\\s+revalidate\\s*=\\s*\\d+\\s*;?\\s*$/m, \"\");\n}\n\nfunction normalizeRevalidationPath(path: string): string {\n const pathname = path.startsWith(\"/\") ? path : `/${path}`;\n const withoutTrailing = pathname.length > 1 ? pathname.replace(/\\/+$/, \"\") : pathname;\n\n return withoutTrailing === \"\" ? \"/\" : withoutTrailing;\n}\n\nfunction cacheControlSeconds(value: number | undefined, name: string): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new Error(`cacheControl() ${name} must be a non-negative integer.`);\n }\n\n return value;\n}\n\nfunction staleWhileRevalidateDirective(value: boolean | number): string {\n if (value === true) {\n return \"stale-while-revalidate\";\n }\n\n if (value === false) {\n throw new Error(\"cacheControl() staleWhileRevalidate must be true or a non-negative integer.\");\n }\n\n const seconds = cacheControlSeconds(value, \"staleWhileRevalidate\");\n return `stale-while-revalidate=${seconds}`;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../src/cookies.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAgBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACtC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAwBrB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAmCR;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC1B,QAAQ,CAGV;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAM,GAC3E,QAAQ,CAKV"}
1
+ {"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../src/cookies.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAgBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACtC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAwBrB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAiDR;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC1B,QAAQ,CAGV;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAM,GAC3E,QAAQ,CAKV"}
package/dist/cookies.js CHANGED
@@ -45,6 +45,20 @@ export function serializeCookie(name, value, options = {}) {
45
45
  if (options.sameSite === "None" && options.secure !== true) {
46
46
  throw new TypeError("SameSite=None requires Secure");
47
47
  }
48
+ if (name.startsWith("__Secure-") && options.secure !== true) {
49
+ throw new TypeError("__Secure- cookies require Secure");
50
+ }
51
+ if (name.startsWith("__Host-")) {
52
+ if (options.secure !== true) {
53
+ throw new TypeError("__Host- cookies require Secure");
54
+ }
55
+ if (options.path !== "/") {
56
+ throw new TypeError("__Host- cookies require Path=/");
57
+ }
58
+ if (options.domain !== undefined) {
59
+ throw new TypeError("__Host- cookies must not set Domain");
60
+ }
61
+ }
48
62
  const parts = [`${name}=${encodeURIComponent(value)}`];
49
63
  if (options.maxAge !== undefined) {
50
64
  if (!Number.isSafeInteger(options.maxAge)) {
@@ -1 +1 @@
1
- {"version":3,"file":"cookies.js","sourceRoot":"","sources":["../src/cookies.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Configures attributes used when serializing a Set-Cookie header.\n */\nexport interface CookieOptions {\n domain?: string;\n expires?: Date;\n httpOnly?: boolean;\n maxAge?: number;\n path?: string;\n sameSite?: \"Strict\" | \"Lax\" | \"None\";\n secure?: boolean;\n}\n\nconst COOKIE_NAME = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/;\n\nfunction assertCookieName(name: string): void {\n if (!COOKIE_NAME.test(name)) {\n throw new TypeError(`invalid cookie name: ${JSON.stringify(name)}`);\n }\n}\n\nfunction assertAttributeValue(value: string): void {\n if (/[\\r\\n;]/.test(value)) {\n throw new TypeError(`invalid cookie attribute value: ${JSON.stringify(value)}`);\n }\n}\n\n/**\n * Parses a raw `Cookie` header into decoded name/value pairs.\n *\n * Malformed percent-encoded values are skipped so one bad cookie does not abort request handling.\n */\nexport function parseCookieHeader(\n cookieHeader: string | null | undefined,\n): Map<string, string> {\n const values = new Map<string, string>();\n\n for (const part of (cookieHeader ?? \"\").split(\";\")) {\n const [rawName, ...rawValue] = part.trim().split(\"=\");\n\n if (rawName === undefined || rawName === \"\") {\n continue;\n }\n\n const raw = rawValue.join(\"=\");\n if (raw.indexOf(\"%\") === -1) {\n values.set(rawName, raw);\n continue;\n }\n\n try {\n values.set(rawName, decodeURIComponent(raw));\n } catch {\n // Treat malformed cookie values as absent for this request.\n }\n }\n\n return values;\n}\n\n/**\n * Serializes a cookie name, value, and attributes for a `Set-Cookie` header.\n *\n * Cookie names and attribute values are validated, and `SameSite=None` requires `Secure`.\n */\nexport function serializeCookie(\n name: string,\n value: string,\n options: CookieOptions = {},\n): string {\n assertCookieName(name);\n\n if (options.sameSite === \"None\" && options.secure !== true) {\n throw new TypeError(\"SameSite=None requires Secure\");\n }\n\n const parts = [`${name}=${encodeURIComponent(value)}`];\n\n if (options.maxAge !== undefined) {\n if (!Number.isSafeInteger(options.maxAge)) {\n throw new TypeError(\"invalid cookie Max-Age\");\n }\n parts.push(`Max-Age=${options.maxAge}`);\n }\n\n if (options.domain !== undefined) {\n assertAttributeValue(options.domain);\n parts.push(`Domain=${options.domain}`);\n }\n\n if (options.path !== undefined) {\n assertAttributeValue(options.path);\n parts.push(`Path=${options.path}`);\n }\n\n if (options.expires !== undefined) {\n parts.push(`Expires=${options.expires.toUTCString()}`);\n }\n\n if (options.httpOnly === true) parts.push(\"HttpOnly\");\n if (options.secure === true) parts.push(\"Secure\");\n if (options.sameSite !== undefined) parts.push(`SameSite=${options.sameSite}`);\n\n return parts.join(\"; \");\n}\n\n/**\n * Appends a serialized cookie to a response's `Set-Cookie` headers and returns the same response.\n */\nexport function setCookie(\n response: Response,\n name: string,\n value: string,\n options: CookieOptions = {},\n): Response {\n response.headers.append(\"set-cookie\", serializeCookie(name, value, options));\n return response;\n}\n\n/**\n * Appends an expiring `Set-Cookie` header that removes a cookie in the browser.\n */\nexport function deleteCookie(\n response: Response,\n name: string,\n options: Pick<CookieOptions, \"domain\" | \"path\" | \"sameSite\" | \"secure\"> = {},\n): Response {\n return setCookie(response, name, \"\", {\n ...options,\n maxAge: 0,\n });\n}\n"]}
1
+ {"version":3,"file":"cookies.js","sourceRoot":"","sources":["../src/cookies.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Configures attributes used when serializing a Set-Cookie header.\n */\nexport interface CookieOptions {\n domain?: string;\n expires?: Date;\n httpOnly?: boolean;\n maxAge?: number;\n path?: string;\n sameSite?: \"Strict\" | \"Lax\" | \"None\";\n secure?: boolean;\n}\n\nconst COOKIE_NAME = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/;\n\nfunction assertCookieName(name: string): void {\n if (!COOKIE_NAME.test(name)) {\n throw new TypeError(`invalid cookie name: ${JSON.stringify(name)}`);\n }\n}\n\nfunction assertAttributeValue(value: string): void {\n if (/[\\r\\n;]/.test(value)) {\n throw new TypeError(`invalid cookie attribute value: ${JSON.stringify(value)}`);\n }\n}\n\n/**\n * Parses a raw `Cookie` header into decoded name/value pairs.\n *\n * Malformed percent-encoded values are skipped so one bad cookie does not abort request handling.\n */\nexport function parseCookieHeader(\n cookieHeader: string | null | undefined,\n): Map<string, string> {\n const values = new Map<string, string>();\n\n for (const part of (cookieHeader ?? \"\").split(\";\")) {\n const [rawName, ...rawValue] = part.trim().split(\"=\");\n\n if (rawName === undefined || rawName === \"\") {\n continue;\n }\n\n const raw = rawValue.join(\"=\");\n if (raw.indexOf(\"%\") === -1) {\n values.set(rawName, raw);\n continue;\n }\n\n try {\n values.set(rawName, decodeURIComponent(raw));\n } catch {\n // Treat malformed cookie values as absent for this request.\n }\n }\n\n return values;\n}\n\n/**\n * Serializes a cookie name, value, and attributes for a `Set-Cookie` header.\n *\n * Cookie names and attribute values are validated, and `SameSite=None` requires `Secure`.\n */\nexport function serializeCookie(\n name: string,\n value: string,\n options: CookieOptions = {},\n): string {\n assertCookieName(name);\n\n if (options.sameSite === \"None\" && options.secure !== true) {\n throw new TypeError(\"SameSite=None requires Secure\");\n }\n if (name.startsWith(\"__Secure-\") && options.secure !== true) {\n throw new TypeError(\"__Secure- cookies require Secure\");\n }\n if (name.startsWith(\"__Host-\")) {\n if (options.secure !== true) {\n throw new TypeError(\"__Host- cookies require Secure\");\n }\n if (options.path !== \"/\") {\n throw new TypeError(\"__Host- cookies require Path=/\");\n }\n if (options.domain !== undefined) {\n throw new TypeError(\"__Host- cookies must not set Domain\");\n }\n }\n\n const parts = [`${name}=${encodeURIComponent(value)}`];\n\n if (options.maxAge !== undefined) {\n if (!Number.isSafeInteger(options.maxAge)) {\n throw new TypeError(\"invalid cookie Max-Age\");\n }\n parts.push(`Max-Age=${options.maxAge}`);\n }\n\n if (options.domain !== undefined) {\n assertAttributeValue(options.domain);\n parts.push(`Domain=${options.domain}`);\n }\n\n if (options.path !== undefined) {\n assertAttributeValue(options.path);\n parts.push(`Path=${options.path}`);\n }\n\n if (options.expires !== undefined) {\n parts.push(`Expires=${options.expires.toUTCString()}`);\n }\n\n if (options.httpOnly === true) parts.push(\"HttpOnly\");\n if (options.secure === true) parts.push(\"Secure\");\n if (options.sameSite !== undefined) parts.push(`SameSite=${options.sameSite}`);\n\n return parts.join(\"; \");\n}\n\n/**\n * Appends a serialized cookie to a response's `Set-Cookie` headers and returns the same response.\n */\nexport function setCookie(\n response: Response,\n name: string,\n value: string,\n options: CookieOptions = {},\n): Response {\n response.headers.append(\"set-cookie\", serializeCookie(name, value, options));\n return response;\n}\n\n/**\n * Appends an expiring `Set-Cookie` header that removes a cookie in the browser.\n */\nexport function deleteCookie(\n response: Response,\n name: string,\n options: Pick<CookieOptions, \"domain\" | \"path\" | \"sameSite\" | \"secure\"> = {},\n): Response {\n return setCookie(response, name, \"\", {\n ...options,\n maxAge: 0,\n });\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reckona/mreact-router",
3
- "version": "0.0.179",
3
+ "version": "0.0.180",
4
4
  "description": "File-system app router, SSR, actions, and deployment adapters for mreact.",
5
5
  "keywords": [
6
6
  "jsx",
@@ -105,20 +105,20 @@
105
105
  },
106
106
  "dependencies": {
107
107
  "typescript": "^6.0.3",
108
- "@reckona/mreact": "0.0.179",
109
- "@reckona/mreact-compat": "0.0.179",
110
- "@reckona/mreact-compiler": "0.0.179",
111
- "@reckona/mreact-devtools": "0.0.179",
112
- "@reckona/mreact-query": "0.0.179",
113
- "@reckona/mreact-reactive-core": "0.0.179",
114
- "@reckona/mreact-reactive-dom": "0.0.179",
115
- "@reckona/mreact-shared": "0.0.179",
116
- "@reckona/mreact-server": "0.0.179"
108
+ "@reckona/mreact": "0.0.180",
109
+ "@reckona/mreact-compat": "0.0.180",
110
+ "@reckona/mreact-devtools": "0.0.180",
111
+ "@reckona/mreact-compiler": "0.0.180",
112
+ "@reckona/mreact-query": "0.0.180",
113
+ "@reckona/mreact-reactive-core": "0.0.180",
114
+ "@reckona/mreact-reactive-dom": "0.0.180",
115
+ "@reckona/mreact-server": "0.0.180",
116
+ "@reckona/mreact-shared": "0.0.180"
117
117
  },
118
118
  "peerDependencies": {
119
119
  "vite": ">=8 <9"
120
120
  },
121
121
  "optionalDependencies": {
122
- "@reckona/mreact-router-native": "0.0.179"
122
+ "@reckona/mreact-router-native": "0.0.180"
123
123
  }
124
124
  }
package/src/actions.ts CHANGED
@@ -73,7 +73,7 @@ let warnedUnrestrictedServerActions = false;
73
73
  /**
74
74
  * Request context passed to authorized server actions.
75
75
  *
76
- * It exposes normalized cookies, headers, the original `Request`, and an optional client IP so authorization hooks can make request-aware decisions.
76
+ * It exposes normalized cookies, headers, and the original `Request`. `clientIp` is reserved for trusted adapter integrations and is omitted by the default header-only dispatcher because forwarded IP headers are attacker-controlled without a trusted proxy boundary.
77
77
  */
78
78
  export interface ServerActionContext {
79
79
  clientIp?: string | undefined;
@@ -455,7 +455,15 @@ async function dispatchServerActionRequestWithoutCacheContext(options: {
455
455
  return manifestResponse;
456
456
  }
457
457
 
458
- const formData = await options.request.formData();
458
+ const boundedRequest = await readServerActionRequestWithLimit(
459
+ options.request,
460
+ options.serverActions?.maxBodyBytes ?? DEFAULT_ACTION_BODY_MAX_BYTES,
461
+ );
462
+ if (boundedRequest instanceof Response) {
463
+ return boundedRequest;
464
+ }
465
+
466
+ const formData = await boundedRequest.formData();
459
467
  const fieldCountResponse = validateServerActionFormFieldCount(
460
468
  formData,
461
469
  options.serverActions?.maxFormFields ?? DEFAULT_ACTION_FORM_MAX_FIELDS,
@@ -575,14 +583,8 @@ function createServerActionContext(request: Request): ServerActionContext {
575
583
  }
576
584
 
577
585
  function clientIpFromRequest(request: Request): string | undefined {
578
- const forwarded = request.headers.get("x-forwarded-for")?.split(",")[0]?.trim();
579
-
580
- if (forwarded !== undefined && forwarded !== "") {
581
- return forwarded;
582
- }
583
-
584
- const realIp = request.headers.get("x-real-ip")?.trim();
585
- return realIp === "" ? undefined : realIp;
586
+ void request;
587
+ return undefined;
586
588
  }
587
589
 
588
590
  function validateServerActionBodySize(
@@ -610,6 +612,54 @@ function validateServerActionBodySize(
610
612
  return undefined;
611
613
  }
612
614
 
615
+ async function readServerActionRequestWithLimit(
616
+ request: Request,
617
+ maxBodyBytes: number,
618
+ ): Promise<Request | Response> {
619
+ if (!Number.isFinite(maxBodyBytes) || maxBodyBytes < 0) {
620
+ return request;
621
+ }
622
+
623
+ const body = request.body;
624
+ if (body === null) {
625
+ return request;
626
+ }
627
+
628
+ const reader = body.getReader();
629
+ const chunks: Uint8Array[] = [];
630
+ let total = 0;
631
+
632
+ try {
633
+ while (true) {
634
+ const { done, value } = await reader.read();
635
+ if (done) break;
636
+ total += value.byteLength;
637
+ if (total > maxBodyBytes) {
638
+ await reader.cancel();
639
+ return jsonResponse({ ok: false, error: "Server action request body is too large." }, 413);
640
+ }
641
+ chunks.push(value);
642
+ }
643
+ } finally {
644
+ reader.releaseLock?.();
645
+ }
646
+
647
+ const buffer = new Uint8Array(total);
648
+ let offset = 0;
649
+ for (const chunk of chunks) {
650
+ buffer.set(chunk, offset);
651
+ offset += chunk.byteLength;
652
+ }
653
+
654
+ const headers = new Headers(request.headers);
655
+ headers.delete("content-length");
656
+ return new Request(request.url, {
657
+ body: buffer,
658
+ headers,
659
+ method: request.method,
660
+ });
661
+ }
662
+
613
663
  function validateServerActionFormFieldCount(
614
664
  formData: FormData,
615
665
  maxFormFields: number,
@@ -574,11 +574,17 @@ async function runWithCloudflareQueryClient<T>(
574
574
  queryClient: QueryClient,
575
575
  fn: () => T,
576
576
  ): Promise<Awaited<T>> {
577
+ if (cloudflareQueryClientFallbackInstalled) {
578
+ installQueryAsyncStorage(cloudflareQueryClientStorage);
579
+ return await runWithSerializedCloudflareQueryClient(queryClient, fn);
580
+ }
581
+
577
582
  try {
578
583
  return await runWithQueryClient(queryClient, fn);
579
584
  } catch (error) {
580
585
  if (isQueryClientScopeUnavailableError(error)) {
581
586
  installQueryAsyncStorage(cloudflareQueryClientStorage);
587
+ cloudflareQueryClientFallbackInstalled = true;
582
588
  return await runWithSerializedCloudflareQueryClient(queryClient, fn);
583
589
  }
584
590
 
@@ -588,6 +594,7 @@ async function runWithCloudflareQueryClient<T>(
588
594
 
589
595
  const cloudflareQueryClientStorage = createCloudflareQueryClientStorage();
590
596
  let cloudflareQueryClientFallbackQueue: Promise<void> = Promise.resolve();
597
+ let cloudflareQueryClientFallbackInstalled = false;
591
598
 
592
599
  async function runWithSerializedCloudflareQueryClient<T>(
593
600
  queryClient: QueryClient,
package/src/cache.ts CHANGED
@@ -348,9 +348,70 @@ function requestCarriesCredentials(request: Request | undefined): boolean {
348
348
  return false;
349
349
  }
350
350
 
351
- return request.headers.has("authorization") || request.headers.has("cookie");
351
+ if (request.headers.has("authorization") || request.headers.has("cookie")) {
352
+ return true;
353
+ }
354
+
355
+ for (const name of request.headers.keys()) {
356
+ const lower = name.toLowerCase();
357
+ if (PUBLIC_ROUTE_CACHE_REQUEST_HEADERS.has(lower)) {
358
+ continue;
359
+ }
360
+
361
+ if (
362
+ lower === "x-api-key" ||
363
+ lower === "cf-access-jwt-assertion" ||
364
+ lower === "proxy-authorization" ||
365
+ lower === "x-auth-token" ||
366
+ lower === "x-authenticated-user" ||
367
+ lower === "x-forwarded-user" ||
368
+ lower === "x-session-id" ||
369
+ lower === "x-user-email" ||
370
+ lower === "x-user-id" ||
371
+ lower.endsWith("-api-key") ||
372
+ lower.endsWith("-auth-token") ||
373
+ lower.endsWith("-session-id") ||
374
+ lower.endsWith("-user") ||
375
+ lower.endsWith("-user-email") ||
376
+ lower.endsWith("-user-id") ||
377
+ lower.includes("-jwt-") ||
378
+ lower.endsWith("-jwt")
379
+ ) {
380
+ return true;
381
+ }
382
+
383
+ return true;
384
+ }
385
+
386
+ return false;
352
387
  }
353
388
 
389
+ const PUBLIC_ROUTE_CACHE_REQUEST_HEADERS = new Set([
390
+ "accept",
391
+ "accept-encoding",
392
+ "accept-language",
393
+ "cache-control",
394
+ "connection",
395
+ "dnt",
396
+ "host",
397
+ "pragma",
398
+ "purpose",
399
+ "referer",
400
+ "sec-ch-prefers-color-scheme",
401
+ "sec-ch-prefers-reduced-motion",
402
+ "sec-ch-ua",
403
+ "sec-ch-ua-mobile",
404
+ "sec-ch-ua-platform",
405
+ "sec-fetch-dest",
406
+ "sec-fetch-mode",
407
+ "sec-fetch-site",
408
+ "sec-fetch-user",
409
+ "upgrade-insecure-requests",
410
+ "user-agent",
411
+ "x-mreact-navigation",
412
+ "x-mreact-navigation-cache",
413
+ ]);
414
+
354
415
  /**
355
416
  * Invalidates cached route responses for a normalized app-router path.
356
417
  *
package/src/cookies.ts CHANGED
@@ -73,6 +73,20 @@ export function serializeCookie(
73
73
  if (options.sameSite === "None" && options.secure !== true) {
74
74
  throw new TypeError("SameSite=None requires Secure");
75
75
  }
76
+ if (name.startsWith("__Secure-") && options.secure !== true) {
77
+ throw new TypeError("__Secure- cookies require Secure");
78
+ }
79
+ if (name.startsWith("__Host-")) {
80
+ if (options.secure !== true) {
81
+ throw new TypeError("__Host- cookies require Secure");
82
+ }
83
+ if (options.path !== "/") {
84
+ throw new TypeError("__Host- cookies require Path=/");
85
+ }
86
+ if (options.domain !== undefined) {
87
+ throw new TypeError("__Host- cookies must not set Domain");
88
+ }
89
+ }
76
90
 
77
91
  const parts = [`${name}=${encodeURIComponent(value)}`];
78
92