'use strict';

var chunkSXKQ7CSX_cjs = require('./chunk-SXKQ7CSX.cjs');

// src/server/auth/defaults.ts
var defaultAuthConfig = {
  protected: ["/api/*"],
  public: ["/api", "/api/auth/*"],
  // Simple rule system
  rules: [
    // Admin users can do anything
    {
      condition: (user) => {
        if (typeof user === "object" && user !== null) {
          if ("isAdmin" in user) {
            return !!user.isAdmin;
          }
          if ("role" in user) {
            return user.role === "admin";
          }
        }
        return false;
      },
      allow: true
    }
  ]
};

// src/server/auth/path-pattern.ts
function parse(input, loose) {
  if (input instanceof RegExp) return { keys: false, pattern: input };
  let c;
  let o;
  let tmp;
  let ext;
  const keys = [];
  let pattern = "";
  const arr = input.split("/");
  arr[0] || arr.shift();
  while (tmp = arr.shift()) {
    c = tmp[0];
    if (c === "*") {
      keys.push(c);
      pattern += tmp[1] === "?" ? "(?:/(.*))?" : "/(.*)";
    } else if (c === ":") {
      o = tmp.indexOf("?", 1);
      ext = tmp.indexOf(".", 1);
      keys.push(tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length));
      pattern += !!~o && !~ext ? "(?:/([^/]+?))?" : "/([^/]+?)";
      if (!!~ext) pattern += (!!~o ? "?" : "") + "\\" + tmp.substring(ext);
    } else {
      pattern += "/" + tmp;
    }
  }
  return {
    keys,
    pattern: new RegExp("^" + pattern + ("/?$"), "i")
  };
}

// src/server/auth/helpers.ts
var isProtectedCustomRoute = (path, method, customRouteAuthConfig) => {
  if (!customRouteAuthConfig) {
    return false;
  }
  const exactRouteKey = `${method}:${path}`;
  if (customRouteAuthConfig.has(exactRouteKey)) {
    return customRouteAuthConfig.get(exactRouteKey) === true;
  }
  const allRouteKey = `ALL:${path}`;
  if (customRouteAuthConfig.has(allRouteKey)) {
    return customRouteAuthConfig.get(allRouteKey) === true;
  }
  for (const [routeKey, requiresAuth] of customRouteAuthConfig.entries()) {
    const colonIndex = routeKey.indexOf(":");
    if (colonIndex === -1) {
      continue;
    }
    const routeMethod = routeKey.substring(0, colonIndex);
    const routePattern = routeKey.substring(colonIndex + 1);
    if (routeMethod !== method && routeMethod !== "ALL") {
      continue;
    }
    if (pathMatchesPattern(path, routePattern)) {
      return requiresAuth === true;
    }
  }
  return false;
};
var findMatchingCustomRoute = (path, method, apiRoutes) => {
  if (!apiRoutes) return void 0;
  for (const route of apiRoutes) {
    if (route.method !== method && route.method !== "ALL") continue;
    const { keys, pattern: regex } = parse(route.path);
    const match = regex.exec(path);
    if (!match) continue;
    const params = {};
    if (keys && keys.length > 0) {
      for (let i = 0; i < keys.length; i++) {
        if (match[i + 1] !== void 0) {
          params[keys[i]] = match[i + 1];
        }
      }
    }
    return { route, params };
  }
  return void 0;
};
var isDevPlaygroundRequest = (path, method, getHeader, authConfig, customRouteAuthConfig) => {
  const protectedAccess = [...defaultAuthConfig.protected || [], ...authConfig.protected || []];
  return process.env.MASTRA_DEV === "true" && // Allow if path doesn't match protected patterns AND is not a protected custom route
  (!isAnyMatch(path, method, protectedAccess) && !isProtectedCustomRoute(path, method, customRouteAuthConfig) || // Or if has playground header
  getHeader("x-mastra-dev-playground") === "true");
};
var isCustomRoutePublic = (path, method, customRouteAuthConfig) => {
  if (!customRouteAuthConfig) {
    return false;
  }
  const exactRouteKey = `${method}:${path}`;
  if (customRouteAuthConfig.has(exactRouteKey)) {
    return !customRouteAuthConfig.get(exactRouteKey);
  }
  const allRouteKey = `ALL:${path}`;
  if (customRouteAuthConfig.has(allRouteKey)) {
    return !customRouteAuthConfig.get(allRouteKey);
  }
  for (const [routeKey, requiresAuth] of customRouteAuthConfig.entries()) {
    const colonIndex = routeKey.indexOf(":");
    if (colonIndex === -1) {
      continue;
    }
    const routeMethod = routeKey.substring(0, colonIndex);
    const routePattern = routeKey.substring(colonIndex + 1);
    if (routeMethod !== method && routeMethod !== "ALL") {
      continue;
    }
    if (pathMatchesPattern(path, routePattern)) {
      return !requiresAuth;
    }
  }
  return false;
};
var isProtectedPath = (path, method, authConfig, customRouteAuthConfig) => {
  const protectedAccess = [...defaultAuthConfig.protected || [], ...authConfig.protected || []];
  return isAnyMatch(path, method, protectedAccess) || isProtectedCustomRoute(path, method, customRouteAuthConfig);
};
var canAccessPublicly = (path, method, authConfig) => {
  const publicAccess = [...defaultAuthConfig.public || [], ...authConfig.public || []];
  return isAnyMatch(path, method, publicAccess);
};
var isAnyMatch = (path, method, patterns) => {
  if (!patterns) {
    return false;
  }
  for (const patternPathOrMethod of patterns) {
    if (patternPathOrMethod instanceof RegExp) {
      if (patternPathOrMethod.test(path)) {
        return true;
      }
    }
    if (typeof patternPathOrMethod === "string" && pathMatchesPattern(path, patternPathOrMethod)) {
      return true;
    }
    if (Array.isArray(patternPathOrMethod) && patternPathOrMethod.length === 2) {
      const [pattern, methodOrMethods] = patternPathOrMethod;
      if (pathMatchesPattern(path, pattern) && matchesOrIncludes(methodOrMethods, method)) {
        return true;
      }
    }
  }
  return false;
};
var pathMatchesPattern = (path, pattern) => {
  const { pattern: regex } = parse(pattern);
  return regex.test(path);
};
var pathMatchesRule = (path, rulePath) => {
  if (!rulePath) return true;
  if (typeof rulePath === "string") {
    return pathMatchesPattern(path, rulePath);
  }
  if (rulePath instanceof RegExp) {
    return rulePath.test(path);
  }
  if (Array.isArray(rulePath)) {
    return rulePath.some((p) => pathMatchesPattern(path, p));
  }
  return false;
};
var matchesOrIncludes = (values, value) => {
  if (typeof values === "string") {
    return values === value;
  }
  if (Array.isArray(values)) {
    return values.includes(value);
  }
  return false;
};
var pass = { action: "next" };
var adaptToMastraAuthRequest = (request) => {
  if (!(request instanceof Request)) {
    return request;
  }
  return {
    raw: request,
    headers: request.headers,
    header: (name) => request.headers.get(name) ?? void 0
  };
};
var getAuthenticatedUser = async ({
  mastra,
  token,
  request
}) => {
  const normalizedToken = token.replace(/^Bearer\s+/i, "").trim();
  if (!normalizedToken) {
    return null;
  }
  const authConfig = mastra.getServer()?.auth;
  if (!authConfig || typeof authConfig.authenticateToken !== "function") {
    return null;
  }
  return await authConfig.authenticateToken(normalizedToken, request);
};
function supportsSessionRefresh(authConfig) {
  return typeof authConfig.getSessionIdFromRequest === "function" && typeof authConfig.refreshSession === "function" && typeof authConfig.getSessionHeaders === "function";
}
var coreAuthMiddleware = async (ctx) => {
  const {
    path,
    method,
    getHeader,
    mastra,
    authConfig,
    customRouteAuthConfig,
    requestContext,
    rawRequest,
    token,
    requiresAuth
  } = ctx;
  const hasAuthProvider = typeof authConfig.authenticateToken === "function";
  if (!hasAuthProvider && isDevPlaygroundRequest(path, method, getHeader, authConfig, customRouteAuthConfig)) {
    return pass;
  }
  if (!isProtectedPath(path, method, authConfig, customRouteAuthConfig)) {
    return pass;
  }
  if (!requiresAuth && canAccessPublicly(path, method, authConfig)) {
    return pass;
  }
  let user;
  let refreshHeaders;
  const authRequest = adaptToMastraAuthRequest(rawRequest);
  try {
    if (typeof authConfig.authenticateToken === "function") {
      user = await authConfig.authenticateToken(token ?? "", authRequest);
    } else {
      throw new Error("No token verification method configured");
    }
    if (!user && supportsSessionRefresh(authConfig) && rawRequest instanceof Request) {
      try {
        const sessionId = authConfig.getSessionIdFromRequest(rawRequest);
        if (sessionId) {
          const newSession = await authConfig.refreshSession(sessionId);
          if (newSession) {
            refreshHeaders = authConfig.getSessionHeaders(newSession);
            const refreshedCookie = Object.entries(refreshHeaders).filter(([k]) => k.toLowerCase() === "set-cookie").map(([, v]) => v.split(";")[0]).join("; ");
            if (refreshedCookie) {
              const refreshedRequest = new Request(rawRequest.url, {
                method: rawRequest.method,
                headers: new Headers(rawRequest.headers)
              });
              refreshedRequest.headers.set("Cookie", refreshedCookie);
              const cookieValue = refreshedCookie.includes("=") ? refreshedCookie.split("=").slice(1).join("=") : refreshedCookie;
              user = await authConfig.authenticateToken(cookieValue, adaptToMastraAuthRequest(refreshedRequest));
            }
            if (!user) {
              refreshHeaders = void 0;
            }
          }
        }
      } catch (refreshErr) {
        refreshHeaders = void 0;
        mastra.getLogger()?.debug("Session refresh failed, falling back to 401", {
          error: refreshErr instanceof Error ? { message: refreshErr.message } : refreshErr
        });
      }
    }
    if (!user) {
      return { action: "error", status: 401, body: { error: "Invalid or expired token" }, headers: refreshHeaders };
    }
    requestContext.set(chunkSXKQ7CSX_cjs.MASTRA_USER_KEY, user);
    requestContext.set("user", user);
    let effectiveToken = token;
    if (!effectiveToken && rawRequest instanceof Request) {
      const cookieHeader = rawRequest.headers.get("cookie");
      if (cookieHeader) {
        const match = cookieHeader.match(/mastra-token=([^;]+)/);
        if (match?.[1]) effectiveToken = match[1];
      }
    }
    if (effectiveToken) {
      requestContext.set(chunkSXKQ7CSX_cjs.MASTRA_AUTH_TOKEN_KEY, effectiveToken);
    }
    if (typeof authConfig.mapUserToResourceId === "function") {
      try {
        const resourceId = authConfig.mapUserToResourceId(user);
        if (resourceId) {
          requestContext.set(chunkSXKQ7CSX_cjs.MASTRA_RESOURCE_ID_KEY, resourceId);
        }
      } catch (mapError) {
        mastra.getLogger()?.error("mapUserToResourceId failed", {
          error: mapError instanceof Error ? { message: mapError.message, stack: mapError.stack } : mapError
        });
        return {
          action: "error",
          status: 500,
          body: { error: "Failed to map authenticated user to a resource ID" },
          headers: refreshHeaders
        };
      }
    }
    try {
      const authMode = requestContext.get(chunkSXKQ7CSX_cjs.MASTRA_AUTH_MODE_KEY);
      const serverConfig = mastra.getServer();
      const studioConfig = mastra.getStudio?.();
      const rbacProvider = authMode === "studio" ? studioConfig?.rbac ?? serverConfig?.rbac : serverConfig?.rbac;
      if (rbacProvider) {
        if (!user || typeof user !== "object" || !("id" in user)) {
          mastra.getLogger()?.warn('RBAC: authenticated user missing required "id" field, skipping permission loading');
        } else {
          const permissions = await rbacProvider.getPermissions(user);
          requestContext.set(chunkSXKQ7CSX_cjs.MASTRA_USER_PERMISSIONS_KEY, permissions);
          requestContext.set("userPermissions", permissions);
          const roles = await rbacProvider.getRoles(user);
          requestContext.set(chunkSXKQ7CSX_cjs.MASTRA_USER_ROLES_KEY, roles);
          requestContext.set("userRoles", roles);
        }
      }
    } catch (rbacError) {
      mastra.getLogger()?.error("RBAC: failed to load user permissions/roles", {
        error: rbacError instanceof Error ? { message: rbacError.message, stack: rbacError.stack } : rbacError
      });
    }
  } catch (err) {
    mastra.getLogger()?.error("Authentication error", {
      error: err instanceof Error ? { message: err.message, stack: err.stack } : err
    });
    return { action: "error", status: 401, body: { error: "Invalid or expired token" }, headers: refreshHeaders };
  }
  if ("authorizeUser" in authConfig && typeof authConfig.authorizeUser === "function") {
    try {
      const isAuthorized = await authConfig.authorizeUser(user, authRequest);
      if (!isAuthorized) {
        return { action: "error", status: 403, body: { error: "Access denied" }, headers: refreshHeaders };
      }
    } catch (err) {
      mastra.getLogger()?.error("Authorization error in authorizeUser", {
        error: err instanceof Error ? { message: err.message, stack: err.stack } : err
      });
      return { action: "error", status: 500, body: { error: "Authorization error" }, headers: refreshHeaders };
    }
  } else if ("authorize" in authConfig && typeof authConfig.authorize === "function") {
    try {
      const authorizeCtx = ctx.buildAuthorizeContext();
      const isAuthorized = await authConfig.authorize(path, method, user, authorizeCtx);
      if (!isAuthorized) {
        return { action: "error", status: 403, body: { error: "Access denied" }, headers: refreshHeaders };
      }
    } catch (err) {
      mastra.getLogger()?.error("Authorization error in authorize", {
        error: err instanceof Error ? { message: err.message, stack: err.stack } : err,
        path,
        method
      });
      return { action: "error", status: 500, body: { error: "Authorization error" }, headers: refreshHeaders };
    }
  } else if ("rules" in authConfig && authConfig.rules && authConfig.rules.length > 0) {
    const isAuthorized = await checkRules(authConfig.rules, path, method, user);
    if (!isAuthorized) {
      return { action: "error", status: 403, body: { error: "Access denied" }, headers: refreshHeaders };
    }
  } else {
    const rbacProvider = mastra.getServer()?.rbac;
    if (rbacProvider) {
      if (defaultAuthConfig.rules && defaultAuthConfig.rules.length > 0) {
        const isAuthorized = await checkRules(defaultAuthConfig.rules, path, method, user);
        if (!isAuthorized) {
          return { action: "error", status: 403, body: { error: "Access denied" }, headers: refreshHeaders };
        }
      } else {
        return { action: "error", status: 403, body: { error: "Access denied" }, headers: refreshHeaders };
      }
    }
  }
  return refreshHeaders ? { action: "next", headers: refreshHeaders } : pass;
};
var checkRules = async (rules, path, method, user) => {
  for (const i in rules || []) {
    const rule = rules?.[i];
    if (!pathMatchesRule(path, rule.path)) {
      continue;
    }
    if (rule.methods && !matchesOrIncludes(rule.methods, method)) {
      continue;
    }
    const condition = rule.condition;
    if (typeof condition === "function") {
      const allowed = await Promise.resolve().then(() => condition(user)).catch(() => false);
      if (allowed) {
        return true;
      }
    } else if (rule.allow) {
      return true;
    }
  }
  return false;
};

exports.canAccessPublicly = canAccessPublicly;
exports.checkRules = checkRules;
exports.coreAuthMiddleware = coreAuthMiddleware;
exports.defaultAuthConfig = defaultAuthConfig;
exports.findMatchingCustomRoute = findMatchingCustomRoute;
exports.getAuthenticatedUser = getAuthenticatedUser;
exports.isCustomRoutePublic = isCustomRoutePublic;
exports.isDevPlaygroundRequest = isDevPlaygroundRequest;
exports.isProtectedCustomRoute = isProtectedCustomRoute;
exports.isProtectedPath = isProtectedPath;
exports.matchesOrIncludes = matchesOrIncludes;
exports.pathMatchesPattern = pathMatchesPattern;
exports.pathMatchesRule = pathMatchesRule;
exports.supportsSessionRefresh = supportsSessionRefresh;
//# sourceMappingURL=chunk-SYZ2NTP3.cjs.map
//# sourceMappingURL=chunk-SYZ2NTP3.cjs.map