@reckona/mreact-router 0.0.178 → 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/actions.d.ts +1 -1
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +50 -9
- package/dist/actions.js.map +1 -1
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +6 -0
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +55 -1
- package/dist/cache.js.map +1 -1
- package/dist/cookies.d.ts.map +1 -1
- package/dist/cookies.js +14 -0
- package/dist/cookies.js.map +1 -1
- package/dist/csrf.d.ts +1 -0
- package/dist/csrf.d.ts.map +1 -1
- package/dist/csrf.js +3 -0
- package/dist/csrf.js.map +1 -1
- package/package.json +11 -11
- package/src/actions.ts +62 -11
- package/src/adapters/cloudflare.ts +7 -0
- package/src/cache.ts +62 -1
- package/src/cookies.ts +14 -0
- package/src/csrf.ts +4 -0
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"]}
|
package/dist/cookies.d.ts.map
CHANGED
|
@@ -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,
|
|
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)) {
|
package/dist/cookies.js.map
CHANGED
|
@@ -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/dist/csrf.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export declare const formCsrfFieldName = "__mreact_csrf";
|
|
5
5
|
export declare function serverActionCookie(csrfToken: string): string;
|
|
6
|
+
export declare function serverActionCookieName(): string;
|
|
6
7
|
/**
|
|
7
8
|
* Creates or reuses the CSRF token embedded into server-rendered forms.
|
|
8
9
|
*/
|
package/dist/csrf.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,eAAO,MAAM,iBAAiB,kBAAgB,CAAC;AAE/C,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAc5D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAEzE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAc3F;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAY1F"}
|
|
1
|
+
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,eAAO,MAAM,iBAAiB,kBAAgB,CAAC;AAE/C,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAc5D;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAEzE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAc3F;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAY1F"}
|
package/dist/csrf.js
CHANGED
|
@@ -18,6 +18,9 @@ export function serverActionCookie(csrfToken) {
|
|
|
18
18
|
}
|
|
19
19
|
return parts.join("; ");
|
|
20
20
|
}
|
|
21
|
+
export function serverActionCookieName() {
|
|
22
|
+
return currentCsrfCookieName();
|
|
23
|
+
}
|
|
21
24
|
/**
|
|
22
25
|
* Creates or reuses the CSRF token embedded into server-rendered forms.
|
|
23
26
|
*/
|
package/dist/csrf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":"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","sourcesContent":["const csrfCookieNameProduction = \"__Host-mreact.csrf\";\nconst csrfCookieNameDevelopment = \"mreact.csrf\";\nconst formFieldCsrf = \"__mreact_csrf\";\n\n/**\n * Names the hidden form field used for app-router CSRF validation.\n */\nexport const formCsrfFieldName = formFieldCsrf;\n\nexport function serverActionCookie(csrfToken: string): string {\n const production = isProductionEnvironment();\n const parts = [\n `${currentCsrfCookieName()}=${encodeURIComponent(csrfToken)}`,\n \"Path=/\",\n \"SameSite=Lax\",\n \"HttpOnly\",\n ];\n\n if (production) {\n parts.push(\"Secure\");\n }\n\n return parts.join(\"; \");\n}\n\n/**\n * Creates or reuses the CSRF token embedded into server-rendered forms.\n */\nexport function createFormCsrfToken(request?: Request | undefined): string {\n return readExistingFormCsrfToken(request) ?? randomToken();\n}\n\n/**\n * Serializes the CSRF cookie used to validate app-router form submissions.\n */\nexport function formCsrfCookie(csrfToken: string): string {\n return serverActionCookie(csrfToken);\n}\n\n/**\n * Validates the CSRF cookie and hidden form field for a form submission.\n */\nexport function validateFormCsrf(request: Request, formData: FormData): Response | undefined {\n const formToken = stringFormValue(formData.get(formFieldCsrf));\n const cookieHeader = request.headers.get(\"cookie\");\n const cookieToken = csrfCookieNamesRead()\n .map((name) => readCookie(cookieHeader, name))\n .find((token) => token !== undefined);\n\n if (formToken === undefined || cookieToken === undefined) {\n return jsonResponse({ ok: false, error: \"Invalid CSRF token.\" }, 403);\n }\n\n return timingSafeStringEqual(formToken, cookieToken)\n ? undefined\n : jsonResponse({ ok: false, error: \"Invalid CSRF token.\" }, 403);\n}\n\nexport function readExistingFormCsrfToken(request: Request | undefined): string | undefined {\n const cookieHeader = request?.headers.get(\"cookie\") ?? null;\n\n for (const name of csrfCookieNamesRead()) {\n const token = readCookie(cookieHeader, name);\n\n if (token !== undefined && isCsrfTokenShape(token)) {\n return token;\n }\n }\n\n return undefined;\n}\n\nfunction isCsrfTokenShape(value: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);\n}\n\nfunction randomToken(): string {\n const cryptoApi = globalThis.crypto;\n\n if (typeof cryptoApi?.randomUUID === \"function\") {\n return cryptoApi.randomUUID();\n }\n\n if (typeof cryptoApi?.getRandomValues !== \"function\") {\n throw new Error(\"Web Crypto is required to create a CSRF token.\");\n }\n\n const bytes = new Uint8Array(16);\n cryptoApi.getRandomValues(bytes);\n bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40;\n bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;\n const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\"));\n return `${hex.slice(0, 4).join(\"\")}-${hex.slice(4, 6).join(\"\")}-${hex.slice(6, 8).join(\"\")}-${hex.slice(8, 10).join(\"\")}-${hex.slice(10).join(\"\")}`;\n}\n\nfunction isProductionEnvironment(): boolean {\n return typeof process !== \"undefined\" && process.env?.NODE_ENV === \"production\";\n}\n\nfunction currentCsrfCookieName(): string {\n return isProductionEnvironment() ? csrfCookieNameProduction : csrfCookieNameDevelopment;\n}\n\nfunction csrfCookieNamesRead(): readonly string[] {\n return isProductionEnvironment()\n ? [csrfCookieNameProduction]\n : [csrfCookieNameProduction, csrfCookieNameDevelopment];\n}\n\nfunction timingSafeStringEqual(left: string, right: string): boolean {\n let diff = left.length ^ right.length;\n const length = Math.max(left.length, right.length);\n\n for (let index = 0; index < length; index += 1) {\n diff |= (left.charCodeAt(index) || 0) ^ (right.charCodeAt(index) || 0);\n }\n\n return diff === 0;\n}\n\nfunction stringFormValue(value: FormDataEntryValue | null): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction readCookie(cookieHeader: string | null, name: string): string | undefined {\n if (cookieHeader === null || cookieHeader.trim() === \"\") {\n return undefined;\n }\n\n for (const part of cookieHeader.split(\";\")) {\n const [rawName, ...rawValue] = part.trim().split(\"=\");\n\n if (rawName !== name) {\n continue;\n }\n\n try {\n return decodeURIComponent(rawValue.join(\"=\"));\n } catch {\n return rawValue.join(\"=\");\n }\n }\n\n return undefined;\n}\n\nfunction jsonResponse(payload: unknown, status: number): Response {\n return Response.json(payload, { status });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":"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","sourcesContent":["const csrfCookieNameProduction = \"__Host-mreact.csrf\";\nconst csrfCookieNameDevelopment = \"mreact.csrf\";\nconst formFieldCsrf = \"__mreact_csrf\";\n\n/**\n * Names the hidden form field used for app-router CSRF validation.\n */\nexport const formCsrfFieldName = formFieldCsrf;\n\nexport function serverActionCookie(csrfToken: string): string {\n const production = isProductionEnvironment();\n const parts = [\n `${currentCsrfCookieName()}=${encodeURIComponent(csrfToken)}`,\n \"Path=/\",\n \"SameSite=Lax\",\n \"HttpOnly\",\n ];\n\n if (production) {\n parts.push(\"Secure\");\n }\n\n return parts.join(\"; \");\n}\n\nexport function serverActionCookieName(): string {\n return currentCsrfCookieName();\n}\n\n/**\n * Creates or reuses the CSRF token embedded into server-rendered forms.\n */\nexport function createFormCsrfToken(request?: Request | undefined): string {\n return readExistingFormCsrfToken(request) ?? randomToken();\n}\n\n/**\n * Serializes the CSRF cookie used to validate app-router form submissions.\n */\nexport function formCsrfCookie(csrfToken: string): string {\n return serverActionCookie(csrfToken);\n}\n\n/**\n * Validates the CSRF cookie and hidden form field for a form submission.\n */\nexport function validateFormCsrf(request: Request, formData: FormData): Response | undefined {\n const formToken = stringFormValue(formData.get(formFieldCsrf));\n const cookieHeader = request.headers.get(\"cookie\");\n const cookieToken = csrfCookieNamesRead()\n .map((name) => readCookie(cookieHeader, name))\n .find((token) => token !== undefined);\n\n if (formToken === undefined || cookieToken === undefined) {\n return jsonResponse({ ok: false, error: \"Invalid CSRF token.\" }, 403);\n }\n\n return timingSafeStringEqual(formToken, cookieToken)\n ? undefined\n : jsonResponse({ ok: false, error: \"Invalid CSRF token.\" }, 403);\n}\n\nexport function readExistingFormCsrfToken(request: Request | undefined): string | undefined {\n const cookieHeader = request?.headers.get(\"cookie\") ?? null;\n\n for (const name of csrfCookieNamesRead()) {\n const token = readCookie(cookieHeader, name);\n\n if (token !== undefined && isCsrfTokenShape(token)) {\n return token;\n }\n }\n\n return undefined;\n}\n\nfunction isCsrfTokenShape(value: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);\n}\n\nfunction randomToken(): string {\n const cryptoApi = globalThis.crypto;\n\n if (typeof cryptoApi?.randomUUID === \"function\") {\n return cryptoApi.randomUUID();\n }\n\n if (typeof cryptoApi?.getRandomValues !== \"function\") {\n throw new Error(\"Web Crypto is required to create a CSRF token.\");\n }\n\n const bytes = new Uint8Array(16);\n cryptoApi.getRandomValues(bytes);\n bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40;\n bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;\n const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\"));\n return `${hex.slice(0, 4).join(\"\")}-${hex.slice(4, 6).join(\"\")}-${hex.slice(6, 8).join(\"\")}-${hex.slice(8, 10).join(\"\")}-${hex.slice(10).join(\"\")}`;\n}\n\nfunction isProductionEnvironment(): boolean {\n return typeof process !== \"undefined\" && process.env?.NODE_ENV === \"production\";\n}\n\nfunction currentCsrfCookieName(): string {\n return isProductionEnvironment() ? csrfCookieNameProduction : csrfCookieNameDevelopment;\n}\n\nfunction csrfCookieNamesRead(): readonly string[] {\n return isProductionEnvironment()\n ? [csrfCookieNameProduction]\n : [csrfCookieNameProduction, csrfCookieNameDevelopment];\n}\n\nfunction timingSafeStringEqual(left: string, right: string): boolean {\n let diff = left.length ^ right.length;\n const length = Math.max(left.length, right.length);\n\n for (let index = 0; index < length; index += 1) {\n diff |= (left.charCodeAt(index) || 0) ^ (right.charCodeAt(index) || 0);\n }\n\n return diff === 0;\n}\n\nfunction stringFormValue(value: FormDataEntryValue | null): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction readCookie(cookieHeader: string | null, name: string): string | undefined {\n if (cookieHeader === null || cookieHeader.trim() === \"\") {\n return undefined;\n }\n\n for (const part of cookieHeader.split(\";\")) {\n const [rawName, ...rawValue] = part.trim().split(\"=\");\n\n if (rawName !== name) {\n continue;\n }\n\n try {\n return decodeURIComponent(rawValue.join(\"=\"));\n } catch {\n return rawValue.join(\"=\");\n }\n }\n\n return undefined;\n}\n\nfunction jsonResponse(payload: unknown, status: number): Response {\n return Response.json(payload, { status });\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reckona/mreact-router",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
109
|
-
"@reckona/mreact-compat": "0.0.
|
|
110
|
-
"@reckona/mreact-
|
|
111
|
-
"@reckona/mreact-
|
|
112
|
-
"@reckona/mreact-
|
|
113
|
-
"@reckona/mreact-
|
|
114
|
-
"@reckona/mreact-reactive-dom": "0.0.
|
|
115
|
-
"@reckona/mreact-server": "0.0.
|
|
116
|
-
"@reckona/mreact-shared": "0.0.
|
|
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.
|
|
122
|
+
"@reckona/mreact-router-native": "0.0.180"
|
|
123
123
|
}
|
|
124
124
|
}
|
package/src/actions.ts
CHANGED
|
@@ -29,6 +29,7 @@ export {
|
|
|
29
29
|
import {
|
|
30
30
|
formCsrfFieldName,
|
|
31
31
|
readExistingFormCsrfToken,
|
|
32
|
+
serverActionCookieName,
|
|
32
33
|
validateFormCsrf,
|
|
33
34
|
} from "./csrf.js";
|
|
34
35
|
import {
|
|
@@ -72,7 +73,7 @@ let warnedUnrestrictedServerActions = false;
|
|
|
72
73
|
/**
|
|
73
74
|
* Request context passed to authorized server actions.
|
|
74
75
|
*
|
|
75
|
-
* It exposes normalized cookies, headers, the original `Request
|
|
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.
|
|
76
77
|
*/
|
|
77
78
|
export interface ServerActionContext {
|
|
78
79
|
clientIp?: string | undefined;
|
|
@@ -434,7 +435,7 @@ async function dispatchServerActionRequestWithoutCacheContext(options: {
|
|
|
434
435
|
options.serverActions.allowedActions === "any"
|
|
435
436
|
? {}
|
|
436
437
|
: { allowedActions: jsonAllowedServerActions(options.serverActions.allowedActions) }),
|
|
437
|
-
csrf:
|
|
438
|
+
csrf: { cookieName: serverActionCookieName() },
|
|
438
439
|
maxBodyBytes: options.serverActions?.maxBodyBytes ?? DEFAULT_ACTION_BODY_MAX_BYTES,
|
|
439
440
|
replayProtection: { seen: replayStore },
|
|
440
441
|
});
|
|
@@ -454,7 +455,15 @@ async function dispatchServerActionRequestWithoutCacheContext(options: {
|
|
|
454
455
|
return manifestResponse;
|
|
455
456
|
}
|
|
456
457
|
|
|
457
|
-
const
|
|
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();
|
|
458
467
|
const fieldCountResponse = validateServerActionFormFieldCount(
|
|
459
468
|
formData,
|
|
460
469
|
options.serverActions?.maxFormFields ?? DEFAULT_ACTION_FORM_MAX_FIELDS,
|
|
@@ -574,14 +583,8 @@ function createServerActionContext(request: Request): ServerActionContext {
|
|
|
574
583
|
}
|
|
575
584
|
|
|
576
585
|
function clientIpFromRequest(request: Request): string | undefined {
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
if (forwarded !== undefined && forwarded !== "") {
|
|
580
|
-
return forwarded;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
const realIp = request.headers.get("x-real-ip")?.trim();
|
|
584
|
-
return realIp === "" ? undefined : realIp;
|
|
586
|
+
void request;
|
|
587
|
+
return undefined;
|
|
585
588
|
}
|
|
586
589
|
|
|
587
590
|
function validateServerActionBodySize(
|
|
@@ -609,6 +612,54 @@ function validateServerActionBodySize(
|
|
|
609
612
|
return undefined;
|
|
610
613
|
}
|
|
611
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
|
+
|
|
612
663
|
function validateServerActionFormFieldCount(
|
|
613
664
|
formData: FormData,
|
|
614
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
|
-
|
|
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
|
|
package/src/csrf.ts
CHANGED
|
@@ -23,6 +23,10 @@ export function serverActionCookie(csrfToken: string): string {
|
|
|
23
23
|
return parts.join("; ");
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
export function serverActionCookieName(): string {
|
|
27
|
+
return currentCsrfCookieName();
|
|
28
|
+
}
|
|
29
|
+
|
|
26
30
|
/**
|
|
27
31
|
* Creates or reuses the CSRF token embedded into server-rendered forms.
|
|
28
32
|
*/
|