v1.0.16
// middlewares/cookie/cookie.ts

import type { Middleware } from "../../core/types.ts";

export type CookieOptions = {
  path?: string;
  domain?: string;
  maxAge?: number;
  expires?: Date;
  secure?: boolean;
  httpOnly?: boolean;
  sameSite?: "Lax" | "Strict" | "None";
};

function parseCookies(header: string): Record<string, string> {
  const out: Record<string, string> = {};
  if (!header) return out;
  for (const part of header.split(";")) {
    const trimmed = part.trim();
    if (!trimmed) continue;
    const eq = trimmed.indexOf("=");
    const name = eq >= 0 ? trimmed.slice(0, eq) : trimmed;
    const val = eq >= 0 ? trimmed.slice(eq + 1) : "";
    out[name] = decodeURIComponent(val);
  }
  return out;
}

function formatCookie(
  name: string,
  value: string,
  opts?: CookieOptions,
): string {
  const parts: string[] = [];
  parts.push(`${name}=${encodeURIComponent(value)}`);
  if (opts?.maxAge !== undefined) {
    parts.push(`Max-Age=${Math.floor(opts.maxAge)}`);
  }
  if (opts?.expires) parts.push(`Expires=${opts.expires.toUTCString()}`);
  if (opts?.domain) parts.push(`Domain=${opts.domain}`);
  if (opts?.path) parts.push(`Path=${opts.path}`);
  if (opts?.secure) parts.push("Secure");
  if (opts?.httpOnly) parts.push("HttpOnly");
  if (opts?.sameSite) parts.push(`SameSite=${opts.sameSite}`);
  return parts.join("; ");
}

export const cookieMiddleware: Middleware = async (req, context, next) => {
  context.cookies = parseCookies(req.headers.get("cookie") ?? "");

  const pending: string[] = [];
  context.setCookie = (name: string, value: string, opts?: CookieOptions) => {
    pending.push(formatCookie(name, value, opts));
  };

  const res = await next();

  if (pending.length === 0) return res;

  const headers = new Headers(res.headers);
  for (const c of pending) headers.append("Set-Cookie", c);

  return new Response(res.body, {
    status: res.status,
    statusText: res.statusText,
    headers,
  });
};