{"version":3,"sources":["../src/server/fga-permissions.ts","../src/server/handlers/utils.ts"],"names":["authEE","MastraFGAPermissions","HTTPException","MASTRA_RESOURCE_ID_KEY","MASTRA_THREAD_ID_KEY","MastraMemory"],"mappings":"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","file":"chunk-RVD3DGBZ.cjs","sourcesContent":["/**\n * Safe re-export of `MastraFGAPermissions` from `@mastra/core/auth/ee`.\n *\n * Why this shim exists:\n * `MastraFGAPermissions` was introduced in `@mastra/core@1.32.0`. Earlier\n * versions of `@mastra/core` ship `@mastra/core/auth/ee` but do not export\n * this constant. A direct named import (`import { MastraFGAPermissions }\n * from '@mastra/core/auth/ee'`) fails at ESM link time when this version\n * of `@mastra/server` is paired with `@mastra/core < 1.32.0`, taking the\n * entire user bundle down before any code runs.\n *\n * A namespace import tolerates missing names — `ns.MissingExport` is just\n * `undefined`, no link-time error. We then expose the permission map.\n *\n * Fallback values:\n * If the consuming `@mastra/core` does not export `MastraFGAPermissions`,\n * we substitute a hardcoded map of the canonical permission strings used\n * by routes in `@mastra/server`. This preserves the explicit RBAC\n * permission overrides those routes already had as string literals in\n * `@mastra/server@1.31.0` (e.g. `requiresPermission: \"agents:execute\"`\n * on `/v1/responses`). Without this fallback, `requiresPermission` would\n * be `undefined` on old core and the auth layer would derive the wrong\n * permission from the route path (e.g. `v1:write` instead of\n * `agents:execute`), breaking RBAC users who upgrade `@mastra/server`\n * but stay on `@mastra/core@1.31.0`.\n *\n * Once the consuming `@mastra/core` is on `1.32.0+` the values are real\n * and behaviour is identical to a direct named import.\n */\n\nimport * as authEE from '@mastra/core/auth/ee';\n\n// Canonical strings for the FGA permission keys actually referenced by\n// `@mastra/server` source. Mirrors `MastraFGAPermissions` in\n// `@mastra/core@1.32.0+` for these specific keys, and matches the string\n// literals previously hardcoded on the same routes in `@mastra/server@1.31.0`.\nconst FALLBACK_PERMISSIONS = {\n AGENTS_CREATE: 'agents:create',\n AGENTS_DELETE: 'agents:delete',\n AGENTS_EXECUTE: 'agents:execute',\n AGENTS_READ: 'agents:read',\n MEMORY_DELETE: 'memory:delete',\n MEMORY_READ: 'memory:read',\n MEMORY_WRITE: 'memory:write',\n TOOLS_EXECUTE: 'tools:execute',\n TOOLS_READ: 'tools:read',\n WORKFLOWS_EXECUTE: 'workflows:execute',\n WORKFLOWS_READ: 'workflows:read',\n} as const;\n\nconst realPermissions = (authEE as any).MastraFGAPermissions;\n\n// Typed as `any` on purpose: consumers of `@mastra/server` may run their\n// typecheck against a `@mastra/core` that doesn't export `MastraFGAPermissions`\n// (anything < 1.32.0). Pinning to the real type would push that name into the\n// emitted `.d.ts` and break downstream typecheck. `any` lets the property\n// accesses (`MastraFGAPermissions.AGENTS_READ`) flow through cleanly on every\n// supported core.\nexport const MastraFGAPermissions: any =\n realPermissions && Object.keys(realPermissions).length > 0 ? realPermissions : FALLBACK_PERMISSIONS;\n","import type { MastraFGAPermissionInput } from '@mastra/core/auth/ee';\nimport type { RequestContext } from '@mastra/core/di';\nimport { MastraMemory } from '@mastra/core/memory';\nimport { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY } from '../constants';\nimport { MastraFGAPermissions } from '../fga-permissions';\nimport { HTTPException } from '../http-exception';\n\n// Validation helper\nexport function validateBody(body: Record) {\n const errorResponse = Object.entries(body).reduce>((acc, [key, value]) => {\n if (!value) {\n acc[key] = `Argument \"${key}\" is required`;\n }\n return acc;\n }, {});\n\n if (Object.keys(errorResponse).length > 0) {\n throw new HTTPException(400, { message: Object.values(errorResponse)[0] });\n }\n}\n\n/**\n * sanitizes the body by removing disallowed keys.\n * @param body body to sanitize\n * @param disallowedKeys keys to remove from the body\n */\nexport function sanitizeBody(body: Record, disallowedKeys: string[]) {\n for (const key of disallowedKeys) {\n if (key in body) {\n delete body[key];\n }\n }\n}\n\nexport function parsePerPage(\n value: string | undefined,\n defaultValue: number = 100,\n max: number = 1000,\n): number | false {\n const normalized = (value || '').trim().toLowerCase();\n // Handle explicit false to bypass pagination\n if (normalized === 'false') {\n return false;\n }\n const parsed = parseInt(value || String(defaultValue), 10);\n if (isNaN(parsed)) return defaultValue;\n return Math.min(max, Math.max(1, parsed));\n}\n\n/**\n * Parses filter query parameters into a key-value object.\n */\nexport function parseFilters(filters: string | string[] | undefined): Record | undefined {\n if (!filters) return undefined;\n\n return Object.fromEntries(\n (Array.isArray(filters) ? filters : [filters]).map((attr: string) => {\n const [key, ...valueParts] = attr.split(':');\n const value = valueParts.join(':'); // ✅ Handles colons in values\n return [key, value];\n }),\n );\n}\n\n// ============================================================================\n// Authorization Utilities\n// ============================================================================\n\n/**\n * Gets the effective resourceId, preferring the reserved key from requestContext\n * over client-provided values for security.\n */\nexport function getEffectiveResourceId(\n requestContext: RequestContext | undefined,\n clientResourceId: string | undefined,\n): string | undefined {\n const contextResourceId = requestContext?.get(MASTRA_RESOURCE_ID_KEY) as string | undefined;\n return contextResourceId || clientResourceId;\n}\n\n/**\n * Gets the effective threadId, preferring the reserved key from requestContext\n * over client-provided values for security.\n */\nexport function getEffectiveThreadId(\n requestContext: RequestContext | undefined,\n clientThreadId: string | undefined,\n): string | undefined {\n const contextThreadId = requestContext?.get(MASTRA_THREAD_ID_KEY) as string | undefined;\n return contextThreadId || clientThreadId;\n}\n\n/**\n * Validates that a thread belongs to the specified resourceId.\n * Throws 403 if the thread exists but belongs to a different resource.\n * Threads with no resourceId are accessible to all (shared threads).\n */\nexport async function validateThreadOwnership(\n thread: { resourceId?: string | null } | null | undefined,\n effectiveResourceId: string | undefined,\n): Promise {\n if (thread && effectiveResourceId && thread.resourceId && thread.resourceId !== effectiveResourceId) {\n throw new HTTPException(403, { message: 'Access denied: thread belongs to a different resource' });\n }\n}\n\n/**\n * Validates both coarse resource ownership and fine-grained thread access.\n * FGA enforcement is a no-op when no FGA provider is configured.\n */\nexport async function enforceThreadAccess({\n mastra,\n requestContext,\n threadId,\n thread,\n effectiveResourceId,\n permission = MastraFGAPermissions.MEMORY_READ,\n}: {\n mastra: any;\n requestContext?: RequestContext;\n threadId: string;\n thread?: { resourceId?: string | null } | null;\n effectiveResourceId?: string;\n permission?: MastraFGAPermissionInput;\n}): Promise {\n await validateThreadOwnership(thread, effectiveResourceId);\n\n const fgaProvider = mastra?.getServer?.()?.fga;\n if (!fgaProvider) {\n return;\n }\n\n const user = requestContext?.get('user');\n if (!user || typeof user !== 'object') {\n throw new HTTPException(403, { message: 'FGA authorization denied: authenticated user is required' });\n }\n\n await MastraMemory.checkThreadFGA({\n mastra,\n user: user as { id: string; [key: string]: unknown },\n threadId,\n resourceId: thread?.resourceId ?? effectiveResourceId,\n requestContext,\n permission,\n });\n}\n\n/**\n * Validates that a workflow run belongs to the specified resourceId.\n * Throws 403 if the run exists but belongs to a different resource.\n */\nexport async function validateRunOwnership(\n run: { resourceId?: string | null } | null | undefined,\n effectiveResourceId: string | undefined,\n): Promise {\n if (run && effectiveResourceId && run.resourceId && run.resourceId !== effectiveResourceId) {\n throw new HTTPException(403, { message: 'Access denied: workflow run belongs to a different resource' });\n }\n}\n"]}