// ../preview-next/src/middleware.ts
import { NextResponse } from "next/server.js";

// ../preview-next/src/constants.ts
var PREVIEW_COOKIE_NAME = "preview_token";
var PREVIEW_REFRESH_COOKIE_NAME = "preview_refresh_token";
var PREVIEW_COOKIE_MAX_AGE = 60 * 60 * 12;
var PREVIEW_CODE_PARAM = "preview_code";

// ../preview-next/src/cookies.ts
function getPreviewCookieOptions(options = {}) {
  const { maxAge = PREVIEW_COOKIE_MAX_AGE, secure } = options;
  const resolvedSecure = secure ?? process.env.NODE_ENV === "production";
  return {
    httpOnly: true,
    secure: resolvedSecure,
    sameSite: "lax",
    path: "/",
    maxAge
  };
}
function setPreviewCookie(res, token, options) {
  res.cookies.set(PREVIEW_COOKIE_NAME, token, getPreviewCookieOptions(options));
  return res;
}
function setPreviewRefreshCookie(res, token, options) {
  res.cookies.set(PREVIEW_REFRESH_COOKIE_NAME, token, getPreviewCookieOptions(options));
  return res;
}
function setPreviewAuthCookies(res, {
  accessToken,
  refreshToken
}, options) {
  if (accessToken) {
    setPreviewCookie(res, accessToken, options);
  }
  if (refreshToken) {
    setPreviewRefreshCookie(res, refreshToken, options);
  }
  return res;
}

// ../preview-next/src/middleware.ts
var EXCHANGE_CODE_PATTERN = /^[A-Za-z0-9_-]{40,256}$/;
function getRequestUrl(request) {
  const nextUrl = request.nextUrl;
  if (nextUrl && typeof nextUrl.href === "string") {
    return new URL(nextUrl.href);
  }
  return new URL(request.url);
}
function resolveRedirectHost(request, url) {
  const forwardedHost = (request.headers.get("x-forwarded-host") ?? "").split(",")[0]?.trim();
  const hostHeader = (request.headers.get("host") ?? "").split(",")[0]?.trim();
  if (forwardedHost && (forwardedHost === url.host || forwardedHost.endsWith(url.host))) {
    return forwardedHost;
  }
  return hostHeader || url.host;
}
function resolveRedirectProtocol(request, url, host) {
  if (host.includes("localhost") || host.includes(".local")) return "http";
  const forwardedProto = (request.headers.get("x-forwarded-proto") ?? "").split(",")[0]?.trim();
  if (forwardedProto === "https" || forwardedProto === "http") return forwardedProto;
  return url.protocol.replace(":", "");
}
function buildCleanRedirectUrl(request) {
  const url = getRequestUrl(request);
  const host = resolveRedirectHost(request, url);
  const protocol = resolveRedirectProtocol(request, url, host);
  const cleanUrl = new URL(`${protocol}://${host}${url.pathname}${url.hash ?? ""}`);
  url.searchParams.forEach((value, key) => {
    if (key === PREVIEW_CODE_PARAM || key === "token" || key === "refreshToken" || key === "refresh") return;
    cleanUrl.searchParams.set(key, value);
  });
  return cleanUrl;
}
function buildRedirectResponse(cleanUrl) {
  const res = NextResponse.redirect(cleanUrl, { status: 302 });
  res.headers.set("Referrer-Policy", "no-referrer");
  res.headers.set("Cache-Control", "no-store");
  return res;
}
function parsePreviewCode(value) {
  if (!value) return { kind: "missing" };
  if (!EXCHANGE_CODE_PATTERN.test(value)) return { kind: "invalid" };
  return { kind: "valid", code: value };
}
function normalizeDashboardUrl(value) {
  if (!value) return null;
  try {
    const parsed = new URL(value);
    if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
    parsed.pathname = "";
    parsed.search = "";
    parsed.hash = "";
    return parsed.toString().replace(/\/$/, "");
  } catch {
    return null;
  }
}
function isApiSuccessEnvelope(value) {
  return value !== null && typeof value === "object" && "success" in value && value.success === true && "data" in value;
}
function isApiErrorEnvelope(value) {
  return value !== null && typeof value === "object" && "success" in value && value.success === false;
}
function isPreviewExchangeSuccessPayload(value) {
  return value !== null && typeof value === "object" && typeof value.accessToken === "string" && (typeof value.refreshToken === "string" || value.refreshToken === null) && typeof value.siteId === "string" && typeof value.expiresAt === "string";
}
async function exchangePreviewCode(params) {
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), params.timeoutMs);
  try {
    const response = await params.fetcher(`${params.dashboardUrl}/api/preview/auth/exchange`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      cache: "no-store",
      body: JSON.stringify({
        previewCode: params.previewCode,
        callbackOrigin: params.callbackOrigin
      }),
      signal: controller.signal
    });
    const json = await response.json().catch(() => null);
    if (response.ok && isApiSuccessEnvelope(json) && isPreviewExchangeSuccessPayload(json.data)) {
      return { success: true, payload: json.data };
    }
    if (response.ok) {
      return {
        success: false,
        status: response.status,
        reason: "invalid_exchange_response"
      };
    }
    const message = isApiErrorEnvelope(json) && typeof json.error?.message === "string" ? json.error.message : void 0;
    return {
      success: false,
      status: response.status,
      reason: "exchange_rejected",
      ...message ? { message } : {}
    };
  } catch {
    return {
      success: false,
      status: 502,
      reason: "exchange_request_failed"
    };
  } finally {
    clearTimeout(timeout);
  }
}
async function handlePreviewTokens(request, options = {}) {
  const req = request;
  const url = getRequestUrl(req);
  const parsedPreviewCode = parsePreviewCode(url.searchParams.get(PREVIEW_CODE_PARAM));
  if (parsedPreviewCode.kind === "missing") return null;
  const cleanUrl = buildCleanRedirectUrl(req);
  const response = buildRedirectResponse(cleanUrl);
  if (parsedPreviewCode.kind === "invalid") {
    options.onExchangeFailure?.({
      reason: "invalid_code_format",
      status: 400
    });
    return response;
  }
  const dashboardUrl = normalizeDashboardUrl(options.dashboardUrl);
  if (!dashboardUrl) {
    options.onExchangeFailure?.({
      reason: "missing_dashboard_url"
    });
    return response;
  }
  const exchangeResult = await exchangePreviewCode({
    dashboardUrl,
    previewCode: parsedPreviewCode.code,
    callbackOrigin: cleanUrl.origin,
    timeoutMs: options.exchangeTimeoutMs ?? 1e4,
    fetcher: options.fetcher ?? fetch
  });
  if (!exchangeResult.success) {
    options.onExchangeFailure?.({
      reason: exchangeResult.reason,
      status: exchangeResult.status,
      ...exchangeResult.message ? { message: exchangeResult.message } : {}
    });
    return response;
  }
  const maxAge = options.maxAge ?? PREVIEW_COOKIE_MAX_AGE;
  const secure = cleanUrl.protocol === "https:";
  setPreviewAuthCookies(
    response,
    {
      accessToken: exchangeResult.payload.accessToken,
      refreshToken: exchangeResult.payload.refreshToken
    },
    { maxAge, secure }
  );
  return response;
}
export {
  handlePreviewTokens
};
//# sourceMappingURL=middleware.mjs.map