{"version":3,"sources":["../src/middleware/server.ts","../src/middleware/cookie-header.ts","../src/middleware/module.ts"],"sourcesContent":["/**\n * Server-side middleware utilities for accessing middleware data in pages\n */\n\nimport { AsyncLocalStorage } from \"async_hooks\";\nimport type { ReadonlyMiddlewareStore } from \"./types\";\n\ntype MiddlewareStoreInput = Record<string, any> | Map<string, any>;\nconst MIDDLEWARE_DATA_STORE_KEY = Symbol.for(\"farm.middlewareDataStore\");\nconst MIDDLEWARE_CONTEXT_STORE_KEY = Symbol.for(\"farm.middlewareContextStore\");\n\nfunction getGlobalMiddlewareStore(key: symbol): AsyncLocalStorage<Map<string, any>> {\n  const state = globalThis as typeof globalThis & Record<symbol, unknown>;\n  const existing = state[key];\n  if (existing instanceof AsyncLocalStorage) {\n    return existing as AsyncLocalStorage<Map<string, any>>;\n  }\n\n  const store = new AsyncLocalStorage<Map<string, any>>();\n  state[key] = store;\n  return store;\n}\n\nconst middlewareStore = getGlobalMiddlewareStore(MIDDLEWARE_DATA_STORE_KEY);\nconst middlewareContextStore = getGlobalMiddlewareStore(MIDDLEWARE_CONTEXT_STORE_KEY);\n\nfunction toMiddlewareMap(data: MiddlewareStoreInput): Map<string, any> {\n  if (data instanceof Map) {\n    return new Map(data);\n  }\n  return new Map(Object.entries(data));\n}\n\n/**\n * Internal: Set middleware data for the current request\n * This is called by the server renderer before rendering starts.\n * Prefer _runWithMiddlewareData for request-scoped async flows.\n */\nexport function _setCurrentMiddlewareData(data: MiddlewareStoreInput): void {\n  middlewareStore.enterWith(toMiddlewareMap(data));\n}\n\n/**\n * Internal: Clear middleware data after request completes\n */\nexport function _clearCurrentMiddlewareData(): void {\n  middlewareStore.enterWith(new Map());\n}\n\n/** Internal: Clear server-only middleware context after rendering. */\nexport function _clearCurrentMiddlewareContext(): void {\n  middlewareContextStore.enterWith(new Map());\n}\n\n/**\n * Internal: Run code with middleware data available\n * This is called by the server renderer\n */\nexport async function _runWithMiddlewareData<T>(\n  data: MiddlewareStoreInput,\n  fn: () => T | Promise<T>,\n): Promise<T> {\n  return middlewareStore.run(toMiddlewareMap(data), fn);\n}\n\n/** Internal: Run code with server-only middleware context available. */\nexport async function _runWithMiddlewareContext<T>(\n  context: MiddlewareStoreInput,\n  fn: () => T | Promise<T>,\n): Promise<T> {\n  return middlewareContextStore.run(toMiddlewareMap(context), fn);\n}\n\n/**\n * Get middleware data in a server component\n * No props needed - uses global storage!\n *\n * @example\n * ```tsx\n * import { getMiddlewareData } from 'farm/middleware';\n *\n * export default function Page() {\n *   const data = getMiddlewareData();  // ← No props needed!\n *   const user = data.get('user');\n *   const demoInfo = data.get('demoInfo');\n *\n *   return <div>Welcome {user?.name}</div>;\n * }\n * ```\n */\nexport function getMiddlewareData<T extends Record<string, any> = Record<string, any>>(): Map<\n  keyof T,\n  T[keyof T]\n> {\n  return (middlewareStore.getStore() || new Map()) as Map<keyof T, T[keyof T]>;\n}\n\n/**\n * Get a specific value from middleware data (synchronous)\n * Uses AsyncLocalStorage for request scoping - no props needed.\n *\n * @example\n * ```tsx\n * import { getMiddlewareValue } from 'farm/middleware';\n *\n * export default function Page() {\n *   const user = getMiddlewareValue<User>('user');  // ← No props needed!\n *   const stats = getMiddlewareValue('dashboardStats');\n *\n *   return <div>Welcome {user?.name}</div>;\n * }\n * ```\n */\nexport function getMiddlewareValue<T = any>(key: string): T | undefined {\n  const data = getMiddlewareData();\n  return data.get(key);\n}\n\n/**\n * Read server-only values set by route middleware for the current request.\n * The returned store is available to the matched page, layouts, and nested\n * Server Components, but is never added to hydration props.\n */\nexport function getMiddlewareContext<\n  T extends Record<string, any> = Record<string, any>,\n>(): ReadonlyMiddlewareStore<T> {\n  return (middlewareContextStore.getStore() || new Map()) as unknown as ReadonlyMiddlewareStore<T>;\n}\n\n/**\n * Type-safe middleware data accessor with type parameter\n *\n * @example\n * ```tsx\n * import { createMiddlewareAccessor } from 'farm/middleware/server';\n *\n * interface MiddlewareData {\n *   user: { id: number; name: string };\n *   dashboardStats: { views: number; clicks: number };\n * }\n *\n * const getData = createMiddlewareAccessor<MiddlewareData>();\n *\n * export default function Page() {\n *   const data = getData();\n *   const user = data.user;  // Fully typed!\n *   const stats = data.dashboardStats;  // Fully typed!\n *\n *   return <div>Welcome {user?.name}</div>;\n * }\n * ```\n */\nexport function createMiddlewareAccessor<T extends Record<string, any>>() {\n  return (): Partial<T> => {\n    const data = getMiddlewareData();\n    const result: any = {};\n\n    for (const [key, value] of data) {\n      result[key] = value;\n    }\n\n    return result as Partial<T>;\n  };\n}\n","import type { CookieOptions } from \"./types\";\n\nfunction decodeCookieValue(value: string): string {\n  try {\n    return decodeURIComponent(value);\n  } catch {\n    // Cookies are not required to be percent-encoded; keep the raw value\n    // instead of failing the whole request on malformed encoding.\n    return value;\n  }\n}\n\nexport function parseMiddlewareCookieHeader(cookieHeader?: string | null): Record<string, string> {\n  const cookies = Object.create(null) as Record<string, string>;\n  if (!cookieHeader) return cookies;\n\n  for (const cookie of cookieHeader.split(\";\")) {\n    const separator = cookie.indexOf(\"=\");\n    if (separator < 0) continue;\n\n    const name = cookie.slice(0, separator).trim();\n    if (!name) continue;\n\n    const value = cookie.slice(separator + 1).trim();\n    cookies[name] = decodeCookieValue(value);\n  }\n\n  return cookies;\n}\n\n/**\n * Apply the attributes a cookie name prefix makes mandatory.\n *\n * Browsers reject a `Set-Cookie` whose name starts with `__Host-` or\n * `__Secure-` unless it carries `Secure` (and, for `__Host-`, `Path=/` with no\n * `Domain`). A rejected header is discarded silently, so emitting one without\n * these attributes makes both a set and a *deletion* a no-op — a logout that\n * looks like it worked while the session cookie stays live. The attributes are\n * therefore derived from the name rather than trusted from the caller.\n */\nexport function applyCookieNamePrefixRequirements(\n  name: string,\n  options: CookieOptions,\n): CookieOptions {\n  if (name.startsWith(\"__Host-\")) {\n    return { ...options, secure: true, path: \"/\", domain: undefined };\n  }\n  if (name.startsWith(\"__Secure-\")) {\n    return { ...options, secure: true };\n  }\n  return options;\n}\n\nexport function serializeMiddlewareCookie(\n  name: string,\n  value: string,\n  options: CookieOptions = {},\n): string {\n  const resolved = applyCookieNamePrefixRequirements(name, options);\n  let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;\n\n  if (resolved.maxAge != null) cookie += `; Max-Age=${resolved.maxAge}`;\n  if (resolved.expires) cookie += `; Expires=${resolved.expires.toUTCString()}`;\n  cookie += `; Path=${resolved.path || \"/\"}`;\n  if (resolved.domain) cookie += `; Domain=${resolved.domain}`;\n  if (resolved.secure) cookie += \"; Secure\";\n  if (resolved.httpOnly) cookie += \"; HttpOnly\";\n  if (resolved.sameSite) {\n    cookie += `; SameSite=${resolved.sameSite.charAt(0).toUpperCase()}${resolved.sameSite.slice(1)}`;\n  }\n\n  return cookie;\n}\n\n/**\n * Serialize the tombstone that removes a cookie. A deletion only matches the\n * stored cookie when its `Path` and `Domain` match the ones it was set with,\n * so callers must be able to pass them through.\n */\nexport function serializeMiddlewareCookieDeletion(\n  name: string,\n  options: CookieOptions = {},\n): string {\n  return serializeMiddlewareCookie(name, \"\", { ...options, maxAge: 0, expires: new Date(0) });\n}\n","import { createWebRequestFromFarmRequest } from \"../server/request\";\nimport type {\n  MiddlewareConfig,\n  MiddlewareContext,\n  MiddlewareFunction,\n  MiddlewareModule,\n  MiddlewareStore,\n  RequestMiddlewareContext,\n} from \"./types\";\n\nexport interface NormalizedMiddlewareModule {\n  handlers: MiddlewareFunction[];\n  config?: MiddlewareConfig;\n}\n\nfunction isWebRequest(request: unknown): request is Request {\n  return typeof Request !== \"undefined\" && request instanceof Request;\n}\n\nfunction toWebRequest(ctx: MiddlewareContext): Request {\n  if (isWebRequest(ctx.request)) {\n    return ctx.request;\n  }\n  return createWebRequestFromFarmRequest(ctx.request, { origin: ctx.url.origin });\n}\n\nfunction createRequestMiddlewareContext(\n  ctx: MiddlewareContext,\n): RequestMiddlewareContext<Record<string, any>, Record<string, any>> {\n  const context = {\n    get url() {\n      return ctx.url;\n    },\n    get pathname() {\n      return ctx.pathname;\n    },\n    get searchParams() {\n      return ctx.searchParams;\n    },\n    get method() {\n      return ctx.method;\n    },\n    get params() {\n      return ctx.params;\n    },\n    get route() {\n      return ctx.route;\n    },\n    get locals() {\n      return ctx.locals as MiddlewareStore<Record<string, any>>;\n    },\n    get data() {\n      return ctx.data as MiddlewareStore<Record<string, any>>;\n    },\n    get headers() {\n      return ctx.headers;\n    },\n    get cookies() {\n      return ctx.cookies;\n    },\n    get(key: string) {\n      return ctx.locals.get(key);\n    },\n    has(key: string) {\n      return ctx.locals.has(key);\n    },\n    set(key: string, value: any) {\n      ctx.locals.set(key, value);\n    },\n    delete(key: string) {\n      return ctx.locals.delete(key);\n    },\n    redirect(url: string, status?: number) {\n      ctx.redirect(url, status);\n    },\n    rewrite(url: string) {\n      ctx.rewrite(url);\n    },\n    json(data: any, status?: number) {\n      ctx.json(data, status);\n    },\n    text(content: string, status?: number) {\n      ctx.text(content, status);\n    },\n    html(content: string, status?: number) {\n      ctx.html(content, status);\n    },\n  } satisfies RequestMiddlewareContext;\n\n  return context;\n}\n\n/**\n * Normalize the two supported middleware file styles to Farm's internal chain.\n */\nexport function normalizeMiddlewareModule(\n  middlewareModule: MiddlewareModule | Record<string, any>,\n  routePath: string,\n): NormalizedMiddlewareModule | null {\n  const module = middlewareModule as MiddlewareModule;\n  const defaultExport = module.default;\n  const namedExport = module.middleware;\n  const hasNamedExport = typeof namedExport === \"function\";\n\n  if (namedExport !== undefined && !hasNamedExport) {\n    throw new TypeError(\"The named middleware export must be a function\");\n  }\n\n  if (defaultExport && hasNamedExport) {\n    throw new Error(\n      \"A middleware file cannot export both a default handler and a named middleware handler\",\n    );\n  }\n\n  if (hasNamedExport) {\n    return {\n      handlers: [\n        async (ctx) => {\n          return namedExport(toWebRequest(ctx), createRequestMiddlewareContext(ctx));\n        },\n      ],\n      config: module.config,\n    };\n  }\n\n  if (defaultExport && typeof defaultExport === \"object\" && \"build\" in defaultExport) {\n    if (typeof (defaultExport as any).setBasePath === \"function\") {\n      (defaultExport as any).setBasePath(routePath);\n    }\n    const built = (defaultExport as any).build();\n    const handlers = Array.isArray(built?.handlers)\n      ? built.handlers.filter((handler: unknown) => typeof handler === \"function\")\n      : [];\n    return handlers.length > 0\n      ? {\n          handlers,\n          config: module.config || built?.config,\n        }\n      : null;\n  }\n\n  if (typeof defaultExport === \"function\") {\n    return {\n      handlers: [defaultExport as MiddlewareFunction],\n      config: module.config,\n    };\n  }\n\n  return null;\n}\n"],"mappings":"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","names":[]}