'use strict';

var chunkKURYHRSI_cjs = require('../../chunk-KURYHRSI.cjs');
var chunkSYZ2NTP3_cjs = require('../../chunk-SYZ2NTP3.cjs');
var chunkDRDVJ35H_cjs = require('../../chunk-DRDVJ35H.cjs');
var chunkSXKQ7CSX_cjs = require('../../chunk-SXKQ7CSX.cjs');
var chunkZ7LCIYK7_cjs = require('../../chunk-Z7LCIYK7.cjs');
var chunkN54Q3AQR_cjs = require('../../chunk-N54Q3AQR.cjs');
var stream = require('stream');
var promises = require('stream/promises');
var requestContext = require('@mastra/core/request-context');
var server = require('@mastra/core/server');
var hono = require('hono');
var v4 = require('zod/v4');
var utils = require('@mastra/core/utils');

// src/server/server-adapter/routes/fga-manifest.ts
function isProtectedFGARoute(route) {
  return route.requiresAuth !== false;
}
function getToolRoutePermission(path) {
  return path.includes("/execute") ? "tools:execute" : "tools:read";
}
function getAgentToolResourceId(agentId, toolId) {
  return `${agentId}:${toolId}`;
}
function getMCPToolResourceId(serverId, toolId) {
  return JSON.stringify([serverId, toolId]);
}
var STORED_ROUTE_FGA = {
  agents: { resourceType: "stored-agents", idParams: ["storedAgentId", "agentId"] },
  "mcp-clients": { resourceType: "stored-mcp-clients", idParams: ["storedMCPClientId", "mcpClientId"] },
  "prompt-blocks": { resourceType: "stored-prompt-blocks", idParams: ["storedPromptBlockId", "promptBlockId"] },
  scorers: { resourceType: "stored-scorers", idParams: ["storedScorerId", "scorerId"] },
  skills: { resourceType: "stored-skills", idParams: ["storedSkillId"] },
  workspaces: { resourceType: "stored-workspaces", idParams: ["storedWorkspaceId"] }
};
function getStoredResourceRouteFGAConfig(path, permission) {
  const match = path.match(/^\/stored\/([^/]+)/);
  if (!match?.[1]) {
    return null;
  }
  const config = STORED_ROUTE_FGA[match[1]];
  if (!config) {
    return null;
  }
  return {
    resourceType: config.resourceType,
    resourceId: (params, { requestContext }) => {
      for (const idParam of config.idParams) {
        const id = params[idParam];
        if (typeof id === "string" && id) {
          return id;
        }
      }
      const scopedResourceId = requestContext?.get(chunkSXKQ7CSX_cjs.MASTRA_RESOURCE_ID_KEY);
      return typeof scopedResourceId === "string" && scopedResourceId ? scopedResourceId : config.resourceType;
    },
    permission
  };
}
function getBuiltInRouteFGAConfig(route) {
  if (!isProtectedFGARoute(route) || !route.path || !route.method) {
    return null;
  }
  const permission = chunkKURYHRSI_cjs.getEffectivePermission(route);
  if (!permission) {
    return null;
  }
  const path = route.path;
  const storedRouteConfig = getStoredResourceRouteFGAConfig(path, permission);
  if (storedRouteConfig) {
    return storedRouteConfig;
  }
  if (path.startsWith("/agents/:agentId/tools/:toolId")) {
    return {
      resourceType: "tool",
      resourceId: ({ agentId, toolId }) => getAgentToolResourceId(String(agentId), String(toolId)),
      permission: getToolRoutePermission(path)
    };
  }
  if (path.startsWith("/agents/:agentId")) {
    return { resourceType: "agent", resourceIdParam: "agentId", permission };
  }
  if (path.startsWith("/workflows/:workflowId")) {
    return { resourceType: "workflow", resourceIdParam: "workflowId", permission };
  }
  if (path.startsWith("/tools/:toolId")) {
    return { resourceType: "tool", resourceIdParam: "toolId", permission };
  }
  if (path.startsWith("/mcp/:serverId/tools/:toolId")) {
    return {
      resourceType: "tool",
      resourceId: ({ serverId, toolId }) => getMCPToolResourceId(String(serverId), String(toolId)),
      permission: getToolRoutePermission(path)
    };
  }
  if (path.startsWith("/mcp/:serverId")) {
    return { resourceType: "mcp", resourceIdParam: "serverId", permission };
  }
  if (path.startsWith("/memory/threads/:threadId") || path.startsWith("/memory/network/threads/:threadId")) {
    return { resourceType: "thread", resourceIdParam: "threadId", permission };
  }
  if (path === "/memory/threads" || path === "/memory/network/threads") {
    return {
      resourceType: "thread",
      resourceId: ({ threadId, resourceId }) => {
        if (typeof threadId === "string") return threadId;
        return typeof resourceId === "string" ? resourceId : void 0;
      },
      permission
    };
  }
  if (path === "/memory/save-messages" || path === "/memory/network/save-messages") {
    return {
      resourceType: "thread",
      resourceId: ({ messages }) => {
        if (!Array.isArray(messages)) return void 0;
        const threadId = messages.find(
          (message) => message && typeof message === "object" && "threadId" in message
        )?.threadId;
        return typeof threadId === "string" ? threadId : void 0;
      },
      permission
    };
  }
  if (path === "/v1/responses") {
    return { resourceType: "agent", resourceIdParam: "agent_id", permission };
  }
  if (path.startsWith("/v1/responses/:responseId")) {
    return { resourceType: "response", resourceIdParam: "responseId", permission };
  }
  if (path === "/v1/conversations") {
    return { resourceType: "agent", resourceIdParam: "agent_id", permission };
  }
  if (path.startsWith("/v1/conversations/:conversationId")) {
    return { resourceType: "conversation", resourceIdParam: "conversationId", permission };
  }
  return null;
}

// src/server/server-adapter/redact.ts
function redactV2Payload(payload) {
  const redactedPayload = { ...payload };
  if (redactedPayload.metadata && typeof redactedPayload.metadata === "object") {
    const { request, ...metadataRest } = redactedPayload.metadata;
    redactedPayload.metadata = metadataRest;
  }
  if (redactedPayload.output && typeof redactedPayload.output === "object") {
    const output = { ...redactedPayload.output };
    if (Array.isArray(output.steps)) {
      output.steps = output.steps.map((step) => {
        if (step && typeof step === "object") {
          const { request, ...stepRest } = step;
          return stepRest;
        }
        return step;
      });
    }
    redactedPayload.output = output;
  }
  return redactedPayload;
}
function redactStreamChunk(chunk) {
  if (!chunk || typeof chunk !== "object") {
    return chunk;
  }
  const typedChunk = chunk;
  switch (chunk.type) {
    case "step-start": {
      if ("payload" in typedChunk && typedChunk.payload && typeof typedChunk.payload === "object") {
        const { payload, ...rest } = typedChunk;
        const { request, ...payloadRest } = payload;
        return {
          ...rest,
          type: "step-start",
          payload: {
            ...payloadRest,
            // Keep an empty request object to maintain structure but remove body
            request: {}
          }
        };
      } else if ("request" in typedChunk) {
        const { request, ...rest } = typedChunk;
        return {
          ...rest,
          type: "step-start",
          // Keep an empty request object to maintain structure
          request: {}
        };
      }
      return chunk;
    }
    case "step-finish": {
      if ("payload" in typedChunk && typedChunk.payload && typeof typedChunk.payload === "object") {
        const { payload, ...rest } = typedChunk;
        return {
          ...rest,
          type: "step-finish",
          payload: redactV2Payload(payload)
        };
      } else if ("request" in typedChunk) {
        const { request, ...rest } = typedChunk;
        return {
          ...rest,
          type: "step-finish"
        };
      }
      return chunk;
    }
    case "finish": {
      if ("payload" in typedChunk && typedChunk.payload && typeof typedChunk.payload === "object") {
        const { payload, ...rest } = typedChunk;
        return {
          ...rest,
          type: "finish",
          payload: redactV2Payload(payload)
        };
      } else if ("request" in typedChunk) {
        const { request, ...rest } = typedChunk;
        return {
          ...rest,
          type: "finish"
        };
      }
      return chunk;
    }
    default:
      return chunk;
  }
}
function serializeStreamChunk(chunk) {
  try {
    return { ok: true, json: utils.safeStringify(chunk) };
  } catch (error) {
    return { ok: false, error: error instanceof Error ? error : new Error(String(error)) };
  }
}

// src/server/server-adapter/index.ts
function isAbortSignalError(error) {
  if (!error || typeof error !== "object") return false;
  const { code, name } = error;
  return name === "AbortError" || code === "ABORT_ERR";
}
function isExpectedResponseCloseError(error) {
  if (!error || typeof error !== "object") return false;
  const { code } = error;
  return code === "ECONNRESET" || code === "EPIPE" || code === "ERR_STREAM_DESTROYED" || code === "ERR_STREAM_WRITE_AFTER_END" || code === "ERR_STREAM_PREMATURE_CLOSE";
}
function isResponseClosed(response) {
  return Boolean(response.writableEnded || response.destroyed);
}
function isProtectedFGARoute2(route) {
  return route.requiresAuth !== false;
}
function formatRoute(route) {
  return `${route.method} ${route.path}`;
}
function getFGAProvider(mastra, requestContext) {
  if (requestContext) {
    const authMode = requestContext.get(chunkSXKQ7CSX_cjs.MASTRA_AUTH_MODE_KEY);
    if (authMode === "studio") {
      const studioFga = mastra?.getStudio?.()?.fga;
      if (studioFga) return studioFga;
    }
  }
  return mastra?.getServer?.()?.fga;
}
function getFGARouteInfo(route) {
  return {
    path: route.path,
    method: route.method,
    requiresAuth: route.requiresAuth,
    requiresPermission: route.requiresPermission,
    fga: route.fga
  };
}
function getRoutePermissions(route) {
  return [chunkKURYHRSI_cjs.getEffectivePermission(route), route.fga?.permission].flatMap((value) => Array.isArray(value) ? value : [value]).filter((permission) => Boolean(permission));
}
async function resolveRouteFGAConfig(fgaProvider, route, requestContext, params) {
  if (route.fga) {
    return route.fga;
  }
  const resolvedConfig = await fgaProvider.resolveRouteFGA?.({
    route: getFGARouteInfo(route),
    params,
    requestContext
  });
  if (resolvedConfig) {
    return resolvedConfig;
  }
  return getBuiltInRouteFGAConfig(route);
}
function getSchemaTypeName(schema) {
  const schemaDef = schema?._def ?? schema?.def;
  return schemaDef?.typeName ?? schemaDef?.type;
}
function unwrapOptionalNullable(schema) {
  let inner = schema;
  let typeName = getSchemaTypeName(inner);
  while (typeName === "ZodOptional" || typeName === "ZodNullable" || typeName === "optional" || typeName === "nullable") {
    const innerDef = inner?._def ?? inner?.def;
    if (!innerDef?.innerType) {
      return inner;
    }
    inner = innerDef.innerType;
    typeName = getSchemaTypeName(inner);
  }
  return inner;
}
function parseComplexQueryParams(queryParamSchema, params) {
  if (!(queryParamSchema instanceof v4.z.ZodObject)) {
    return params;
  }
  const parsedParams = { ...params };
  const shape = queryParamSchema.shape;
  for (const [key, fieldSchema] of Object.entries(shape)) {
    const rawValue = parsedParams[key];
    if (typeof rawValue !== "string") {
      continue;
    }
    const unwrappedField = unwrapOptionalNullable(fieldSchema);
    const typeName = getSchemaTypeName(unwrappedField);
    const isComplex = typeName === "ZodObject" || typeName === "ZodArray" || typeName === "ZodRecord" || typeName === "object" || typeName === "array" || typeName === "record";
    if (!isComplex) {
      continue;
    }
    try {
      parsedParams[key] = JSON.parse(rawValue);
    } catch {
    }
  }
  return parsedParams;
}
function normalizeQueryParams(rawQuery) {
  const queryParams = {};
  const bracketGroups = {};
  for (const [key, value] of Object.entries(rawQuery)) {
    const bracketMatch = key.match(/^([^[]+)\[([^\]]+)\]$/);
    if (bracketMatch) {
      const parent = bracketMatch[1];
      const child = bracketMatch[2];
      const strValue = Array.isArray(value) ? value.filter((v) => typeof v === "string")[0] : typeof value === "string" ? value : void 0;
      if (strValue !== void 0) {
        if (!bracketGroups[parent]) {
          bracketGroups[parent] = {};
        }
        bracketGroups[parent][child] = strValue;
      }
    } else if (typeof value === "string") {
      queryParams[key] = value;
    } else if (Array.isArray(value)) {
      const stringValues = value.filter((v) => typeof v === "string");
      queryParams[key] = stringValues.length === 1 ? stringValues[0] : stringValues;
    }
  }
  for (const [parent, children] of Object.entries(bracketGroups)) {
    if (!(parent in queryParams)) {
      queryParams[parent] = JSON.stringify(children);
    }
  }
  return queryParams;
}
var MastraServer = class _MastraServer extends server.MastraServerBase {
  mastra;
  bodyLimitOptions;
  tools;
  prefix;
  openapiPath;
  taskStore;
  customRouteAuthConfig;
  streamOptions;
  httpLoggingConfig;
  customApiRoutes;
  mcpOptions;
  customRouteHandler = null;
  constructor({
    app,
    mastra,
    bodyLimitOptions,
    tools,
    prefix = "/api",
    openapiPath = "",
    taskStore,
    customRouteAuthConfig,
    streamOptions,
    customApiRoutes,
    mcpOptions
  }) {
    super({ app, name: "MastraServer" });
    this.mastra = mastra;
    this.bodyLimitOptions = bodyLimitOptions;
    this.tools = tools;
    this.prefix = chunkDRDVJ35H_cjs.normalizeRoutePath(prefix);
    this.openapiPath = openapiPath;
    this.taskStore = taskStore;
    this.customRouteAuthConfig = customRouteAuthConfig;
    this.streamOptions = { redact: true, ...streamOptions };
    this.customApiRoutes = customApiRoutes;
    this.mcpOptions = mcpOptions;
    const serverConfig = mastra.getServer();
    this.httpLoggingConfig = this.parseLoggingConfig(serverConfig?.build?.apiReqLogs);
    mastra.setMastraServer(this);
  }
  /**
   * Parses the apiReqLogs configuration into a normalized HttpLoggingConfig.
   * @param config - The raw config value from server.build.apiReqLogs
   * @returns Normalized HttpLoggingConfig or undefined if disabled
   */
  parseLoggingConfig(config) {
    if (config === true) {
      return {
        enabled: true,
        level: "info",
        redactHeaders: ["authorization", "cookie"]
      };
    }
    if (typeof config === "object" && config.enabled) {
      return {
        enabled: true,
        level: config.level || "info",
        excludePaths: config.excludePaths,
        includeHeaders: config.includeHeaders,
        includeQueryParams: config.includeQueryParams,
        redactHeaders: [.../* @__PURE__ */ new Set([...["authorization", "cookie"], ...config.redactHeaders || []])]
      };
    }
    return void 0;
  }
  /**
   * Determines if a request to the given path should be logged.
   * @param path - The request path to check
   * @returns true if the request should be logged, false otherwise
   */
  shouldLogRequest(path) {
    if (!this.httpLoggingConfig?.enabled) {
      return false;
    }
    const excludePaths = this.httpLoggingConfig.excludePaths || [];
    return !excludePaths.some((excluded) => path === excluded || path.startsWith(excluded + "/"));
  }
  mergeRequestContext({
    paramsRequestContext,
    bodyRequestContext
  }) {
    const requestContext$1 = new requestContext.RequestContext();
    if (bodyRequestContext) {
      for (const [key, value] of Object.entries(bodyRequestContext)) {
        if (chunkSXKQ7CSX_cjs.isReservedRequestContextKey(key)) continue;
        requestContext$1.set(key, value);
      }
    }
    if (paramsRequestContext) {
      for (const [key, value] of Object.entries(paramsRequestContext)) {
        if (chunkSXKQ7CSX_cjs.isReservedRequestContextKey(key)) continue;
        requestContext$1.set(key, value);
      }
    }
    return requestContext$1;
  }
  applyRequestMetadataToContext({
    requestContext,
    getHeader
  }) {
    if (chunkSXKQ7CSX_cjs.isStudioClientTypeHeader(getHeader(chunkSXKQ7CSX_cjs.MASTRA_CLIENT_TYPE_HEADER))) {
      requestContext.set(chunkSXKQ7CSX_cjs.MASTRA_IS_STUDIO_KEY, true);
    }
  }
  /**
   * Determines which auth configuration to use for the current request.
   *
   * Request routing logic:
   * 1. If `x-mastra-client-type: studio` header is present AND `studio.auth` is configured:
   *    → Use studio auth (for internal team members accessing Studio UI)
   * 2. If studio header is present but `studio.auth` is NOT configured:
   *    → No auth required (Studio development mode)
   * 3. Otherwise:
   *    → Use server auth (for external customers calling API)
   *
   * Security note: The header is only for routing - auth validation happens
   * via session cookies/tokens. If someone spoofs the studio header but doesn't
   * have a valid studio session, they'll get a 401 (not fall back to server auth).
   */
  getEffectiveAuthConfig(getHeader) {
    const isStudioRequest = chunkSXKQ7CSX_cjs.isStudioClientTypeHeader(getHeader(chunkSXKQ7CSX_cjs.MASTRA_CLIENT_TYPE_HEADER));
    const studioAuth = this.mastra.getStudio?.()?.auth;
    const serverAuth = this.mastra.getServer()?.auth;
    if (isStudioRequest && studioAuth) {
      return { authConfig: studioAuth, authMode: "studio" };
    }
    if (serverAuth) {
      return { authConfig: serverAuth, authMode: "server" };
    }
    return null;
  }
  /**
   * Gets the effective RBAC provider for the current request based on auth mode.
   */
  getEffectiveRBACProvider(requestContext) {
    const authMode = requestContext.get(chunkSXKQ7CSX_cjs.MASTRA_AUTH_MODE_KEY);
    if (authMode === "studio") {
      return this.mastra.getStudio?.()?.rbac ?? this.mastra.getServer()?.rbac;
    }
    return this.mastra.getServer()?.rbac;
  }
  /**
   * Gets the effective FGA provider for the current request based on auth mode.
   */
  getEffectiveFGAProvider(requestContext) {
    const authMode = requestContext.get(chunkSXKQ7CSX_cjs.MASTRA_AUTH_MODE_KEY);
    if (authMode === "studio") {
      return this.mastra.getStudio?.()?.fga ?? this.mastra.getServer()?.fga;
    }
    return this.mastra.getServer()?.fga;
  }
  /**
   * Check if the current request should be authenticated/authorized.
   * Returns null if auth passes, or an error response if it fails.
   *
   * This is a thin wrapper around coreAuthMiddleware that:
   * 1. Routes to the correct auth provider (studio vs server) based on request headers
   * 2. Handles route-level requiresAuth opt-out (not available in global middleware)
   * 3. Delegates all other auth logic to coreAuthMiddleware
   * 4. Translates the AuthResult into the {status, error} format adapters expect
   *
   * Security: When `x-mastra-client-type: studio` header is present and studio auth
   * is configured, we ONLY use studio auth. If authentication fails, we return 401
   * and redirect to login - we do NOT fall back to server auth. This prevents
   * external users from spoofing the studio header to access Studio UI.
   */
  async checkRouteAuth(route, context) {
    const effectiveAuth = this.getEffectiveAuthConfig(context.getHeader);
    if (!effectiveAuth) {
      return null;
    }
    const { authConfig, authMode } = effectiveAuth;
    context.requestContext.set(chunkSXKQ7CSX_cjs.MASTRA_AUTH_MODE_KEY, authMode);
    if (route.requiresAuth === false) {
      return null;
    }
    const authHeader = context.getHeader("authorization");
    let token = authHeader ? authHeader.replace("Bearer ", "") : null;
    if (!token) {
      token = context.getQuery("apiKey") || null;
    }
    const fallbackHeaders = new Headers();
    for (const headerName of ["authorization", "cookie"]) {
      const headerValue = context.getHeader(headerName);
      if (headerValue) {
        fallbackHeaders.set(headerName, headerValue);
      }
    }
    const result = await chunkSYZ2NTP3_cjs.coreAuthMiddleware({
      path: context.path,
      method: context.method,
      getHeader: context.getHeader,
      mastra: this.mastra,
      authConfig,
      customRouteAuthConfig: this.customRouteAuthConfig,
      requestContext: context.requestContext,
      rawRequest: context.request ?? new Request(`http://localhost${context.path}`, { method: context.method, headers: fallbackHeaders }),
      token,
      buildAuthorizeContext: context.buildAuthorizeContext ?? (() => null),
      requiresAuth: route.requiresAuth
    });
    if (result.action === "next") {
      if (result.headers) {
        return { status: 200, error: "", headers: result.headers };
      }
      return null;
    }
    const errorBody = result.body;
    return { status: result.status, error: errorBody?.error ?? "Access denied", headers: result.headers };
  }
  /**
   * Check if the user has the required permission for a route.
   *
   * Uses convention-based permission derivation:
   * 1. If route has explicit `requiresPermission`, use that
   * 2. Otherwise, derive permission from path/method (e.g., GET /agents → agents:read)
   * 3. Routes with `requiresAuth: false` skip permission checks
   *
   * When the route specifies an array of permissions, the user needs ANY ONE
   * of them (logical OR).
   *
   * @param route - The route being accessed
   * @param userPermissions - The user's permissions from the request context
   * @returns Error response if permission denied, null if allowed
   */
  /**
   * Check if the user has the required permission for a route.
   *
   * Uses convention-based permission derivation:
   * 1. If route has explicit `requiresPermission`, use that
   * 2. Otherwise, derive permission from path/method (e.g., GET /agents → agents:read)
   * 3. Routes with `requiresAuth: false` skip permission checks
   *
   * Permission checks use the RBAC provider that corresponds to the auth mode
   * (studio vs server) that was used for authentication.
   *
   * @param route - The route being accessed
   * @param userPermissions - The user's permissions from the request context
   * @param hasPermissionFn - Function to check if user permissions match required permission
   * @param requestContext - Request context to determine which RBAC provider to use
   * @returns Error response if permission denied, null if allowed
   */
  checkRoutePermission(route, userPermissions, hasPermissionFn, requestContext) {
    const rbacProvider = requestContext ? this.getEffectiveRBACProvider(requestContext) : this.mastra.getServer()?.rbac;
    if (!rbacProvider) {
      return null;
    }
    const requiredPermission = chunkKURYHRSI_cjs.getEffectivePermission(route);
    if (!requiredPermission) {
      return null;
    }
    const permissions = Array.isArray(requiredPermission) ? requiredPermission : [requiredPermission];
    const hasAny = userPermissions && permissions.some((perm) => hasPermissionFn(userPermissions, perm));
    if (!hasAny) {
      return {
        status: 403,
        error: "Forbidden",
        message: `Missing required permission: ${permissions.join(" or ")}`
      };
    }
    return null;
  }
  async init() {
    this.registerContextMiddleware();
    this.registerAuthMiddleware();
    this.registerHttpLoggingMiddleware();
    await this.validateEELicense();
    await this.validateAgentBuilderLicense();
    await this.validateFGAPolicyCoverage();
    await this.registerCustomApiRoutes();
    await this.registerRoutes();
  }
  /**
   * Validate that EE features have a valid license in production.
   * Throws if RBAC or FGA is configured without a valid license outside dev/test environments.
   */
  async validateEELicense() {
    const serverConfig = this.mastra.getServer();
    const studioConfig = this.mastra.getStudio?.();
    const configuredFeatures = [
      serverConfig?.rbac || studioConfig?.rbac ? "RBAC" : null,
      serverConfig?.fga || studioConfig?.fga ? "FGA" : null
    ].filter((feature) => feature !== null);
    if (configuredFeatures.length === 0) return;
    try {
      const { isEEEnabled } = await import('@mastra/core/auth/ee');
      if (!isEEEnabled()) {
        const featureList = configuredFeatures.join(" and ");
        throw new Error(
          `[mastra/auth-ee] ${featureList} ${configuredFeatures.length === 1 ? "is" : "are"} configured but no valid EE license was found.
${featureList} ${configuredFeatures.length === 1 ? "requires" : "require"} a Mastra Enterprise License for production use.
Set the MASTRA_EE_LICENSE environment variable with your license key.
Learn more: https://github.com/mastra-ai/mastra/blob/main/ee/LICENSE`
        );
      }
    } catch (err) {
      if (err instanceof Error && err.message.startsWith("[mastra/auth-ee]")) {
        throw err;
      }
      throw new Error(
        `[mastra/auth-ee] ${configuredFeatures.join(" and ")} ${configuredFeatures.length === 1 ? "is" : "are"} configured but the EE module (@mastra/core/auth/ee) could not be loaded.
Ensure @mastra/core is updated to a version that includes EE support.`
      );
    }
  }
  /**
   * Validate that an Agent Builder configuration has a valid EE license.
   * Throws if the editor is configured with builder support but no valid EE license is available.
   */
  async validateAgentBuilderLicense() {
    const editor = this.mastra.getEditor();
    if (!editor?.hasEnabledBuilderConfig?.()) return;
    try {
      const { isEEEnabled } = await import('@mastra/core/auth/ee');
      if (!isEEEnabled()) {
        throw new Error(
          "[mastra/auth-ee] Agent Builder is configured but no valid EE license was found.\nAgent Builder requires a Mastra Enterprise License for production use.\nSet the MASTRA_EE_LICENSE environment variable with your license key.\nLearn more: https://github.com/mastra-ai/mastra/blob/main/ee/LICENSE"
        );
      }
    } catch (err) {
      if (err instanceof Error && err.message.startsWith("[mastra/auth-ee]")) {
        throw err;
      }
      throw new Error(
        "[mastra/auth-ee] Agent Builder is configured but the EE module (@mastra/core/auth/ee) could not be loaded.\nEnsure @mastra/core is updated to a version that includes EE support."
      );
    }
  }
  /**
   * Validate route-level FGA policy coverage when an FGA provider opts into
   * startup checks.
   */
  async validateFGAPolicyCoverage() {
    const serverConfig = this.mastra.getServer();
    const studioConfig = this.mastra.getStudio?.();
    const fgaProvider = serverConfig?.fga ?? studioConfig?.fga;
    if (!fgaProvider) return;
    const customRoutes = (this.customApiRoutes ?? serverConfig?.apiRoutes ?? []).filter(
      (route) => !route._mastraInternal
    );
    const routes = [...chunkKURYHRSI_cjs.SERVER_ROUTES, ...customRoutes];
    if (fgaProvider.validatePermissions) {
      const permissions = [...new Set(routes.flatMap((route) => getRoutePermissions(route)))];
      await fgaProvider.validatePermissions(permissions);
    }
    const auditMode = fgaProvider.auditProtectedRoutes ?? (fgaProvider.requireForProtectedRoutes ? "warn" : false);
    if (!auditMode || fgaProvider.resolveRouteFGA) return;
    const missingRoutes = routes.filter(
      (route) => isProtectedFGARoute2(route) && !route.fga && !getBuiltInRouteFGAConfig(route)
    );
    if (missingRoutes.length === 0) return;
    const routeList = missingRoutes.map((route) => formatRoute(route));
    const message = `[mastra/auth-ee] FGA is configured but ${missingRoutes.length} protected route${missingRoutes.length === 1 ? " is" : "s are"} missing FGA metadata: ${routeList.join(", ")}`;
    if (auditMode === "error") {
      throw new Error(message);
    }
    this.mastra.getLogger()?.warn(message, {
      routes: routeList,
      count: missingRoutes.length
    });
  }
  /**
   * Override in adapters to register custom API routes defined via registerApiRoute().
   * Called by init() between registerAuthMiddleware() and registerRoutes().
   */
  async registerCustomApiRoutes() {
  }
  /**
   * Validates that no custom route path collides with the built-in route prefix.
   * Throws if any route path starts with the server's `apiPrefix`.
   */
  validateCustomRoutePaths(routes) {
    const prefix = this.prefix ?? "";
    if (!prefix) return;
    for (const route of routes) {
      if (route._mastraInternal) continue;
      if (route.path.startsWith(`${prefix}/`) || route.path === prefix) {
        throw new Error(
          `Custom API route "${route.path}" must not start with "${prefix}" \u2014 that path is reserved for built-in Mastra routes. Choose a different path (e.g. "${route.path.replace(prefix, "/custom")}").`
        );
      }
    }
  }
  /**
   * Creates an internal Hono sub-app with all custom API routes registered.
   * Stores the handler on this instance for use by handleCustomRouteRequest().
   * Returns true if custom routes were found and registered.
   */
  async buildCustomRouteHandler() {
    const routes = this.customApiRoutes ?? this.mastra.getServer()?.apiRoutes;
    if (!routes || routes.length === 0) return false;
    const NOT_FOUND_HEADER = "x-mastra-custom-route-not-found";
    const mastra = this.mastra;
    const app = new hono.Hono();
    app.use("*", async (c, next) => {
      c.set("mastra", mastra);
      c.set("requestContext", c.env?.requestContext ?? new requestContext.RequestContext());
      await next();
    });
    const serverOnError = this.mastra.getServer()?.onError;
    app.onError((err, c) => {
      if (serverOnError) {
        return serverOnError(err, c);
      }
      return c.json({ error: "Internal Server Error" }, 500);
    });
    this.validateCustomRoutePaths(routes);
    for (const route of routes) {
      const handler = "handler" in route && route.handler ? route.handler : "createHandler" in route ? await route.createHandler({ mastra }) : void 0;
      if (!handler) continue;
      const middlewares = [];
      if (route.middleware) {
        middlewares.push(...Array.isArray(route.middleware) ? route.middleware : [route.middleware]);
      }
      const allHandlers = [...middlewares, handler];
      if (route.method === "ALL") {
        app.all(route.path, allHandlers[0], ...allHandlers.slice(1));
      } else {
        app.on(route.method, route.path, allHandlers[0], ...allHandlers.slice(1));
      }
    }
    app.notFound(() => new Response(null, { status: 404, headers: { [NOT_FOUND_HEADER]: "true" } }));
    this.customRouteHandler = async (request, env) => app.fetch(request, env);
    return true;
  }
  /**
   * Forwards a request to the internal custom route handler.
   * Returns the Response if a custom route matched, or null to fall through.
   */
  async handleCustomRouteRequest(url, method, headers, body, requestContext, signal) {
    if (!this.customRouteHandler) return null;
    const fetchHeaders = new Headers();
    for (const [key, value] of Object.entries(headers)) {
      if (typeof value === "string") fetchHeaders.set(key, value);
      else if (Array.isArray(value))
        value.forEach((v) => {
          fetchHeaders.append(key, v);
        });
    }
    const init = { method, headers: fetchHeaders, signal };
    if (["POST", "PUT", "PATCH", "DELETE"].includes(method) && body !== void 0) {
      if (body instanceof ArrayBuffer || body instanceof Uint8Array || body instanceof ReadableStream) {
        init.body = body;
        if (body instanceof ReadableStream) {
          init.duplex = "half";
        }
      } else {
        const contentType = (typeof headers["content-type"] === "string" ? headers["content-type"] : "") || "";
        if (contentType.includes("application/json")) {
          init.body = JSON.stringify(body);
        } else if (typeof body === "string") {
          init.body = body;
        }
      }
    }
    const request = new globalThis.Request(url, init);
    const response = await this.customRouteHandler(request, { requestContext });
    if (response.headers.get("x-mastra-custom-route-not-found") === "true") return null;
    return response;
  }
  /**
   * Pipes a custom route Response to a Node.js ServerResponse (http.ServerResponse).
   * Works with Koa (ctx.res), Express (res), and Fastify (reply.raw).
   */
  async writeCustomRouteResponse(response, nodeRes, signal) {
    const headers = {};
    response.headers.forEach((value, key) => {
      if (key.toLowerCase() !== "set-cookie") {
        headers[key] = value;
      }
    });
    const setCookies = response.headers.getSetCookie?.();
    if (setCookies && setCookies.length > 0) {
      headers["set-cookie"] = setCookies;
    }
    if (isResponseClosed(nodeRes)) {
      await response.body?.cancel();
      return;
    }
    nodeRes.writeHead(response.status, headers);
    if (response.body) {
      let responseBodyError;
      let responseBodyErrorAfterResponseClosed = false;
      try {
        const responseStream = stream.Readable.fromWeb(response.body);
        responseStream.once("error", (error) => {
          responseBodyError = error;
          responseBodyErrorAfterResponseClosed = isResponseClosed(nodeRes);
        });
        if (signal) {
          await promises.pipeline(responseStream, nodeRes, { signal });
        } else {
          await promises.pipeline(responseStream, nodeRes);
        }
      } catch (error) {
        const expectedSignalAbort = signal?.aborted && isAbortSignalError(error) && (!responseBodyError || responseBodyErrorAfterResponseClosed);
        const expectedResponseClose = (!responseBodyError || responseBodyErrorAfterResponseClosed) && isResponseClosed(nodeRes) && isExpectedResponseCloseError(error);
        if (!expectedSignalAbort && !expectedResponseClose) {
          throw error;
        }
      }
    } else {
      const text = await response.text();
      if (!isResponseClosed(nodeRes)) {
        nodeRes.end(text);
      }
    }
  }
  /**
   * Builds the OpenAPI spec object with servers field and custom route paths.
   */
  buildOpenAPISpec(config, prefix) {
    const openApiSpec = chunkN54Q3AQR_cjs.generateOpenAPIDocument(chunkKURYHRSI_cjs.SERVER_ROUTES, config);
    if (prefix) {
      openApiSpec.servers = [{ url: prefix }];
    }
    const allCustomRoutes = this.customApiRoutes ?? this.mastra.getServer()?.apiRoutes;
    if (allCustomRoutes && allCustomRoutes.length > 0) {
      const customPaths = chunkN54Q3AQR_cjs.convertCustomRoutesToOpenAPIPaths(allCustomRoutes);
      if (prefix) {
        for (const pathKey of Object.keys(customPaths)) {
          if (!customPaths[pathKey].servers) {
            customPaths[pathKey].servers = [{ url: "/" }];
          }
        }
      }
      openApiSpec.paths = { ...openApiSpec.paths, ...customPaths };
    }
    return openApiSpec;
  }
  async registerOpenAPIRoute(app, config = {}, { prefix }) {
    const {
      title = "Mastra API",
      version = "1.0.0",
      description = "Mastra Server API",
      path = "/openapi.json"
    } = config;
    const openApiSpec = this.buildOpenAPISpec({ title, version, description }, prefix);
    const openApiRoute = {
      method: "GET",
      path,
      responseType: "json",
      handler: async () => openApiSpec
    };
    await this.registerRoute(app, openApiRoute, { prefix });
  }
  async registerRoutes() {
    for (const route of chunkKURYHRSI_cjs.SERVER_ROUTES) {
      await this.registerRoute(this.app, route, { prefix: this.prefix });
    }
    if (this.openapiPath) {
      const specConfig = {
        title: "Mastra API",
        version: "1.0.0",
        description: "Mastra Server API"
      };
      await this.registerOpenAPIRoute(this.app, { ...specConfig, path: this.openapiPath }, { prefix: this.prefix });
    }
  }
  async parsePathParams(route, params) {
    const pathParamSchema = route.pathParamSchema;
    if (!pathParamSchema) {
      return params;
    }
    return pathParamSchema.parseAsync(params);
  }
  async parseQueryParams(route, params) {
    const queryParamSchema = route.queryParamSchema;
    if (!queryParamSchema) {
      return params;
    }
    const normalizedParams = parseComplexQueryParams(queryParamSchema, params);
    return queryParamSchema.parseAsync(normalizedParams);
  }
  async parseBody(route, body) {
    const bodySchema = route.bodySchema;
    if (!bodySchema) {
      return body;
    }
    return bodySchema.parseAsync(body);
  }
  static CONTEXT_LABELS = {
    query: "query parameters",
    body: "request body",
    path: "path parameters"
  };
  resolveValidationError(route, error, context) {
    const hook = route.onValidationError ?? this.mastra.getServer()?.onValidationError;
    if (hook) {
      try {
        const result = hook(error, context);
        if (result) {
          return result;
        }
      } catch (hookError) {
        this.mastra.getLogger()?.error("Error in custom onValidationError hook", {
          error: hookError instanceof Error ? { message: hookError.message, stack: hookError.stack } : hookError
        });
      }
    }
    return {
      status: 400,
      body: chunkZ7LCIYK7_cjs.formatZodError(error, _MastraServer.CONTEXT_LABELS[context])
    };
  }
};
async function checkRouteFGA(mastra, route, requestContext, params) {
  const fgaProvider = getFGAProvider(mastra, requestContext);
  if (!fgaProvider) return null;
  const fgaConfig = await resolveRouteFGAConfig(fgaProvider, route, requestContext, params);
  if (!fgaConfig) {
    if (fgaProvider.requireForProtectedRoutes && isProtectedFGARoute2(route)) {
      return {
        status: 403,
        error: "Forbidden",
        message: "FGA authorization denied: route FGA metadata is required"
      };
    }
    return null;
  }
  const user = requestContext?.get("user");
  if (!user) {
    return {
      status: 403,
      error: "Forbidden",
      message: "FGA authorization denied: authenticated user is required"
    };
  }
  const resourceId = typeof fgaConfig.resourceId === "function" ? fgaConfig.resourceId(params, { requestContext }) : fgaConfig.resourceId || (fgaConfig.resourceIdParam ? params[fgaConfig.resourceIdParam] : void 0);
  if (!fgaConfig.resourceType || !resourceId) {
    return {
      status: 403,
      error: "Forbidden",
      message: "FGA authorization denied: route FGA metadata is incomplete"
    };
  }
  const effectivePermission = route.path ? chunkKURYHRSI_cjs.getEffectivePermission(route) : null;
  const permission = fgaConfig.permission || effectivePermission || `${getFGAResourcePermissionSlug(fgaConfig.resourceType)}:${deriveFGAAction(route.method)}`;
  const authorized = await fgaProvider.check(user, {
    resource: { type: fgaConfig.resourceType, id: resourceId },
    permission,
    context: { resourceId, requestContext }
  });
  if (!authorized) {
    return {
      status: 403,
      error: "Forbidden",
      message: `FGA authorization denied: cannot ${permission} on ${fgaConfig.resourceType}:${resourceId}`
    };
  }
  return null;
}
function deriveFGAAction(method) {
  switch (method.toUpperCase()) {
    case "GET":
      return "read";
    case "DELETE":
      return "delete";
    case "POST":
    case "PUT":
    case "PATCH":
      return "write";
    default:
      return "read";
  }
}
function getFGAResourcePermissionSlug(resourceType) {
  const resourcePermissionSlugs = {
    agent: "agents",
    workflow: "workflows",
    tool: "tools",
    thread: "memory"
  };
  return resourcePermissionSlugs[resourceType] ?? resourceType;
}

Object.defineProperty(exports, "SERVER_ROUTES", {
  enumerable: true,
  get: function () { return chunkKURYHRSI_cjs.SERVER_ROUTES; }
});
Object.defineProperty(exports, "deriveAction", {
  enumerable: true,
  get: function () { return chunkKURYHRSI_cjs.deriveAction; }
});
Object.defineProperty(exports, "derivePermission", {
  enumerable: true,
  get: function () { return chunkKURYHRSI_cjs.derivePermission; }
});
Object.defineProperty(exports, "extractResource", {
  enumerable: true,
  get: function () { return chunkKURYHRSI_cjs.extractResource; }
});
Object.defineProperty(exports, "getEffectivePermission", {
  enumerable: true,
  get: function () { return chunkKURYHRSI_cjs.getEffectivePermission; }
});
Object.defineProperty(exports, "WorkflowRegistry", {
  enumerable: true,
  get: function () { return chunkDRDVJ35H_cjs.WorkflowRegistry; }
});
Object.defineProperty(exports, "normalizeRoutePath", {
  enumerable: true,
  get: function () { return chunkDRDVJ35H_cjs.normalizeRoutePath; }
});
Object.defineProperty(exports, "MASTRA_AUTH_MODE_KEY", {
  enumerable: true,
  get: function () { return chunkSXKQ7CSX_cjs.MASTRA_AUTH_MODE_KEY; }
});
Object.defineProperty(exports, "MASTRA_CLIENT_TYPE_HEADER", {
  enumerable: true,
  get: function () { return chunkSXKQ7CSX_cjs.MASTRA_CLIENT_TYPE_HEADER; }
});
Object.defineProperty(exports, "MASTRA_IS_STUDIO_KEY", {
  enumerable: true,
  get: function () { return chunkSXKQ7CSX_cjs.MASTRA_IS_STUDIO_KEY; }
});
Object.defineProperty(exports, "MASTRA_STUDIO_CLIENT_TYPE", {
  enumerable: true,
  get: function () { return chunkSXKQ7CSX_cjs.MASTRA_STUDIO_CLIENT_TYPE; }
});
Object.defineProperty(exports, "isReservedRequestContextKey", {
  enumerable: true,
  get: function () { return chunkSXKQ7CSX_cjs.isReservedRequestContextKey; }
});
Object.defineProperty(exports, "isStudioClientTypeHeader", {
  enumerable: true,
  get: function () { return chunkSXKQ7CSX_cjs.isStudioClientTypeHeader; }
});
Object.defineProperty(exports, "isZodError", {
  enumerable: true,
  get: function () { return chunkZ7LCIYK7_cjs.isZodError; }
});
Object.defineProperty(exports, "createPublicRoute", {
  enumerable: true,
  get: function () { return chunkN54Q3AQR_cjs.createPublicRoute; }
});
Object.defineProperty(exports, "createRoute", {
  enumerable: true,
  get: function () { return chunkN54Q3AQR_cjs.createRoute; }
});
Object.defineProperty(exports, "generateOpenAPIDocument", {
  enumerable: true,
  get: function () { return chunkN54Q3AQR_cjs.generateOpenAPIDocument; }
});
Object.defineProperty(exports, "jsonQueryParam", {
  enumerable: true,
  get: function () { return chunkN54Q3AQR_cjs.jsonQueryParam; }
});
Object.defineProperty(exports, "pickParams", {
  enumerable: true,
  get: function () { return chunkN54Q3AQR_cjs.pickParams; }
});
Object.defineProperty(exports, "wrapSchemaForQueryParams", {
  enumerable: true,
  get: function () { return chunkN54Q3AQR_cjs.wrapSchemaForQueryParams; }
});
exports.MastraServer = MastraServer;
exports.checkRouteFGA = checkRouteFGA;
exports.normalizeQueryParams = normalizeQueryParams;
exports.redactStreamChunk = redactStreamChunk;
exports.serializeStreamChunk = serializeStreamChunk;
//# sourceMappingURL=index.cjs.map
//# sourceMappingURL=index.cjs.map