"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/portal/index.ts
var portal_exports = {};
__export(portal_exports, {
  CUSTOMER_PORTAL_PATH: () => CUSTOMER_PORTAL_PATH,
  DEFAULT_LOGOUT_REDIRECT: () => DEFAULT_LOGOUT_REDIRECT,
  DEFAULT_PORTAL_REDIRECT: () => DEFAULT_PORTAL_REDIRECT,
  PORTAL_CODE_PARAM: () => PORTAL_CODE_PARAM,
  PORTAL_COOKIE_MAX_AGE: () => PORTAL_COOKIE_MAX_AGE,
  PORTAL_LOGIN_SUCCESS_PARAM: () => PORTAL_LOGIN_SUCCESS_PARAM,
  PORTAL_TOKEN_COOKIE: () => PORTAL_TOKEN_COOKIE,
  REDIRECT_TO_PARAM: () => REDIRECT_TO_PARAM,
  createPortalApiConfig: () => createPortalApiConfig,
  getDashboardUrl: () => getDashboardUrl,
  getPortalLoginUrl: () => getPortalLoginUrl,
  getPortalToken: () => getPortalToken,
  handlePortalCallback: () => handlePortalCallback,
  handlePortalLogout: () => handlePortalLogout,
  hasPortalSession: () => hasPortalSession,
  isValidRedirectPath: () => isValidRedirectPath
});
module.exports = __toCommonJS(portal_exports);

// src/portal/constants.ts
var PORTAL_TOKEN_COOKIE = "portal_token";
var PORTAL_COOKIE_MAX_AGE = 30 * 24 * 60 * 60;
var PORTAL_CODE_PARAM = "portal_code";
var REDIRECT_TO_PARAM = "redirect_to";
var CUSTOMER_PORTAL_PATH = "/portal";
var DEFAULT_PORTAL_REDIRECT = CUSTOMER_PORTAL_PATH;
var DEFAULT_LOGOUT_REDIRECT = "/";
var PORTAL_LOGIN_SUCCESS_PARAM = "portal_login";

// src/portal/callback.ts
var import_server = require("next/server");

// ../path-utils/src/redirectPaths.ts
var REDIRECT_BASE_URL = "https://redirect.local";
var CONTROL_CHAR_PATTERN = /[\u0000-\u001F\u007F]/;
var ENCODED_SEPARATOR_PATTERN = /%(?:2f|5c|00|0d|0a|252f|255c|2500|250d|250a)/i;
function prevalidateInput(value) {
  if (value === null || value === void 0) {
    return { ok: false, error: { tag: "MISSING" } };
  }
  if (typeof value !== "string") {
    return { ok: false, error: { tag: "INVALID_PATH" } };
  }
  const trimmed = value.trim();
  if (!trimmed) {
    return { ok: false, error: { tag: "EMPTY" } };
  }
  if (CONTROL_CHAR_PATTERN.test(trimmed)) {
    return { ok: false, error: { tag: "CONTROL_CHAR" } };
  }
  if (trimmed.includes("\\")) {
    return { ok: false, error: { tag: "BACKSLASH" } };
  }
  return trimmed;
}
function isHttpUrl(value) {
  return /^https?:\/\//i.test(value);
}
function pathContainsEncodedSeparator(pathname) {
  return ENCODED_SEPARATOR_PATTERN.test(pathname);
}
function parseRedirectPath(value, policy) {
  const normalized = prevalidateInput(value);
  if (typeof normalized !== "string") {
    return normalized;
  }
  const base = policy.tag === "same-origin" ? policy.baseUrl instanceof URL ? policy.baseUrl : new URL(policy.baseUrl) : new URL(REDIRECT_BASE_URL);
  if (!normalized.startsWith("/") && !isHttpUrl(normalized)) {
    return { ok: false, error: { tag: "INVALID_PATH" } };
  }
  if (policy.tag === "internal-only" && isHttpUrl(normalized)) {
    return { ok: false, error: { tag: "EXTERNAL_URL" } };
  }
  try {
    const candidate = new URL(normalized, base.origin);
    if (candidate.origin !== base.origin) {
      return { ok: false, error: { tag: "EXTERNAL_URL" } };
    }
    if (!candidate.pathname.startsWith("/")) {
      return { ok: false, error: { tag: "INVALID_PATH" } };
    }
    if (pathContainsEncodedSeparator(candidate.pathname)) {
      return { ok: false, error: { tag: "ENCODED_SEPARATOR" } };
    }
    return {
      ok: true,
      value: `${candidate.pathname}${candidate.search}${candidate.hash}`
    };
  } catch {
    return { ok: false, error: { tag: "INVALID_PATH" } };
  }
}
function parseInternalRedirectPath(value) {
  return parseRedirectPath(value, { tag: "internal-only" });
}

// ../path-utils/src/safeAppPath.ts
function parseSafeAppPath(value) {
  const result = parseInternalRedirectPath(value);
  return result.ok ? { ok: true, value: result.value } : result;
}
function sanitizeSafeAppPath(value) {
  const result = parseSafeAppPath(value);
  return result.ok ? result.value : null;
}
function assertSafeAppPath(value) {
  const result = parseSafeAppPath(value);
  if (!result.ok) {
    throw new Error(`Expected a safe app path, got ${result.error.tag}`);
  }
  return result.value;
}
function safeAppPathOrFallback(value, fallback) {
  const result = parseSafeAppPath(value);
  return result.ok ? result.value : fallback;
}
function buildSafeRedirectUrl(path, baseUrl) {
  const base = baseUrl instanceof URL ? baseUrl : new URL(baseUrl);
  const expectedOrigin = base.origin;
  const resolved = new URL(path, expectedOrigin);
  if (resolved.origin !== expectedOrigin) {
    throw new Error("Safe app path resolved to an unexpected origin");
  }
  return resolved;
}

// src/portal/redirects.ts
var DEPRECATED_REDIRECT_PATH_WARNING = '[SDK] handlePortalCallback/handlePortalLogout: "redirectPath" is deprecated, use "defaultRedirectPath"';
function resolveRedirectPathOption({
  options,
  defaultValue,
  warn,
  nodeEnv
}) {
  if (options.defaultRedirectPath !== void 0) {
    return options.defaultRedirectPath;
  }
  if (options.redirectPath !== void 0) {
    if (nodeEnv !== "production") {
      warn(DEPRECATED_REDIRECT_PATH_WARNING);
    }
    return options.redirectPath;
  }
  return defaultValue;
}
function resolveDefaultRedirect(options, defaultValue, warn = console.warn, nodeEnv = process.env.NODE_ENV) {
  return assertSafeAppPath(
    resolveRedirectPathOption({
      options,
      defaultValue,
      warn,
      nodeEnv
    })
  );
}
function resolveCallbackRedirect(redirectTo, defaultRedirect) {
  return safeAppPathOrFallback(redirectTo, defaultRedirect);
}
function resolveLogoutRedirect({
  defaultRedirect,
  formRedirect,
  queryRedirect
}) {
  if (typeof formRedirect === "string") {
    const sanitized = sanitizeSafeAppPath(formRedirect);
    if (sanitized) {
      return sanitized;
    }
  }
  const querySanitized = sanitizeSafeAppPath(queryRedirect);
  return querySanitized ?? defaultRedirect;
}

// src/portal/callback.ts
function isProduction() {
  return process.env.NODE_ENV === "production";
}
function getRequestOrigin(request) {
  const url = request.nextUrl;
  const forwardedHostRaw = request.headers.get("x-forwarded-host");
  const forwardedHost = forwardedHostRaw?.split(",")[0]?.trim();
  const hostRaw = request.headers.get("host");
  const host = hostRaw?.split(",")[0]?.trim();
  const isInternalHost = (value) => {
    const normalized = value.toLowerCase();
    return normalized.includes("localhost") || normalized.endsWith(".local") || normalized.startsWith("127.") || normalized.startsWith("0.0.0.0") || normalized.startsWith("[::1]") || normalized === "::1";
  };
  const hostHeader = forwardedHost && (!host || isInternalHost(host) && !isInternalHost(forwardedHost)) ? forwardedHost : host || url.host;
  const forwardedProtoRaw = request.headers.get("x-forwarded-proto");
  const forwardedProto = forwardedProtoRaw?.split(",")[0]?.trim();
  const isLocalHost = hostHeader.includes("localhost") || hostHeader.includes(".local");
  const protocol = forwardedProto || (isLocalHost ? "http" : url.protocol.replace(":", ""));
  return `${protocol}://${hostHeader}`;
}
function getDashboardUrl() {
  const target = process.env.RIVERBANK_ENV?.toLowerCase();
  const prefix = target === "remote" || target === "production" || target === "prod" ? "RIVERBANK_REMOTE" : "RIVERBANK_LOCAL";
  const url = process.env[`${prefix}_DASHBOARD_URL`];
  if (!url) return null;
  return url.replace(/\/api$/, "").replace(/\/$/, "");
}
function resolveDashboardUrl(option) {
  if (typeof option === "string") return option;
  if (typeof option === "function") return option();
  return getDashboardUrl();
}
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;
}
async function exchangePortalCode(params) {
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), params.timeoutMs);
  try {
    const response = await fetch(`${params.dashboardUrl}/api/portal/auth/exchange`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      cache: "no-store",
      body: JSON.stringify({
        portalCode: params.portalCode,
        callbackOrigin: params.callbackOrigin
      }),
      signal: controller.signal
    });
    const json = await response.json().catch(() => null);
    if (response.ok && isApiSuccessEnvelope(json)) {
      return { success: true, payload: json.data };
    }
    const fallbackMessage = response.status >= 500 ? "Unable to complete portal sign-in right now. Please try again." : "Invalid or expired portal code.";
    const envelopeMessage = isApiErrorEnvelope(json) && typeof json.error?.message === "string" ? json.error.message : null;
    return {
      success: false,
      status: response.status,
      message: envelopeMessage ?? fallbackMessage
    };
  } catch {
    return {
      success: false,
      status: 502,
      message: "Unable to complete portal sign-in right now. Please try again."
    };
  } finally {
    clearTimeout(timeout);
  }
}
function handlePortalCallback(options = {}) {
  const defaultRedirect = resolveDefaultRedirect(options, DEFAULT_PORTAL_REDIRECT);
  const secure = options.secure ?? isProduction();
  const exchangeTimeoutMs = options.exchangeTimeoutMs ?? 1e4;
  const { dashboardUrl } = options;
  return async function GET(request) {
    const { searchParams } = request.nextUrl;
    const portalCode = searchParams.get(PORTAL_CODE_PARAM);
    const redirectTo = searchParams.get(REDIRECT_TO_PARAM);
    const finalRedirect = resolveCallbackRedirect(redirectTo, defaultRedirect);
    if (!portalCode) {
      return import_server.NextResponse.json({ error: "Missing portal_code parameter" }, { status: 400 });
    }
    const url = resolveDashboardUrl(dashboardUrl);
    if (!url) {
      return import_server.NextResponse.json({ error: "Dashboard URL is not configured" }, { status: 500 });
    }
    const callbackOrigin = getRequestOrigin(request);
    const exchangeResult = await exchangePortalCode({
      dashboardUrl: url,
      portalCode,
      callbackOrigin,
      timeoutMs: exchangeTimeoutMs
    });
    if (!exchangeResult.success) {
      const status = exchangeResult.status >= 500 || exchangeResult.status <= 0 ? 502 : exchangeResult.status;
      return import_server.NextResponse.json({ error: exchangeResult.message }, { status });
    }
    const redirectUrl = buildSafeRedirectUrl(finalRedirect, getRequestOrigin(request));
    redirectUrl.searchParams.set(PORTAL_LOGIN_SUCCESS_PARAM, "success");
    const response = import_server.NextResponse.redirect(redirectUrl);
    response.headers.set("Referrer-Policy", "no-referrer");
    response.headers.set("Cache-Control", "no-store");
    response.cookies.set(PORTAL_TOKEN_COOKIE, exchangeResult.payload.sessionToken, {
      httpOnly: true,
      secure,
      sameSite: "lax",
      path: "/",
      maxAge: PORTAL_COOKIE_MAX_AGE
    });
    return response;
  };
}
function handlePortalLogout(options = {}) {
  const defaultRedirect = resolveDefaultRedirect(options, DEFAULT_LOGOUT_REDIRECT);
  const secure = options.secure ?? isProduction();
  const { dashboardUrl } = options;
  return async function POST(request) {
    const portalToken = request.cookies.get(PORTAL_TOKEN_COOKIE)?.value;
    let formRedirect = null;
    try {
      const formData = await request.formData();
      formRedirect = formData.get(REDIRECT_TO_PARAM);
    } catch {
    }
    const redirectTo = resolveLogoutRedirect({
      defaultRedirect,
      formRedirect,
      queryRedirect: request.nextUrl.searchParams.get(REDIRECT_TO_PARAM)
    });
    if (portalToken) {
      const url = resolveDashboardUrl(dashboardUrl);
      if (url) {
        try {
          await fetch(`${url}/api/portal/auth/logout`, {
            method: "POST",
            headers: {
              Authorization: `Bearer ${portalToken}`
            }
          });
        } catch {
        }
      }
    }
    const redirectUrl = buildSafeRedirectUrl(redirectTo, getRequestOrigin(request));
    const response = import_server.NextResponse.redirect(redirectUrl);
    response.cookies.set(PORTAL_TOKEN_COOKIE, "", {
      httpOnly: true,
      secure,
      sameSite: "lax",
      path: "/",
      maxAge: 0
      // Expire immediately
    });
    return response;
  };
}

// src/portal/validation.ts
function isValidRedirectPath(path) {
  return sanitizeSafeAppPath(path) !== null;
}

// src/portal/token.ts
function getPortalToken(cookieStore) {
  const cookie = cookieStore.get(PORTAL_TOKEN_COOKIE);
  return cookie?.value ?? null;
}
function hasPortalSession(cookieStore) {
  return getPortalToken(cookieStore) !== null;
}

// src/portal/config.ts
function createPortalApiConfig(options) {
  const { token, siteId, dashboardUrl } = options;
  const baseUrl = dashboardUrl.endsWith("/") ? `${dashboardUrl.slice(0, -1)}/api` : `${dashboardUrl}/api`;
  return {
    baseUrl,
    auth: { type: "bearer", token },
    siteId
  };
}
function getPortalLoginUrl(dashboardUrl) {
  const baseUrl = dashboardUrl.endsWith("/") ? dashboardUrl.slice(0, -1) : dashboardUrl;
  return `${baseUrl}/api/portal/auth/send-magic-link`;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  CUSTOMER_PORTAL_PATH,
  DEFAULT_LOGOUT_REDIRECT,
  DEFAULT_PORTAL_REDIRECT,
  PORTAL_CODE_PARAM,
  PORTAL_COOKIE_MAX_AGE,
  PORTAL_LOGIN_SUCCESS_PARAM,
  PORTAL_TOKEN_COOKIE,
  REDIRECT_TO_PARAM,
  createPortalApiConfig,
  getDashboardUrl,
  getPortalLoginUrl,
  getPortalToken,
  handlePortalCallback,
  handlePortalLogout,
  hasPortalSession,
  isValidRedirectPath
});
//# sourceMappingURL=portal.js.map