@mastra/server 1.79.0 → 1.80.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/dist/_types/@internal_core/dist/storage/index.d.ts +243 -243
  2. package/dist/_types/@internal_voice/dist/_types/@internal_core/dist/request-context/index.d.ts +13 -13
  3. package/dist/_types/@internal_voice/dist/_types/@internal_core/dist/routes/index.d.ts +12 -12
  4. package/dist/_types/@internal_voice/dist/_types/@internal_core/dist/types/index.d.ts +1 -2
  5. package/dist/{agent-builder-CuBD1tpv.cjs → agent-builder-BkPIfCgW.cjs} +2 -2
  6. package/dist/{agent-builder-CuBD1tpv.cjs.map → agent-builder-BkPIfCgW.cjs.map} +1 -1
  7. package/dist/{agent-builder-VhM8ADW-.js → agent-builder-DvxYJR85.js} +2 -2
  8. package/dist/{agent-builder-VhM8ADW-.js.map → agent-builder-DvxYJR85.js.map} +1 -1
  9. package/dist/{api-schema-manifest-DIlNfbyw.cjs → api-schema-manifest-CQSdIekp.cjs} +2 -2
  10. package/dist/{api-schema-manifest-DIlNfbyw.cjs.map → api-schema-manifest-CQSdIekp.cjs.map} +1 -1
  11. package/dist/{api-schema-manifest-CI90M4sX.js → api-schema-manifest-Ce-tWsRS.js} +2 -2
  12. package/dist/{api-schema-manifest-CI90M4sX.js.map → api-schema-manifest-Ce-tWsRS.js.map} +1 -1
  13. package/dist/{dist-B-bEVWlJ.cjs → dist-B3KkuNCj.cjs} +41 -7
  14. package/dist/{dist-B-bEVWlJ.cjs.map → dist-B3KkuNCj.cjs.map} +1 -1
  15. package/dist/dist-CTklSbUE.js +1 -0
  16. package/dist/{dist-k77XQGUn.js → dist-DqKW0v-Y.js} +41 -7
  17. package/dist/{dist-k77XQGUn.js.map → dist-DqKW0v-Y.js.map} +1 -1
  18. package/dist/{dist-B3kC8Yd0.cjs → dist-rMs0TQWs.cjs} +1 -1
  19. package/dist/docs/SKILL.md +2 -2
  20. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  21. package/dist/docs/references/docs-connections-a2a.md +1 -1
  22. package/dist/docs/references/docs-guides-mcp-authentication-authorization.md +2 -2
  23. package/dist/docs/references/docs-server-middleware.md +1 -1
  24. package/dist/docs/references/reference-observability-tracing-advanced-queries.md +92 -11
  25. package/dist/{helpers-CAcEhq38.cjs → helpers-DvzrUzqY.cjs} +2 -2
  26. package/dist/{helpers-CAcEhq38.cjs.map → helpers-DvzrUzqY.cjs.map} +1 -1
  27. package/dist/{helpers-vrqddDd5.js → helpers-gCkmhB9x.js} +2 -2
  28. package/dist/{helpers-vrqddDd5.js.map → helpers-gCkmhB9x.js.map} +1 -1
  29. package/dist/{observability-BBMCMeT-.cjs → observability-C2BZQ2jU.cjs} +3 -2
  30. package/dist/{observability-BBMCMeT-.cjs.map → observability-C2BZQ2jU.cjs.map} +1 -1
  31. package/dist/{observability-ZRgRcvoX.js → observability-Dz9jvMJ3.js} +3 -2
  32. package/dist/{observability-ZRgRcvoX.js.map → observability-Dz9jvMJ3.js.map} +1 -1
  33. package/dist/{observability-new-endpoints-fjoZzEtk.js → observability-new-endpoints-3DlTYf34.js} +117 -4
  34. package/dist/observability-new-endpoints-3DlTYf34.js.map +1 -0
  35. package/dist/{observability-new-endpoints-tG3-odLa.cjs → observability-new-endpoints-Drr7q2Dj.cjs} +121 -2
  36. package/dist/observability-new-endpoints-Drr7q2Dj.cjs.map +1 -0
  37. package/dist/{probe-image-size-BdfbUHxx.js → probe-image-size-BRq0A2_y.js} +2 -2
  38. package/dist/{probe-image-size-BdfbUHxx.js.map → probe-image-size-BRq0A2_y.js.map} +1 -1
  39. package/dist/{probe-image-size-Alv3gwKl.cjs → probe-image-size-C8vYbACH.cjs} +2 -2
  40. package/dist/{probe-image-size-Alv3gwKl.cjs.map → probe-image-size-C8vYbACH.cjs.map} +1 -1
  41. package/dist/{routes-DGLJyqjD.cjs → routes-B4I5n3rK.cjs} +12 -11
  42. package/dist/routes-B4I5n3rK.cjs.map +1 -0
  43. package/dist/{routes-BC20mdNN.js → routes-nhnsGZVb.js} +12 -11
  44. package/dist/routes-nhnsGZVb.js.map +1 -0
  45. package/dist/server/auth/helpers.d.ts.map +1 -1
  46. package/dist/server/auth/index.cjs +1 -1
  47. package/dist/server/auth/index.js +1 -1
  48. package/dist/server/handlers/agent-builder.cjs +1 -1
  49. package/dist/server/handlers/agent-builder.js +1 -1
  50. package/dist/server/handlers/auth.cjs +15 -1
  51. package/dist/server/handlers/auth.cjs.map +1 -1
  52. package/dist/server/handlers/auth.d.ts.map +1 -1
  53. package/dist/server/handlers/auth.js +15 -1
  54. package/dist/server/handlers/auth.js.map +1 -1
  55. package/dist/server/handlers/mcp-client-versions.cjs +1 -1
  56. package/dist/server/handlers/mcp-client-versions.js +1 -1
  57. package/dist/server/handlers/observability-new-endpoints.cjs +2 -1
  58. package/dist/server/handlers/observability-new-endpoints.d.ts +132 -0
  59. package/dist/server/handlers/observability-new-endpoints.d.ts.map +1 -1
  60. package/dist/server/handlers/observability-new-endpoints.js +1 -1
  61. package/dist/server/handlers/observability-shared.cjs +19 -0
  62. package/dist/server/handlers/observability-shared.cjs.map +1 -1
  63. package/dist/server/handlers/observability-shared.d.ts +10 -0
  64. package/dist/server/handlers/observability-shared.d.ts.map +1 -1
  65. package/dist/server/handlers/observability-shared.js +18 -1
  66. package/dist/server/handlers/observability-shared.js.map +1 -1
  67. package/dist/server/handlers/observability.cjs +3 -2
  68. package/dist/server/handlers/observability.js +3 -3
  69. package/dist/server/handlers/prompt-block-versions.cjs +1 -1
  70. package/dist/server/handlers/prompt-block-versions.js +1 -1
  71. package/dist/server/handlers/schedules-workflows-shim.cjs.map +1 -1
  72. package/dist/server/handlers/schedules-workflows-shim.js.map +1 -1
  73. package/dist/server/handlers/scorer-versions.cjs +1 -1
  74. package/dist/server/handlers/scorer-versions.js +1 -1
  75. package/dist/server/handlers/stored-agents.cjs +29 -11
  76. package/dist/server/handlers/stored-agents.cjs.map +1 -1
  77. package/dist/server/handlers/stored-agents.d.ts.map +1 -1
  78. package/dist/server/handlers/stored-agents.js +29 -11
  79. package/dist/server/handlers/stored-agents.js.map +1 -1
  80. package/dist/server/handlers/stored-mcp-clients.cjs +1 -1
  81. package/dist/server/handlers/stored-mcp-clients.js +1 -1
  82. package/dist/server/handlers/stored-prompt-blocks.cjs +1 -1
  83. package/dist/server/handlers/stored-prompt-blocks.js +1 -1
  84. package/dist/server/handlers/stored-scorers.cjs +1 -1
  85. package/dist/server/handlers/stored-scorers.js +1 -1
  86. package/dist/server/handlers/stored-skill-favorites.cjs +1 -1
  87. package/dist/server/handlers/stored-skill-favorites.js +1 -1
  88. package/dist/server/handlers/stored-skills.cjs +1 -1
  89. package/dist/server/handlers/stored-skills.js +1 -1
  90. package/dist/server/handlers/system.cjs +2 -2
  91. package/dist/server/handlers/system.d.ts +2 -0
  92. package/dist/server/handlers/system.d.ts.map +1 -1
  93. package/dist/server/handlers/system.js +2 -2
  94. package/dist/server/handlers/tools.d.ts.map +1 -1
  95. package/dist/server/handlers/workspace.cjs +1 -1
  96. package/dist/server/handlers/workspace.d.ts +23 -23
  97. package/dist/server/handlers/workspace.js +1 -1
  98. package/dist/server/handlers.cjs +3 -3
  99. package/dist/server/handlers.js +3 -3
  100. package/dist/server/schemas/index.cjs +2 -2
  101. package/dist/server/schemas/index.js +2 -2
  102. package/dist/server/schemas/system.d.ts +2 -0
  103. package/dist/server/schemas/system.d.ts.map +1 -1
  104. package/dist/server/server-adapter/index.cjs +95 -3
  105. package/dist/server/server-adapter/index.cjs.map +1 -1
  106. package/dist/server/server-adapter/index.d.ts +28 -1
  107. package/dist/server/server-adapter/index.d.ts.map +1 -1
  108. package/dist/server/server-adapter/index.js +93 -4
  109. package/dist/server/server-adapter/index.js.map +1 -1
  110. package/dist/server/server-adapter/mcp-disconnect.d.ts +16 -0
  111. package/dist/server/server-adapter/mcp-disconnect.d.ts.map +1 -0
  112. package/dist/server/server-adapter/routes/observability.d.ts +129 -0
  113. package/dist/server/server-adapter/routes/observability.d.ts.map +1 -1
  114. package/dist/server/server-adapter/routes/system.d.ts +2 -0
  115. package/dist/server/server-adapter/routes/system.d.ts.map +1 -1
  116. package/dist/server/server-adapter/routes/workspace.d.ts +23 -23
  117. package/dist/{system-BvpFMIJB.cjs → system-B_Sod-Le.cjs} +2 -1
  118. package/dist/system-B_Sod-Le.cjs.map +1 -0
  119. package/dist/{system-CpzPxRRq.js → system-sSSmmt7I.js} +2 -1
  120. package/dist/system-sSSmmt7I.js.map +1 -0
  121. package/dist/tools-CmFSfDMn.js.map +1 -1
  122. package/dist/tools-SPJtxG9N.cjs.map +1 -1
  123. package/dist/{workspace-B6kzp-bo.js → workspace-BVHXoKmP.js} +2 -2
  124. package/dist/workspace-BVHXoKmP.js.map +1 -0
  125. package/dist/{workspace-COKR1SxH.cjs → workspace-d25MZ9dj.cjs} +2 -2
  126. package/dist/workspace-d25MZ9dj.cjs.map +1 -0
  127. package/package.json +9 -9
  128. package/dist/dist-BM9J-PTK.js +0 -1
  129. package/dist/observability-new-endpoints-fjoZzEtk.js.map +0 -1
  130. package/dist/observability-new-endpoints-tG3-odLa.cjs.map +0 -1
  131. package/dist/routes-BC20mdNN.js.map +0 -1
  132. package/dist/routes-DGLJyqjD.cjs.map +0 -1
  133. package/dist/system-BvpFMIJB.cjs.map +0 -1
  134. package/dist/system-CpzPxRRq.js.map +0 -1
  135. package/dist/workspace-B6kzp-bo.js.map +0 -1
  136. package/dist/workspace-COKR1SxH.cjs.map +0 -1
@@ -1,3 +1,3 @@
1
1
  require("./rolldown-runtime-BwC_XMyb.cjs");
2
- const require_dist = require("./dist-B-bEVWlJ.cjs");
2
+ const require_dist = require("./dist-B3KkuNCj.cjs");
3
3
  exports.openai = require_dist.openai;
@@ -3,7 +3,7 @@ name: mastra-server
3
3
  description: Documentation for @mastra/server. Use when working with @mastra/server APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/server"
6
- version: "1.79.0"
6
+ version: "1.80.0-alpha.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -24,7 +24,7 @@ Read the individual reference documents for detailed explanations and code examp
24
24
 
25
25
  ### Reference
26
26
 
27
- - [Reference: Advanced trace queries](references/reference-observability-tracing-advanced-queries.md) - Find, count, and measure completed traces with structured predicates. List matching traces, aggregate them into grouped measures, paginate, poll, and discover query fields.
27
+ - [Reference: Advanced trace queries](references/reference-observability-tracing-advanced-queries.md) - Find, count, and measure completed traces and spans with structured predicates. List matching traces, aggregate traces or spans into grouped measures, paginate, poll, and discover query fields.
28
28
  - [Reference: createRoute()](references/reference-server-create-route.md) - Use createRoute() to define type-safe Mastra server routes with Zod validation for requests and responses, plus handler context and OpenAPI metadata.
29
29
  - [Reference: MastraServer](references/reference-server-mastra-server.md) - The MastraServer abstract class is the base for all server adapters. Extend this class to create adapters for frameworks other than Hono or Express.
30
30
  - [Reference: Server routes](references/reference-server-routes.md) - Server adapters register these routes when you call server.init(). All routes are prefixed with the prefix option if configured.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.79.0",
2
+ "version": "1.80.0-alpha.0",
3
3
  "package": "@mastra/server",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -100,7 +100,7 @@ export const supportAgent = new Agent({
100
100
  id: 'support-agent',
101
101
  name: 'Support Agent',
102
102
  instructions: 'Answer user questions and delegate weather questions when needed.',
103
- model: 'openai/gpt-5.6-sol',
103
+ model: 'openai/gpt-6.1-sol',
104
104
  agents: {
105
105
  remoteWeatherAgent,
106
106
  },
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Discover all available pages from the documentation index: https://mastra.ai/llms.txt
4
4
 
5
- # MCP authentication
5
+ # MCP authentication and authorization
6
6
 
7
7
  You either connect your Mastra application to someone else's protected MCP server, or you expose your own tools and data to a third-party client. Each direction needs different credentials and different checks.
8
8
 
@@ -125,7 +125,7 @@ An MCP access token is for the MCP server. The specification prohibits passing t
125
125
 
126
126
  Keep access tokens, refresh tokens, and service credentials outside model-visible instructions, tool arguments, and tool results. Return only the data needed for the task. The [authentication and identity guide](https://mastra.ai/docs/guides/authentication-identity) explains this model boundary.
127
127
 
128
- ## Verify before production
128
+ ## Production checklist
129
129
 
130
130
  - [ ] **Validate tokens:** Configure validation for your issuer, including audience and expiry checks, and confirm an unvalidated token is rejected.
131
131
  - [ ] **Challenge missing tokens:** Confirm every protected server path returns `401` without a bearer token.
@@ -8,7 +8,7 @@ Mastra servers can execute custom middleware functions before or after an API ro
8
8
 
9
9
  A middleware receives the [Hono](https://hono.dev) `Context` (`c`) and a `next` function. If it returns a `Response` the request is short-circuited. Calling `next()` continues processing the next middleware or route handler.
10
10
 
11
- > **Note:** Middleware handlers use Hono's signature, so they run on Hono-based serving paths: `mastra dev` and `mastra build`, the [Hono adapter](https://mastra.ai/reference/server/hono-adapter), and adapters built on it such as `@mastra/next` and `@mastra/tanstack-start`. Adapters for other frameworks (Express, Fastify, Koa) can't run Hono handlers and log a warning at startup when middleware is configured. Register middleware through the framework's own API there instead.
11
+ > **Note:** Middleware handlers use Hono's signature, so they run on Hono-based serving paths: `mastra dev` and `mastra build`, the [Hono adapter](https://mastra.ai/reference/server/hono-adapter), and adapters built on it such as `@mastra/next` and `@mastra/tanstack-start`. Adapters for other frameworks (Elysia, Express, Fastify, Koa, NestJS) can't run Hono handlers and log a warning at startup when middleware is configured. Register middleware through the framework's own API there instead.
12
12
  >
13
13
  > User middleware never runs on routes declared public with `requiresAuth: false`, so it can't block endpoints the framework needs to keep reachable, such as the Studio sign-in routes.
14
14
 
@@ -10,8 +10,9 @@ Advanced trace queries select completed traces with a structured time range and
10
10
  | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | ------------------------------------------ |
11
11
  | Query traces | List matching traces, paginate through them, and poll for new ones. | `queryTraces()` | `POST /api/observability/traces/query` |
12
12
  | Aggregate traces | Count matching traces and compute measures, such as error rate, latency percentiles, tokens, and cost, optionally grouped by dimensions and time buckets. | `aggregateTraces()` | `POST /api/observability/traces/aggregate` |
13
+ | Aggregate spans | Compute the same measures over individual spans, such as every agent run including nested ones, grouped by span dimensions. | `aggregateSpans()` | `POST /api/observability/spans/aggregate` |
13
14
 
14
- Both APIs accept the same [trace selection](#select-traces). The filters, operators, and limits on this page apply to each. Use the aggregate API to find the group that needs attention, such as an agent with a high error rate, then send the same predicate plus the group's dimensions to the query API to list the traces behind it. Each query result represents a trace. Use its `traceId` to [retrieve the full trace](https://mastra.ai/reference/client-js/observability).
15
+ The trace APIs accept the same [trace selection](#select-traces). The filters, operators, and limits on this page apply to each. Use the aggregate API to find the group that needs attention, such as an agent with a high error rate, then send the same predicate plus the group's dimensions to the query API to list the traces behind it. Each query result represents a trace. Use its `traceId` to [retrieve the full trace](https://mastra.ai/reference/client-js/observability).
15
16
 
16
17
  The endpoints use the same authentication as other observability routes and require the `observability:read` permission. Every request requires a time range.
17
18
 
@@ -25,6 +26,7 @@ The configured observability store must support each API. Call `getObservability
25
26
  | -------------------------------- | -------------------------------------- | -------------------------------------------------------------------------------------- |
26
27
  | `traceQuery` | `trace-query` | `queryTraces()` |
27
28
  | `traceAggregate` | `trace-aggregate` | `aggregateTraces()` |
29
+ | `spanAggregate` | `span-aggregate` | `aggregateSpans()` |
28
30
  | `traceQueryRootDuration` | `trace-query-root-duration` | Trace-scope `durationMs` predicates |
29
31
  | `traceQueryTimeToFirstChunk` | `trace-query-time-to-first-chunk` | `timeToFirstChunkMs` predicates and results |
30
32
  | `traceQueryTimeToFirstChunkSort` | `trace-query-time-to-first-chunk-sort` | `orderBy` on `timeToFirstChunkMs` |
@@ -34,7 +36,7 @@ The configured observability store must support each API. Call `getObservability
34
36
  | `traceQueryDiscovery` | `trace-query-discovery` | [Field and value discovery](#discover-fields-and-values) |
35
37
  | `traceQueryTenantScope` | `trace-query-tenant-scope` | [Trusted tenant scope](#trusted-tenant-scope) |
36
38
 
37
- A missing `traceAggregate` value means the server doesn't support aggregation. Servers without the aggregate route return `404`, and stores without the feature return `501 TRACE_AGGREGATE_UNSUPPORTED`. Against a store without a sub-feature, a request that uses a gated field returns `501` before storage runs. Root span `name`, `spanType`, and `entityId` are the exception and return `422` with a `field_not_allowed` issue.
39
+ A missing `traceAggregate` value means the server doesn't support aggregation. Servers without the aggregate route return `404`, and stores without the feature return `501 TRACE_AGGREGATE_UNSUPPORTED`. A missing `spanAggregate` value means the same for span aggregation, and stores without the feature return `501 SPAN_AGGREGATE_UNSUPPORTED`. Against a store without a sub-feature, a request that uses a gated field returns `501` before storage runs. Root span `name`, `spanType`, and `entityId` are the exception and return `422` with a `field_not_allowed` issue.
38
40
 
39
41
  ## Select traces
40
42
 
@@ -212,7 +214,7 @@ const selectedModel = {
212
214
  {
213
215
  op: 'eq',
214
216
  left: { path: 'model' },
215
- right: { literal: 'claude-sonnet-4-6' },
217
+ right: { literal: 'claude-sonnet-5-5' },
216
218
  },
217
219
  { op: 'eq', left: { path: 'provider' }, right: { literal: 'anthropic' } },
218
220
  ],
@@ -700,14 +702,14 @@ Token and cost measures read the model usage metrics recorded for each trace, so
700
702
 
701
703
  A trace that recorded at least one usage metric is usage-bearing. `tokens.<kind>.sum` adds the tokens of a group's usage-bearing traces, and `tokens.<kind>.avg` divides that sum by the number of usage-bearing traces, not by `count`. Both are `null` when the group has no usage-bearing traces.
702
704
 
703
- Cost comes from estimated cost recorded on total input and total output token metrics. `cost.sum` adds the cost of traces with at least one priced metric, and `cost.avg` divides by the number of those traces. A metric whose pricing failed, including a partial cost, isn't priced.
705
+ Cost comes from estimated cost recorded on total input and total output token metrics. `cost.sum` adds the cost of traces with at least one priced metric, and `cost.avg` divides by the number of those traces. A partly priced call, where Mastra could price some token types but not others, adds the cost of the priced token types. A metric with any other pricing failure adds no cost.
704
706
 
705
707
  When you request any `cost.*` measure, every row also includes a `cost` object:
706
708
 
707
- | Field | Description |
708
- | ---------- | ------------------------------------------------------------------------------------------------------------------------------ |
709
- | `coverage` | Fraction of usage-bearing traces whose usage was fully priced, from 0 to 1. `null` when the group has no usage-bearing traces. |
710
- | `unit` | Cost unit of the priced metrics, such as `USD`. `'mixed'` when they use more than one unit, and `null` when none are priced. |
709
+ | Field | Description |
710
+ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
711
+ | `coverage` | Fraction of usage-bearing traces whose usage was fully priced, from 0 to 1. A trace with a partly priced call isn't fully priced, so it lowers coverage even though its known cost is in `cost.sum`. `null` when the group has no usage-bearing traces. |
712
+ | `unit` | Cost unit of the priced metrics, such as `USD`. `'mixed'` when they use more than one unit, and `null` when none are priced. |
711
713
 
712
714
  `cost.sum` and `cost.avg` are `null` when the group has no priced traces or `unit` is `'mixed'`. A coverage below 1 means the cost understates the group's spend. The `cost` object isn't a measure, so `having` and `orderBy` can't reference it.
713
715
 
@@ -803,11 +805,90 @@ PostgreSQL and ClickHouse stop aggregations after the same `traceQueryTimeoutMs`
803
805
  | `501` | The installed Core or configured observability store doesn't support aggregation or a requested field. Returns `TRACE_AGGREGATE_UNSUPPORTED`. |
804
806
  | `504` | A PostgreSQL or ClickHouse aggregation exceeded its execution timeout. Returns `TRACE_QUERY_EXECUTION_TIMEOUT` without partial results. |
805
807
 
808
+ ## Aggregate spans
809
+
810
+ Use `aggregateSpans()` or `POST /api/observability/spans/aggregate` to compute measures over individual spans instead of traces. Trace aggregation only sees each trace's root span, so an agent run nested inside a workflow isn't counted. Span aggregation counts every span that matches, at any depth.
811
+
812
+ The request has the same shape as [`aggregateTraces()`](#aggregate-request-fields), with the same measures, `having`, `orderBy`, `interval`, limits, and errors. The differences are in which records are selected and which dimensions are available.
813
+
814
+ ### Aggregate spans with the client SDK
815
+
816
+ This request counts agent runs by status per day, including nested runs:
817
+
818
+ ```typescript
819
+ const { capabilities } = await mastraClient.getObservabilityCapabilities()
820
+
821
+ if (capabilities.spanAggregate) {
822
+ const { rows } = await mastraClient.aggregateSpans({
823
+ timeRange: {
824
+ from: '2026-08-01T00:00:00.000Z',
825
+ to: '2026-08-08T00:00:00.000Z',
826
+ },
827
+ where: { op: 'eq', left: { path: 'spanType' }, right: { literal: 'agent_run' } },
828
+ groupBy: ['status'],
829
+ interval: '1d',
830
+ measures: ['count', 'duration.p95'],
831
+ })
832
+ }
833
+ ```
834
+
835
+ Send the same body to `POST /api/observability/spans/aggregate` to use HTTP directly.
836
+
837
+ ### Span selection
838
+
839
+ Aggregation selects the spans that [`querySpans()`](https://mastra.ai/reference/client-js/observability) would return for the same `timeRange` and `where`:
840
+
841
+ - `timeRange` bounds each span's `startedAt`, and can span up to 365 days.
842
+ - `where` accepts the `querySpans()` fields and operators, such as `spanType`, `name`, `status`, `durationMs`, entity and parent/root entity fields, and context identifiers.
843
+ - Only completed spans count. When a span was exported more than once, only its latest copy counts.
844
+
845
+ `count` equals the number of spans `querySpans()` pages through for the same request. Buckets use each span's `startedAt`. `duration.*` measures read the span's own duration, and `errorCount` and `errorRate` read whether the span itself recorded an error.
846
+
847
+ On ClickHouse, a request whose `where` limits `spanType` to agent, workflow, processor, or scorer runs, RAG ingestion, or tool calls reads the smaller branch table instead of every span. That path can differ from `querySpans()`:
848
+
849
+ - Spans written before an upgrade from `@mastra/clickhouse` 1.4, 1.5, or 1.6 aren't in the branch table, so older windows can count fewer spans.
850
+ - After ClickHouse merges the copies of a span exported more than once, the branch table keeps the copy written last, not the one that ended last. Counts don't change, but the `status` and duration of a retried span can.
851
+
852
+ ### Span dimensions
853
+
854
+ | Dimension | Notes |
855
+ | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
856
+ | `name`, `spanType`, `status` | The span's own name, type, and status. `status` is `error` when the span recorded an error and `success` otherwise. |
857
+ | `entityType`, `entityId`, `entityName` | The entity that produced the span. |
858
+ | `parentEntityType`, `parentEntityName`, `rootEntityType`, `rootEntityName` | The calling entity and the trace's root entity, such as the agent that made a model call. |
859
+ | `environment`, `serviceName`, `executionSource` | Deployment attributes recorded on the span. |
860
+ | `threadId`, `resourceId`, `userId`, `sessionId`, `organizationId`, `experimentId` | Context identifiers recorded on the span. |
861
+
862
+ `countDistinct.<field>` accepts these dimensions and `traceId`, so `countDistinct.traceId` counts the traces the selected spans belong to. Span aggregation can't group by `metadata.<key>`, identity fields such as `traceId`, `spanId`, or `runId`, or by model and provider.
863
+
864
+ ### Span tokens and cost
865
+
866
+ Token and cost measures use the usage metrics recorded by each span, matched by `traceId` and `spanId`. The [trace token rules](#token-and-cost-measures) apply per span: metrics from `timeRange.from` on count, retried exports count once, and averages divide by usage-bearing spans.
867
+
868
+ Usage isn't added up to parent spans. Model calls record usage on `model_generation` spans, so an `agent_run` span has no tokens of its own unless a model call under it wasn't exported. When a `model_generation` span isn't exported, its usage is recorded on the nearest exported ancestor instead. For token totals per agent, select `model_generation` spans and group by the calling agent:
869
+
870
+ ```typescript
871
+ const tokensByAgent = await mastraClient.aggregateSpans({
872
+ timeRange: {
873
+ from: '2026-08-01T00:00:00.000Z',
874
+ to: '2026-08-08T00:00:00.000Z',
875
+ },
876
+ where: { op: 'eq', left: { path: 'spanType' }, right: { literal: 'model_generation' } },
877
+ groupBy: ['parentEntityName'],
878
+ measures: ['tokens.total.sum', 'cost.sum'],
879
+ orderBy: { field: 'cost.sum', direction: 'desc' },
880
+ })
881
+ ```
882
+
883
+ ### List the spans behind a group
884
+
885
+ Aggregation never returns span records. To inspect a group, send the same `timeRange` and `where` to `querySpans()`, and add the group's dimension values as `eq` conditions. For example, add `{ op: 'eq', left: { path: 'status' }, right: { literal: 'error' } }` to list the failed agent runs from the first example.
886
+
806
887
  ## Trusted tenant scope
807
888
 
808
- Hosts that serve more than one tenant supply a trusted scope outside the query document. The server reads the reserved `organizationId` request-context key, which only server-side authentication can set, and passes `{ organizationId }` to the planner. The scope is carried on the trusted plan and ANDed into every scan: current roots, related spans, the usage metrics read by token and cost measures, and both discovery routes. A related record from another tenant that shares a `traceId` never qualifies a trace.
889
+ Hosts that serve more than one tenant supply a trusted scope outside the query document. The server reads the reserved `organizationId` request-context key, which only server-side authentication can set, and passes `{ organizationId }` to the planner. The scope is carried on the trusted plan and ANDed into every scan: current roots, related spans, the usage metrics read by token and cost measures, span aggregation, and both discovery routes. A related record from another tenant that shares a `traceId` never qualifies a trace.
809
890
 
810
- Hosts that call storage directly can pass a fuller scope to `planTraceQuery()`, `planTraceAggregate()`, `planTraceQueryObservedFields()`, and `planTraceQueryValues()`:
891
+ Hosts that call storage directly can pass a fuller scope to `planTraceQuery()`, `planTraceAggregate()`, `planSpanAggregate()`, `planTraceQueryObservedFields()`, and `planTraceQueryValues()`:
811
892
 
812
893
  ```typescript
813
894
  const plan = planTraceQuery(parseTraceQueryRequest(request), {
@@ -938,7 +1019,7 @@ Both routes require `observability:read` and use the configured observability st
938
1019
 
939
1020
  ## Limitations
940
1021
 
941
- Both APIs consider completed traces only and don't include running traces. Trace queries can't return custom projections, embedded evidence, or summaries, and numbered trace pages include a total count. Aggregation can't group by span fields, `traceId`, or `attributes.*`, compute numeric measures over metadata, paginate groups, or zero-fill empty buckets. The CLI doesn't expose a trace aggregation command, so use the SDK or the HTTP endpoint.
1022
+ The query and aggregate APIs consider completed traces and spans only, not running ones. Trace queries can't return custom projections, embedded evidence, or summaries, and numbered trace pages include a total count. Trace aggregation can't group by span fields other than the root span's `name`, `spanType`, and `entityId`, or by `traceId` or `attributes.*`. Aggregation can't compute numeric measures over metadata, paginate groups, or zero-fill empty buckets. Span aggregation can't group by `model` or `provider`, and it attributes tokens only to the span that recorded them. The CLI's `mastra api trace aggregate` covers trace aggregation, and `mastra api span query` and `mastra api span aggregate` cover span queries and span aggregation.
942
1023
 
943
1024
  ## Related
944
1025
 
@@ -382,7 +382,7 @@ const coreAuthMiddleware = async (ctx) => {
382
382
  body: { error: "Access denied" },
383
383
  headers: refreshHeaders
384
384
  };
385
- } else if (mastra.getServer()?.rbac) {
385
+ } else if (requestContext.get("mastra__authMode") === "studio" ? mastra.getStudio?.()?.rbac ?? mastra.getServer()?.rbac : mastra.getServer()?.rbac) {
386
386
  if (defaultAuthConfig.rules && defaultAuthConfig.rules.length > 0) {
387
387
  if (!await checkRules(defaultAuthConfig.rules, path, method, user)) return {
388
388
  action: "error",
@@ -500,4 +500,4 @@ Object.defineProperty(exports, "supportsSessionRefresh", {
500
500
  }
501
501
  });
502
502
 
503
- //# sourceMappingURL=helpers-CAcEhq38.cjs.map
503
+ //# sourceMappingURL=helpers-DvzrUzqY.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers-CAcEhq38.cjs","names":["HTTPException","MASTRA_USER_KEY","MASTRA_AUTH_TOKEN_KEY","CompositeAuth","MASTRA_RESOURCE_ID_KEY","MASTRA_AUTH_MODE_KEY","MASTRA_USER_PERMISSIONS_KEY","MASTRA_USER_ROLES_KEY"],"sources":["../src/server/auth/defaults.ts","../src/server/auth/path-pattern.ts","../src/server/auth/helpers.ts"],"sourcesContent":["import type { MastraAuthConfig } from '@mastra/core/server';\n\n// Default configuration that can be extended by clients\nexport const defaultAuthConfig: MastraAuthConfig = {\n protected: ['/api/*'],\n public: ['/api', '/api/auth/*'],\n // Simple rule system\n rules: [\n // Admin users can do anything\n {\n condition: user => {\n if (typeof user === 'object' && user !== null) {\n if ('isAdmin' in user) {\n return !!user.isAdmin;\n }\n\n if ('role' in user) {\n return user.role === 'admin';\n }\n }\n return false;\n },\n allow: true,\n },\n ],\n};\n","/**\n * Path pattern matching utility\n * Inlined from regexparam v3.0.0 (MIT License)\n * https://github.com/lukeed/regexparam\n *\n * Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nexport interface ParsedPattern {\n keys: string[] | false;\n pattern: RegExp;\n}\n\n/**\n * Parse a route pattern into a RegExp\n * Supports:\n * - Named parameters: /users/:id\n * - Optional parameters: /users/:id?\n * - Wildcards: /files/*\n * - Mixed patterns: /api/:version/users/:id\n */\nexport function parse(input: string | RegExp, loose?: boolean): ParsedPattern {\n if (input instanceof RegExp) return { keys: false, pattern: input };\n\n let c: string;\n let o: number;\n let tmp: string | undefined;\n let ext: number;\n const keys: string[] = [];\n let pattern = '';\n const arr = input.split('/');\n\n arr[0] || arr.shift();\n\n while ((tmp = arr.shift())) {\n c = tmp[0]!;\n if (c === '*') {\n keys.push(c);\n pattern += tmp[1] === '?' ? '(?:/(.*))?' : '/(.*)';\n } else if (c === ':') {\n o = tmp.indexOf('?', 1);\n ext = tmp.indexOf('.', 1);\n keys.push(tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length));\n pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';\n if (!!~ext) pattern += (!!~o ? '?' : '') + '\\\\' + tmp.substring(ext);\n } else {\n pattern += '/' + tmp;\n }\n }\n\n return {\n keys: keys,\n pattern: new RegExp('^' + pattern + (loose ? '(?=$|/)' : '/?$'), 'i'),\n };\n}\n\n/**\n * Test if a path matches a pattern\n */\nexport function matchPath(path: string, pattern: string | RegExp): boolean {\n const { pattern: regex } = parse(pattern);\n return regex.test(path);\n}\n","import type { ISessionProvider } from '@mastra/core/auth';\nimport type { IRBACProvider, EEUser } from '@mastra/core/auth/ee';\nimport type { Mastra } from '@mastra/core/mastra';\nimport { CompositeAuth } from '@mastra/core/server';\nimport type { ApiRoute, IMastraAuthProvider, MastraAuthConfig, MastraAuthRequest } from '@mastra/core/server';\n\nimport {\n MASTRA_RESOURCE_ID_KEY,\n MASTRA_USER_KEY,\n MASTRA_USER_PERMISSIONS_KEY,\n MASTRA_USER_ROLES_KEY,\n MASTRA_AUTH_TOKEN_KEY,\n MASTRA_AUTH_MODE_KEY,\n} from '../constants';\nimport { HTTPException } from '../http-exception';\nimport { defaultAuthConfig } from './defaults';\nimport { parse } from './path-pattern';\n\n// Re-export request-context key constants so custom middleware can read namespaced\n// auth state without importing internal paths.\nexport { MASTRA_USER_KEY, MASTRA_USER_PERMISSIONS_KEY, MASTRA_USER_ROLES_KEY } from '../constants';\n\n/**\n * Check if a route is a registered custom route that requires authentication.\n * Returns true only if the route is explicitly registered with requiresAuth: true.\n * Returns false if the route is not in the config or has requiresAuth: false.\n */\nexport const isProtectedCustomRoute = (\n path: string,\n method: string,\n customRouteAuthConfig?: Map<string, boolean>,\n): boolean => {\n if (!customRouteAuthConfig) {\n return false;\n }\n\n // Check exact match first (fast path for static routes)\n const exactRouteKey = `${method}:${path}`;\n if (customRouteAuthConfig.has(exactRouteKey)) {\n return customRouteAuthConfig.get(exactRouteKey) === true;\n }\n\n // Check exact match for ALL method\n const allRouteKey = `ALL:${path}`;\n if (customRouteAuthConfig.has(allRouteKey)) {\n return customRouteAuthConfig.get(allRouteKey) === true;\n }\n\n // Check pattern matches for dynamic routes (e.g., '/users/:id')\n for (const [routeKey, requiresAuth] of customRouteAuthConfig.entries()) {\n const colonIndex = routeKey.indexOf(':');\n if (colonIndex === -1) {\n continue; // Skip malformed keys\n }\n\n const routeMethod = routeKey.substring(0, colonIndex);\n const routePattern = routeKey.substring(colonIndex + 1);\n\n // Check if method matches (exact match or ALL)\n if (routeMethod !== method && routeMethod !== 'ALL') {\n continue;\n }\n\n // Check if path matches the pattern\n if (pathMatchesPattern(path, routePattern)) {\n return requiresAuth === true;\n }\n }\n\n return false; // Not in config = not a protected custom route\n};\n\n/**\n * Find a matching custom API route for the given path and method.\n * Returns the matched route and any extracted path parameters.\n */\nexport const findMatchingCustomRoute = (\n path: string,\n method: string,\n apiRoutes?: ApiRoute[],\n): { route: ApiRoute; params: Record<string, string> } | undefined => {\n if (!apiRoutes) return undefined;\n\n for (const route of apiRoutes) {\n if (route.method !== method && route.method !== 'ALL') continue;\n\n const { keys, pattern: regex } = parse(route.path);\n const match = regex.exec(path);\n if (!match) continue;\n\n const params: Record<string, string> = {};\n if (keys && keys.length > 0) {\n for (let i = 0; i < keys.length; i++) {\n if (match[i + 1] !== undefined) {\n params[keys[i]!] = match[i + 1]!;\n }\n }\n }\n\n return { route, params };\n }\n\n return undefined;\n};\n\n/**\n * Check if request is from dev playground\n * @param getHeader - Function to get header value from request\n * @param customRouteAuthConfig - Map of custom route auth configurations\n */\nexport const isDevPlaygroundRequest = (\n path: string,\n method: string,\n getHeader: (name: string) => string | undefined,\n authConfig: MastraAuthConfig,\n customRouteAuthConfig?: Map<string, boolean>,\n): boolean => {\n const protectedAccess = [...(defaultAuthConfig.protected || []), ...(authConfig.protected || [])];\n return (\n process.env.MASTRA_DEV === 'true' &&\n // Allow if path doesn't match protected patterns AND is not a protected custom route\n ((!isAnyMatch(path, method, protectedAccess) && !isProtectedCustomRoute(path, method, customRouteAuthConfig)) ||\n // Or if has playground header\n getHeader('x-mastra-dev-playground') === 'true')\n );\n};\n\nexport const isCustomRoutePublic = (\n path: string,\n method: string,\n customRouteAuthConfig?: Map<string, boolean>,\n): boolean => {\n if (!customRouteAuthConfig) {\n return false;\n }\n\n // Check exact match first (fast path for static routes)\n const exactRouteKey = `${method}:${path}`;\n if (customRouteAuthConfig.has(exactRouteKey)) {\n return !customRouteAuthConfig.get(exactRouteKey); // True when route opts out of auth\n }\n\n // Check exact match for ALL method\n const allRouteKey = `ALL:${path}`;\n if (customRouteAuthConfig.has(allRouteKey)) {\n return !customRouteAuthConfig.get(allRouteKey);\n }\n\n // Check pattern matches for dynamic routes (e.g., '/users/:id').\n // Any matching pattern that requires auth wins over overlapping public patterns.\n let matchedPublic = false;\n for (const [routeKey, requiresAuth] of customRouteAuthConfig.entries()) {\n const colonIndex = routeKey.indexOf(':');\n if (colonIndex === -1) {\n continue; // Skip malformed keys\n }\n\n const routeMethod = routeKey.substring(0, colonIndex);\n const routePattern = routeKey.substring(colonIndex + 1);\n\n // Check if method matches (exact match or ALL)\n if (routeMethod !== method && routeMethod !== 'ALL') {\n continue;\n }\n\n if (pathMatchesPattern(path, routePattern)) {\n if (requiresAuth) {\n return false;\n }\n matchedPublic = true;\n }\n }\n\n return matchedPublic;\n};\n\n// NOTE: This uses isProtectedCustomRoute (default-allow for unknown paths) rather than\n// !isCustomRoutePublic (default-deny). This is intentional — all registered server and\n// custom routes are auth-checked via registerRoute/checkRouteAuth regardless of this\n// function. The '/api/*' protected pattern exists as a user-facing override mechanism.\n// The old default-deny logic incorrectly blocked non-API paths (e.g. '/', '/agents')\n// which prevented the studio login page from loading in production.\nexport const isProtectedPath = (\n path: string,\n method: string,\n authConfig: MastraAuthConfig,\n customRouteAuthConfig?: Map<string, boolean>,\n): boolean => {\n const protectedAccess = [...(defaultAuthConfig.protected || []), ...(authConfig.protected || [])];\n return isAnyMatch(path, method, protectedAccess) || isProtectedCustomRoute(path, method, customRouteAuthConfig);\n};\n\nexport const canAccessPublicly = (path: string, method: string, authConfig: MastraAuthConfig): boolean => {\n // Check if this path+method combination is publicly accessible\n const publicAccess = [...(defaultAuthConfig.public || []), ...(authConfig.public || [])];\n\n return isAnyMatch(path, method, publicAccess);\n};\n\nconst isAnyMatch = (\n path: string,\n method: string,\n patterns: MastraAuthConfig['protected'] | MastraAuthConfig['public'],\n): boolean => {\n if (!patterns) {\n return false;\n }\n\n for (const patternPathOrMethod of patterns) {\n if (patternPathOrMethod instanceof RegExp) {\n if (patternPathOrMethod.test(path)) {\n return true;\n }\n }\n\n if (typeof patternPathOrMethod === 'string' && pathMatchesPattern(path, patternPathOrMethod)) {\n return true;\n }\n\n if (Array.isArray(patternPathOrMethod) && patternPathOrMethod.length === 2) {\n const [pattern, methodOrMethods] = patternPathOrMethod;\n if (pathMatchesPattern(path, pattern) && matchesOrIncludes(methodOrMethods, method)) {\n return true;\n }\n }\n }\n\n return false;\n};\n\nexport const pathMatchesPattern = (path: string, pattern: string): boolean => {\n // Use regexparam for battle-tested path matching\n // Supports:\n // - Exact paths: '/api/users'\n // - Wildcards: '/api/agents/*' matches '/api/agents/123'\n // - Path parameters: '/users/:id' matches '/users/123'\n // - Optional parameters: '/users/:id?' matches '/users' and '/users/123'\n // - Mixed patterns: '/api/:version/users/:id/profile'\n const { pattern: regex } = parse(pattern);\n return regex.test(path);\n};\n\nexport const pathMatchesRule = (path: string, rulePath: string | RegExp | string[] | undefined): boolean => {\n if (!rulePath) return true; // No path specified means all paths\n\n if (typeof rulePath === 'string') {\n return pathMatchesPattern(path, rulePath);\n }\n\n if (rulePath instanceof RegExp) {\n return rulePath.test(path);\n }\n\n if (Array.isArray(rulePath)) {\n return rulePath.some(p => pathMatchesPattern(path, p));\n }\n\n return false;\n};\n\nexport const matchesOrIncludes = (values: string | string[], value: string): boolean => {\n if (typeof values === 'string') {\n return values === value;\n }\n\n if (Array.isArray(values)) {\n return values.includes(value);\n }\n\n return false;\n};\n\n// ── Core auth middleware ──\n// Framework-agnostic auth logic extracted from adapter middlewares.\n// Each adapter builds an AuthMiddlewareContext and delegates to coreAuthMiddleware.\n\nexport interface AuthMiddlewareContext {\n path: string;\n method: string;\n getHeader: (name: string) => string | undefined;\n mastra: Mastra;\n authConfig: MastraAuthConfig;\n customRouteAuthConfig?: Map<string, boolean>;\n requestContext: { get: (key: string) => unknown; set: (key: string, value: unknown) => void };\n rawRequest: MastraAuthRequest;\n token: string | null;\n buildAuthorizeContext: () => unknown;\n /** When true, force authentication even if the path matches a public pattern. */\n requiresAuth?: boolean;\n}\n\nexport type AuthResult =\n | { action: 'next'; headers?: Record<string, string> }\n | { action: 'error'; status: number; body: Record<string, unknown>; headers?: Record<string, string> };\n\nconst pass: AuthResult = { action: 'next' };\n\nconst adaptToMastraAuthRequest = (request: MastraAuthRequest): MastraAuthRequest => {\n if (!(request instanceof Request)) {\n return request;\n }\n\n return {\n raw: request,\n headers: request.headers,\n header: name => request.headers.get(name) ?? undefined,\n };\n};\n\nexport interface GetAuthenticatedUserOptions {\n mastra: Mastra;\n token: string;\n request: MastraAuthRequest;\n}\n\nexport const getAuthenticatedUser = async <TUser = unknown>({\n mastra,\n token,\n request,\n}: GetAuthenticatedUserOptions): Promise<TUser | null> => {\n const normalizedToken = token.replace(/^Bearer\\s+/i, '').trim();\n if (!normalizedToken) {\n return null;\n }\n\n const authConfig = mastra.getServer()?.auth;\n if (!authConfig || typeof authConfig.authenticateToken !== 'function') {\n return null;\n }\n\n return (await authConfig.authenticateToken(normalizedToken, request)) as TUser | null;\n};\n\n/**\n * Check if an auth config object supports transparent session refresh.\n * Returns true if the auth provider implements the necessary ISessionProvider methods.\n */\nexport function supportsSessionRefresh(\n authConfig: MastraAuthConfig | IMastraAuthProvider,\n): authConfig is (MastraAuthConfig | IMastraAuthProvider) &\n Pick<ISessionProvider, 'refreshSession' | 'getSessionIdFromRequest' | 'getSessionHeaders'> {\n return (\n typeof (authConfig as any).getSessionIdFromRequest === 'function' &&\n typeof (authConfig as any).refreshSession === 'function' &&\n typeof (authConfig as any).getSessionHeaders === 'function'\n );\n}\n\n/**\n * Single auth middleware: authenticate → authorize.\n * Skip checks (dev playground, unprotected path, public path) are evaluated once.\n */\nexport const coreAuthMiddleware = async (ctx: AuthMiddlewareContext): Promise<AuthResult> => {\n const {\n path,\n method,\n getHeader,\n mastra,\n authConfig,\n customRouteAuthConfig,\n requestContext,\n rawRequest,\n token,\n requiresAuth,\n } = ctx;\n\n // ── Skip checks (evaluated once) ──\n\n // Only bypass auth for dev playground when no real auth provider is configured.\n // When auth IS configured (has authenticateToken), we need the full auth flow\n // so user/roles/permissions are set in requestContext.\n const hasAuthProvider = typeof authConfig.authenticateToken === 'function';\n if (!hasAuthProvider && isDevPlaygroundRequest(path, method, getHeader, authConfig, customRouteAuthConfig)) {\n return pass;\n }\n\n if (!isProtectedPath(path, method, authConfig, customRouteAuthConfig)) {\n return pass;\n }\n\n // When a route explicitly requires auth (requiresAuth: true), skip the\n // public-path bypass so the user is still authenticated and permissions\n // are injected into the request context.\n if (\n !requiresAuth &&\n (canAccessPublicly(path, method, authConfig) || isCustomRoutePublic(path, method, customRouteAuthConfig))\n ) {\n return pass;\n }\n\n // ── Authentication ──\n\n let user: unknown;\n let refreshHeaders: Record<string, string> | undefined;\n const authRequest = adaptToMastraAuthRequest(rawRequest);\n\n type ConsumePendingResponseHeadersFn = (request: typeof authRequest) => Record<string, string> | undefined;\n const mergePendingProviderHeaders = (request: typeof authRequest = authRequest) => {\n const consume = (authConfig as { consumePendingResponseHeaders?: ConsumePendingResponseHeadersFn })\n .consumePendingResponseHeaders;\n if (typeof consume !== 'function') return;\n let pending: Record<string, string> | undefined;\n try {\n pending = consume.call(authConfig, request);\n } catch {\n // Forwarding a rotated cookie is best-effort; never fail auth over it.\n return;\n }\n if (!pending) return;\n refreshHeaders = { ...(refreshHeaders ?? {}), ...pending };\n };\n\n try {\n if (typeof authConfig.authenticateToken === 'function') {\n user = await authConfig.authenticateToken(token ?? '', authRequest);\n mergePendingProviderHeaders();\n } else {\n throw new Error('No token verification method configured');\n }\n\n // If authentication failed, attempt transparent session refresh before returning 401.\n // This handles expired access tokens without requiring client-side refresh logic.\n if (!user && supportsSessionRefresh(authConfig) && rawRequest instanceof Request) {\n let retryHttpError: HTTPException | undefined;\n try {\n const sessionId = authConfig.getSessionIdFromRequest(rawRequest);\n if (sessionId) {\n const newSession = await authConfig.refreshSession(sessionId);\n if (newSession) {\n // Refresh succeeded — build updated session headers and re-authenticate.\n // We create a synthetic request with the new session cookie so\n // authenticateToken (which reads cookies from the request) picks up\n // the refreshed session instead of the expired one.\n refreshHeaders = authConfig.getSessionHeaders(newSession);\n const refreshedCookie = Object.entries(refreshHeaders)\n .filter(([k]) => k.toLowerCase() === 'set-cookie')\n .map(([, v]) => v.split(';')[0]) // Extract name=value before attributes\n .join('; ');\n if (refreshedCookie) {\n const refreshedRequest = new Request(rawRequest.url, {\n method: rawRequest.method,\n headers: new Headers(rawRequest.headers),\n });\n refreshedRequest.headers.set('Cookie', refreshedCookie);\n // Pass the refreshed cookie value as the token so authenticateToken\n // picks up the new session instead of the stale original.\n // Auth providers typically read cookies from the request object, but\n // some may also inspect the token parameter directly.\n const cookieValue = refreshedCookie.includes('=')\n ? refreshedCookie.split('=').slice(1).join('=')\n : refreshedCookie;\n try {\n const retryAuthRequest = adaptToMastraAuthRequest(refreshedRequest);\n user = await authConfig.authenticateToken(cookieValue, retryAuthRequest);\n mergePendingProviderHeaders(retryAuthRequest);\n } catch (retryErr) {\n retryHttpError = retryErr instanceof HTTPException ? retryErr : undefined;\n throw retryErr;\n }\n }\n if (!user) {\n refreshHeaders = undefined;\n }\n }\n }\n } catch (refreshErr) {\n refreshHeaders = undefined;\n // An explicit HTTP error from the retried authenticateToken goes to the outer handler.\n if (retryHttpError === refreshErr) throw refreshErr;\n mastra.getLogger()?.debug('Session refresh failed, falling back to 401', {\n error: refreshErr instanceof Error ? { message: refreshErr.message } : refreshErr,\n });\n }\n }\n\n if (!user) {\n return { action: 'error', status: 401, body: { error: 'Invalid or expired token' }, headers: refreshHeaders };\n }\n\n requestContext.set(MASTRA_USER_KEY, user);\n // Backward-compat: also write the legacy `'user'` key so existing\n // middleware and integrations that read `requestContext.get('user')`\n // (including built-in FGA route enforcement, memory handlers, and the\n // documented public surface) keep working. New code should prefer\n // `MASTRA_USER_KEY` to avoid collisions with caller-supplied keys.\n requestContext.set('user', user);\n\n // Store the raw auth token so downstream code (e.g., editor MCP client\n // resolution) can forward it when connecting to auth-protected MCP servers.\n // The token may arrive via Authorization header, apiKey query param, or\n // cookie (SimpleAuth sets `mastra-token`). Check all sources so the\n // forwarded value is available regardless of how the user authenticated.\n let effectiveToken = token;\n if (!effectiveToken && rawRequest instanceof Request) {\n const cookieHeader = rawRequest.headers.get('cookie');\n if (cookieHeader) {\n const match = cookieHeader.match(/mastra-token=([^;]+)/);\n if (match?.[1]) effectiveToken = match[1];\n }\n }\n if (effectiveToken) {\n requestContext.set(MASTRA_AUTH_TOKEN_KEY, effectiveToken);\n }\n\n if (typeof authConfig.mapUserToResourceId === 'function') {\n try {\n const resourceId = authConfig.mapUserToResourceId(user);\n // CompositeAuth validates the authenticating provider's mapper. It can\n // return undefined when that provider never configured a mapper.\n if (resourceId !== undefined || !(authConfig instanceof CompositeAuth)) {\n if (typeof resourceId !== 'string' || !resourceId.trim()) {\n throw new Error('mapUserToResourceId must return a non-empty string for the authenticated user');\n }\n requestContext.set(MASTRA_RESOURCE_ID_KEY, resourceId);\n }\n } catch (mapError) {\n mastra.getLogger()?.error('mapUserToResourceId failed', {\n error: mapError instanceof Error ? { message: mapError.message, stack: mapError.stack } : mapError,\n });\n return {\n action: 'error',\n status: 500,\n body: { error: 'Failed to map authenticated user to a resource ID' },\n headers: refreshHeaders,\n };\n }\n }\n\n try {\n // Determine which RBAC provider to use based on auth mode\n const authMode = requestContext.get(MASTRA_AUTH_MODE_KEY);\n const serverConfig = mastra.getServer();\n const studioConfig = mastra.getStudio?.();\n // Use studio RBAC if this is a studio request, otherwise use server RBAC\n const rbacProvider = (authMode === 'studio' ? (studioConfig?.rbac ?? serverConfig?.rbac) : serverConfig?.rbac) as\n | IRBACProvider<EEUser>\n | undefined;\n\n if (rbacProvider) {\n if (!user || typeof user !== 'object' || !('id' in user)) {\n mastra.getLogger()?.warn('RBAC: authenticated user missing required \"id\" field, skipping permission loading');\n } else {\n const permissions = await rbacProvider.getPermissions(user as EEUser);\n requestContext.set(MASTRA_USER_PERMISSIONS_KEY, permissions);\n // Backward-compat alias for callers reading the legacy key.\n requestContext.set('userPermissions', permissions);\n\n const roles = await rbacProvider.getRoles(user as EEUser);\n requestContext.set(MASTRA_USER_ROLES_KEY, roles);\n // Backward-compat alias for callers reading the legacy key.\n requestContext.set('userRoles', roles);\n }\n }\n } catch (rbacError) {\n mastra.getLogger()?.error('RBAC: failed to load user permissions/roles', {\n error: rbacError instanceof Error ? { message: rbacError.message, stack: rbacError.stack } : rbacError,\n });\n }\n } catch (err) {\n mastra.getLogger()?.error('Authentication error', {\n error: err instanceof Error ? { message: err.message, stack: err.stack } : err,\n });\n // Explicit HTTP errors from auth callbacks keep their status/message; anything else is redacted.\n // The HTTPException message is sent to the client, so callers must keep it safe (no internal details).\n if (err instanceof HTTPException && err.status >= 400 && err.status <= 599) {\n return { action: 'error', status: err.status, body: { error: err.message }, headers: refreshHeaders };\n }\n return { action: 'error', status: 401, body: { error: 'Invalid or expired token' }, headers: refreshHeaders };\n }\n\n // ── Authorization ──\n\n if ('authorizeUser' in authConfig && typeof authConfig.authorizeUser === 'function') {\n try {\n const isAuthorized = await authConfig.authorizeUser(user, authRequest);\n\n if (!isAuthorized) {\n return { action: 'error', status: 403, body: { error: 'Access denied' }, headers: refreshHeaders };\n }\n } catch (err) {\n mastra.getLogger()?.error('Authorization error in authorizeUser', {\n error: err instanceof Error ? { message: err.message, stack: err.stack } : err,\n });\n return { action: 'error', status: 500, body: { error: 'Authorization error' }, headers: refreshHeaders };\n }\n } else if ('authorize' in authConfig && typeof authConfig.authorize === 'function') {\n try {\n const authorizeCtx = ctx.buildAuthorizeContext();\n const isAuthorized = await authConfig.authorize(path, method, user, authorizeCtx as any);\n\n if (!isAuthorized) {\n return { action: 'error', status: 403, body: { error: 'Access denied' }, headers: refreshHeaders };\n }\n } catch (err) {\n mastra.getLogger()?.error('Authorization error in authorize', {\n error: err instanceof Error ? { message: err.message, stack: err.stack } : err,\n path,\n method,\n });\n return { action: 'error', status: 500, body: { error: 'Authorization error' }, headers: refreshHeaders };\n }\n } else if ('rules' in authConfig && authConfig.rules && authConfig.rules.length > 0) {\n const isAuthorized = await checkRules(authConfig.rules, path, method, user);\n\n if (!isAuthorized) {\n return { action: 'error', status: 403, body: { error: 'Access denied' }, headers: refreshHeaders };\n }\n } else {\n // No explicit authorization configured (authorizeUser, authorize, or rules)\n // Check if RBAC is configured - if not, allow authenticated users through\n // (auth-only mode = authenticated users get full access)\n const rbacProvider = mastra.getServer()?.rbac;\n if (rbacProvider) {\n if (defaultAuthConfig.rules && defaultAuthConfig.rules.length > 0) {\n const isAuthorized = await checkRules(defaultAuthConfig.rules, path, method, user);\n\n if (!isAuthorized) {\n return { action: 'error', status: 403, body: { error: 'Access denied' }, headers: refreshHeaders };\n }\n } else {\n return { action: 'error', status: 403, body: { error: 'Access denied' }, headers: refreshHeaders };\n }\n }\n }\n\n return refreshHeaders ? { action: 'next', headers: refreshHeaders } : pass;\n};\n\n// Check authorization rules\nexport const checkRules = async (\n rules: MastraAuthConfig['rules'],\n path: string,\n method: string,\n user: unknown,\n): Promise<boolean> => {\n // Go through rules in order (first match wins)\n for (const i in rules || []) {\n const rule = rules?.[i]!;\n // Check if rule applies to this path\n if (!pathMatchesRule(path, rule.path)) {\n continue;\n }\n\n // Check if rule applies to this method\n if (rule.methods && !matchesOrIncludes(rule.methods, method)) {\n continue;\n }\n\n // Rule matches, check conditions\n const condition = rule.condition;\n if (typeof condition === 'function') {\n const allowed = await Promise.resolve()\n .then(() => condition(user))\n .catch(() => false);\n\n if (allowed) {\n return true;\n }\n } else if (rule.allow) {\n return true;\n }\n }\n\n // No matching rules, deny by default\n return false;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"helpers-DvzrUzqY.cjs","names":["HTTPException","MASTRA_USER_KEY","MASTRA_AUTH_TOKEN_KEY","CompositeAuth","MASTRA_RESOURCE_ID_KEY","MASTRA_AUTH_MODE_KEY","MASTRA_USER_PERMISSIONS_KEY","MASTRA_USER_ROLES_KEY"],"sources":["../src/server/auth/defaults.ts","../src/server/auth/path-pattern.ts","../src/server/auth/helpers.ts"],"sourcesContent":["import type { MastraAuthConfig } from '@mastra/core/server';\n\n// Default configuration that can be extended by clients\nexport const defaultAuthConfig: MastraAuthConfig = {\n protected: ['/api/*'],\n public: ['/api', '/api/auth/*'],\n // Simple rule system\n rules: [\n // Admin users can do anything\n {\n condition: user => {\n if (typeof user === 'object' && user !== null) {\n if ('isAdmin' in user) {\n return !!user.isAdmin;\n }\n\n if ('role' in user) {\n return user.role === 'admin';\n }\n }\n return false;\n },\n allow: true,\n },\n ],\n};\n","/**\n * Path pattern matching utility\n * Inlined from regexparam v3.0.0 (MIT License)\n * https://github.com/lukeed/regexparam\n *\n * Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nexport interface ParsedPattern {\n keys: string[] | false;\n pattern: RegExp;\n}\n\n/**\n * Parse a route pattern into a RegExp\n * Supports:\n * - Named parameters: /users/:id\n * - Optional parameters: /users/:id?\n * - Wildcards: /files/*\n * - Mixed patterns: /api/:version/users/:id\n */\nexport function parse(input: string | RegExp, loose?: boolean): ParsedPattern {\n if (input instanceof RegExp) return { keys: false, pattern: input };\n\n let c: string;\n let o: number;\n let tmp: string | undefined;\n let ext: number;\n const keys: string[] = [];\n let pattern = '';\n const arr = input.split('/');\n\n arr[0] || arr.shift();\n\n while ((tmp = arr.shift())) {\n c = tmp[0]!;\n if (c === '*') {\n keys.push(c);\n pattern += tmp[1] === '?' ? '(?:/(.*))?' : '/(.*)';\n } else if (c === ':') {\n o = tmp.indexOf('?', 1);\n ext = tmp.indexOf('.', 1);\n keys.push(tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length));\n pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';\n if (!!~ext) pattern += (!!~o ? '?' : '') + '\\\\' + tmp.substring(ext);\n } else {\n pattern += '/' + tmp;\n }\n }\n\n return {\n keys: keys,\n pattern: new RegExp('^' + pattern + (loose ? '(?=$|/)' : '/?$'), 'i'),\n };\n}\n\n/**\n * Test if a path matches a pattern\n */\nexport function matchPath(path: string, pattern: string | RegExp): boolean {\n const { pattern: regex } = parse(pattern);\n return regex.test(path);\n}\n","import type { ISessionProvider } from '@mastra/core/auth';\nimport type { IRBACProvider, EEUser } from '@mastra/core/auth/ee';\nimport type { Mastra } from '@mastra/core/mastra';\nimport { CompositeAuth } from '@mastra/core/server';\nimport type { ApiRoute, IMastraAuthProvider, MastraAuthConfig, MastraAuthRequest } from '@mastra/core/server';\n\nimport {\n MASTRA_RESOURCE_ID_KEY,\n MASTRA_USER_KEY,\n MASTRA_USER_PERMISSIONS_KEY,\n MASTRA_USER_ROLES_KEY,\n MASTRA_AUTH_TOKEN_KEY,\n MASTRA_AUTH_MODE_KEY,\n} from '../constants';\nimport { HTTPException } from '../http-exception';\nimport { defaultAuthConfig } from './defaults';\nimport { parse } from './path-pattern';\n\n// Re-export request-context key constants so custom middleware can read namespaced\n// auth state without importing internal paths.\nexport { MASTRA_USER_KEY, MASTRA_USER_PERMISSIONS_KEY, MASTRA_USER_ROLES_KEY } from '../constants';\n\n/**\n * Check if a route is a registered custom route that requires authentication.\n * Returns true only if the route is explicitly registered with requiresAuth: true.\n * Returns false if the route is not in the config or has requiresAuth: false.\n */\nexport const isProtectedCustomRoute = (\n path: string,\n method: string,\n customRouteAuthConfig?: Map<string, boolean>,\n): boolean => {\n if (!customRouteAuthConfig) {\n return false;\n }\n\n // Check exact match first (fast path for static routes)\n const exactRouteKey = `${method}:${path}`;\n if (customRouteAuthConfig.has(exactRouteKey)) {\n return customRouteAuthConfig.get(exactRouteKey) === true;\n }\n\n // Check exact match for ALL method\n const allRouteKey = `ALL:${path}`;\n if (customRouteAuthConfig.has(allRouteKey)) {\n return customRouteAuthConfig.get(allRouteKey) === true;\n }\n\n // Check pattern matches for dynamic routes (e.g., '/users/:id')\n for (const [routeKey, requiresAuth] of customRouteAuthConfig.entries()) {\n const colonIndex = routeKey.indexOf(':');\n if (colonIndex === -1) {\n continue; // Skip malformed keys\n }\n\n const routeMethod = routeKey.substring(0, colonIndex);\n const routePattern = routeKey.substring(colonIndex + 1);\n\n // Check if method matches (exact match or ALL)\n if (routeMethod !== method && routeMethod !== 'ALL') {\n continue;\n }\n\n // Check if path matches the pattern\n if (pathMatchesPattern(path, routePattern)) {\n return requiresAuth === true;\n }\n }\n\n return false; // Not in config = not a protected custom route\n};\n\n/**\n * Find a matching custom API route for the given path and method.\n * Returns the matched route and any extracted path parameters.\n */\nexport const findMatchingCustomRoute = (\n path: string,\n method: string,\n apiRoutes?: ApiRoute[],\n): { route: ApiRoute; params: Record<string, string> } | undefined => {\n if (!apiRoutes) return undefined;\n\n for (const route of apiRoutes) {\n if (route.method !== method && route.method !== 'ALL') continue;\n\n const { keys, pattern: regex } = parse(route.path);\n const match = regex.exec(path);\n if (!match) continue;\n\n const params: Record<string, string> = {};\n if (keys && keys.length > 0) {\n for (let i = 0; i < keys.length; i++) {\n if (match[i + 1] !== undefined) {\n params[keys[i]!] = match[i + 1]!;\n }\n }\n }\n\n return { route, params };\n }\n\n return undefined;\n};\n\n/**\n * Check if request is from dev playground\n * @param getHeader - Function to get header value from request\n * @param customRouteAuthConfig - Map of custom route auth configurations\n */\nexport const isDevPlaygroundRequest = (\n path: string,\n method: string,\n getHeader: (name: string) => string | undefined,\n authConfig: MastraAuthConfig,\n customRouteAuthConfig?: Map<string, boolean>,\n): boolean => {\n const protectedAccess = [...(defaultAuthConfig.protected || []), ...(authConfig.protected || [])];\n return (\n process.env.MASTRA_DEV === 'true' &&\n // Allow if path doesn't match protected patterns AND is not a protected custom route\n ((!isAnyMatch(path, method, protectedAccess) && !isProtectedCustomRoute(path, method, customRouteAuthConfig)) ||\n // Or if has playground header\n getHeader('x-mastra-dev-playground') === 'true')\n );\n};\n\nexport const isCustomRoutePublic = (\n path: string,\n method: string,\n customRouteAuthConfig?: Map<string, boolean>,\n): boolean => {\n if (!customRouteAuthConfig) {\n return false;\n }\n\n // Check exact match first (fast path for static routes)\n const exactRouteKey = `${method}:${path}`;\n if (customRouteAuthConfig.has(exactRouteKey)) {\n return !customRouteAuthConfig.get(exactRouteKey); // True when route opts out of auth\n }\n\n // Check exact match for ALL method\n const allRouteKey = `ALL:${path}`;\n if (customRouteAuthConfig.has(allRouteKey)) {\n return !customRouteAuthConfig.get(allRouteKey);\n }\n\n // Check pattern matches for dynamic routes (e.g., '/users/:id').\n // Any matching pattern that requires auth wins over overlapping public patterns.\n let matchedPublic = false;\n for (const [routeKey, requiresAuth] of customRouteAuthConfig.entries()) {\n const colonIndex = routeKey.indexOf(':');\n if (colonIndex === -1) {\n continue; // Skip malformed keys\n }\n\n const routeMethod = routeKey.substring(0, colonIndex);\n const routePattern = routeKey.substring(colonIndex + 1);\n\n // Check if method matches (exact match or ALL)\n if (routeMethod !== method && routeMethod !== 'ALL') {\n continue;\n }\n\n if (pathMatchesPattern(path, routePattern)) {\n if (requiresAuth) {\n return false;\n }\n matchedPublic = true;\n }\n }\n\n return matchedPublic;\n};\n\n// NOTE: This uses isProtectedCustomRoute (default-allow for unknown paths) rather than\n// !isCustomRoutePublic (default-deny). This is intentional — all registered server and\n// custom routes are auth-checked via registerRoute/checkRouteAuth regardless of this\n// function. The '/api/*' protected pattern exists as a user-facing override mechanism.\n// The old default-deny logic incorrectly blocked non-API paths (e.g. '/', '/agents')\n// which prevented the studio login page from loading in production.\nexport const isProtectedPath = (\n path: string,\n method: string,\n authConfig: MastraAuthConfig,\n customRouteAuthConfig?: Map<string, boolean>,\n): boolean => {\n const protectedAccess = [...(defaultAuthConfig.protected || []), ...(authConfig.protected || [])];\n return isAnyMatch(path, method, protectedAccess) || isProtectedCustomRoute(path, method, customRouteAuthConfig);\n};\n\nexport const canAccessPublicly = (path: string, method: string, authConfig: MastraAuthConfig): boolean => {\n // Check if this path+method combination is publicly accessible\n const publicAccess = [...(defaultAuthConfig.public || []), ...(authConfig.public || [])];\n\n return isAnyMatch(path, method, publicAccess);\n};\n\nconst isAnyMatch = (\n path: string,\n method: string,\n patterns: MastraAuthConfig['protected'] | MastraAuthConfig['public'],\n): boolean => {\n if (!patterns) {\n return false;\n }\n\n for (const patternPathOrMethod of patterns) {\n if (patternPathOrMethod instanceof RegExp) {\n if (patternPathOrMethod.test(path)) {\n return true;\n }\n }\n\n if (typeof patternPathOrMethod === 'string' && pathMatchesPattern(path, patternPathOrMethod)) {\n return true;\n }\n\n if (Array.isArray(patternPathOrMethod) && patternPathOrMethod.length === 2) {\n const [pattern, methodOrMethods] = patternPathOrMethod;\n if (pathMatchesPattern(path, pattern) && matchesOrIncludes(methodOrMethods, method)) {\n return true;\n }\n }\n }\n\n return false;\n};\n\nexport const pathMatchesPattern = (path: string, pattern: string): boolean => {\n // Use regexparam for battle-tested path matching\n // Supports:\n // - Exact paths: '/api/users'\n // - Wildcards: '/api/agents/*' matches '/api/agents/123'\n // - Path parameters: '/users/:id' matches '/users/123'\n // - Optional parameters: '/users/:id?' matches '/users' and '/users/123'\n // - Mixed patterns: '/api/:version/users/:id/profile'\n const { pattern: regex } = parse(pattern);\n return regex.test(path);\n};\n\nexport const pathMatchesRule = (path: string, rulePath: string | RegExp | string[] | undefined): boolean => {\n if (!rulePath) return true; // No path specified means all paths\n\n if (typeof rulePath === 'string') {\n return pathMatchesPattern(path, rulePath);\n }\n\n if (rulePath instanceof RegExp) {\n return rulePath.test(path);\n }\n\n if (Array.isArray(rulePath)) {\n return rulePath.some(p => pathMatchesPattern(path, p));\n }\n\n return false;\n};\n\nexport const matchesOrIncludes = (values: string | string[], value: string): boolean => {\n if (typeof values === 'string') {\n return values === value;\n }\n\n if (Array.isArray(values)) {\n return values.includes(value);\n }\n\n return false;\n};\n\n// ── Core auth middleware ──\n// Framework-agnostic auth logic extracted from adapter middlewares.\n// Each adapter builds an AuthMiddlewareContext and delegates to coreAuthMiddleware.\n\nexport interface AuthMiddlewareContext {\n path: string;\n method: string;\n getHeader: (name: string) => string | undefined;\n mastra: Mastra;\n authConfig: MastraAuthConfig;\n customRouteAuthConfig?: Map<string, boolean>;\n requestContext: { get: (key: string) => unknown; set: (key: string, value: unknown) => void };\n rawRequest: MastraAuthRequest;\n token: string | null;\n buildAuthorizeContext: () => unknown;\n /** When true, force authentication even if the path matches a public pattern. */\n requiresAuth?: boolean;\n}\n\nexport type AuthResult =\n | { action: 'next'; headers?: Record<string, string> }\n | { action: 'error'; status: number; body: Record<string, unknown>; headers?: Record<string, string> };\n\nconst pass: AuthResult = { action: 'next' };\n\nconst adaptToMastraAuthRequest = (request: MastraAuthRequest): MastraAuthRequest => {\n if (!(request instanceof Request)) {\n return request;\n }\n\n return {\n raw: request,\n headers: request.headers,\n header: name => request.headers.get(name) ?? undefined,\n };\n};\n\nexport interface GetAuthenticatedUserOptions {\n mastra: Mastra;\n token: string;\n request: MastraAuthRequest;\n}\n\nexport const getAuthenticatedUser = async <TUser = unknown>({\n mastra,\n token,\n request,\n}: GetAuthenticatedUserOptions): Promise<TUser | null> => {\n const normalizedToken = token.replace(/^Bearer\\s+/i, '').trim();\n if (!normalizedToken) {\n return null;\n }\n\n const authConfig = mastra.getServer()?.auth;\n if (!authConfig || typeof authConfig.authenticateToken !== 'function') {\n return null;\n }\n\n return (await authConfig.authenticateToken(normalizedToken, request)) as TUser | null;\n};\n\n/**\n * Check if an auth config object supports transparent session refresh.\n * Returns true if the auth provider implements the necessary ISessionProvider methods.\n */\nexport function supportsSessionRefresh(\n authConfig: MastraAuthConfig | IMastraAuthProvider,\n): authConfig is (MastraAuthConfig | IMastraAuthProvider) &\n Pick<ISessionProvider, 'refreshSession' | 'getSessionIdFromRequest' | 'getSessionHeaders'> {\n return (\n typeof (authConfig as any).getSessionIdFromRequest === 'function' &&\n typeof (authConfig as any).refreshSession === 'function' &&\n typeof (authConfig as any).getSessionHeaders === 'function'\n );\n}\n\n/**\n * Single auth middleware: authenticate → authorize.\n * Skip checks (dev playground, unprotected path, public path) are evaluated once.\n */\nexport const coreAuthMiddleware = async (ctx: AuthMiddlewareContext): Promise<AuthResult> => {\n const {\n path,\n method,\n getHeader,\n mastra,\n authConfig,\n customRouteAuthConfig,\n requestContext,\n rawRequest,\n token,\n requiresAuth,\n } = ctx;\n\n // ── Skip checks (evaluated once) ──\n\n // Only bypass auth for dev playground when no real auth provider is configured.\n // When auth IS configured (has authenticateToken), we need the full auth flow\n // so user/roles/permissions are set in requestContext.\n const hasAuthProvider = typeof authConfig.authenticateToken === 'function';\n if (!hasAuthProvider && isDevPlaygroundRequest(path, method, getHeader, authConfig, customRouteAuthConfig)) {\n return pass;\n }\n\n if (!isProtectedPath(path, method, authConfig, customRouteAuthConfig)) {\n return pass;\n }\n\n // When a route explicitly requires auth (requiresAuth: true), skip the\n // public-path bypass so the user is still authenticated and permissions\n // are injected into the request context.\n if (\n !requiresAuth &&\n (canAccessPublicly(path, method, authConfig) || isCustomRoutePublic(path, method, customRouteAuthConfig))\n ) {\n return pass;\n }\n\n // ── Authentication ──\n\n let user: unknown;\n let refreshHeaders: Record<string, string> | undefined;\n const authRequest = adaptToMastraAuthRequest(rawRequest);\n\n type ConsumePendingResponseHeadersFn = (request: typeof authRequest) => Record<string, string> | undefined;\n const mergePendingProviderHeaders = (request: typeof authRequest = authRequest) => {\n const consume = (authConfig as { consumePendingResponseHeaders?: ConsumePendingResponseHeadersFn })\n .consumePendingResponseHeaders;\n if (typeof consume !== 'function') return;\n let pending: Record<string, string> | undefined;\n try {\n pending = consume.call(authConfig, request);\n } catch {\n // Forwarding a rotated cookie is best-effort; never fail auth over it.\n return;\n }\n if (!pending) return;\n refreshHeaders = { ...(refreshHeaders ?? {}), ...pending };\n };\n\n try {\n if (typeof authConfig.authenticateToken === 'function') {\n user = await authConfig.authenticateToken(token ?? '', authRequest);\n mergePendingProviderHeaders();\n } else {\n throw new Error('No token verification method configured');\n }\n\n // If authentication failed, attempt transparent session refresh before returning 401.\n // This handles expired access tokens without requiring client-side refresh logic.\n if (!user && supportsSessionRefresh(authConfig) && rawRequest instanceof Request) {\n let retryHttpError: HTTPException | undefined;\n try {\n const sessionId = authConfig.getSessionIdFromRequest(rawRequest);\n if (sessionId) {\n const newSession = await authConfig.refreshSession(sessionId);\n if (newSession) {\n // Refresh succeeded — build updated session headers and re-authenticate.\n // We create a synthetic request with the new session cookie so\n // authenticateToken (which reads cookies from the request) picks up\n // the refreshed session instead of the expired one.\n refreshHeaders = authConfig.getSessionHeaders(newSession);\n const refreshedCookie = Object.entries(refreshHeaders)\n .filter(([k]) => k.toLowerCase() === 'set-cookie')\n .map(([, v]) => v.split(';')[0]) // Extract name=value before attributes\n .join('; ');\n if (refreshedCookie) {\n const refreshedRequest = new Request(rawRequest.url, {\n method: rawRequest.method,\n headers: new Headers(rawRequest.headers),\n });\n refreshedRequest.headers.set('Cookie', refreshedCookie);\n // Pass the refreshed cookie value as the token so authenticateToken\n // picks up the new session instead of the stale original.\n // Auth providers typically read cookies from the request object, but\n // some may also inspect the token parameter directly.\n const cookieValue = refreshedCookie.includes('=')\n ? refreshedCookie.split('=').slice(1).join('=')\n : refreshedCookie;\n try {\n const retryAuthRequest = adaptToMastraAuthRequest(refreshedRequest);\n user = await authConfig.authenticateToken(cookieValue, retryAuthRequest);\n mergePendingProviderHeaders(retryAuthRequest);\n } catch (retryErr) {\n retryHttpError = retryErr instanceof HTTPException ? retryErr : undefined;\n throw retryErr;\n }\n }\n if (!user) {\n refreshHeaders = undefined;\n }\n }\n }\n } catch (refreshErr) {\n refreshHeaders = undefined;\n // An explicit HTTP error from the retried authenticateToken goes to the outer handler.\n if (retryHttpError === refreshErr) throw refreshErr;\n mastra.getLogger()?.debug('Session refresh failed, falling back to 401', {\n error: refreshErr instanceof Error ? { message: refreshErr.message } : refreshErr,\n });\n }\n }\n\n if (!user) {\n return { action: 'error', status: 401, body: { error: 'Invalid or expired token' }, headers: refreshHeaders };\n }\n\n requestContext.set(MASTRA_USER_KEY, user);\n // Backward-compat: also write the legacy `'user'` key so existing\n // middleware and integrations that read `requestContext.get('user')`\n // (including built-in FGA route enforcement, memory handlers, and the\n // documented public surface) keep working. New code should prefer\n // `MASTRA_USER_KEY` to avoid collisions with caller-supplied keys.\n requestContext.set('user', user);\n\n // Store the raw auth token so downstream code (e.g., editor MCP client\n // resolution) can forward it when connecting to auth-protected MCP servers.\n // The token may arrive via Authorization header, apiKey query param, or\n // cookie (SimpleAuth sets `mastra-token`). Check all sources so the\n // forwarded value is available regardless of how the user authenticated.\n let effectiveToken = token;\n if (!effectiveToken && rawRequest instanceof Request) {\n const cookieHeader = rawRequest.headers.get('cookie');\n if (cookieHeader) {\n const match = cookieHeader.match(/mastra-token=([^;]+)/);\n if (match?.[1]) effectiveToken = match[1];\n }\n }\n if (effectiveToken) {\n requestContext.set(MASTRA_AUTH_TOKEN_KEY, effectiveToken);\n }\n\n if (typeof authConfig.mapUserToResourceId === 'function') {\n try {\n const resourceId = authConfig.mapUserToResourceId(user);\n // CompositeAuth validates the authenticating provider's mapper. It can\n // return undefined when that provider never configured a mapper.\n if (resourceId !== undefined || !(authConfig instanceof CompositeAuth)) {\n if (typeof resourceId !== 'string' || !resourceId.trim()) {\n throw new Error('mapUserToResourceId must return a non-empty string for the authenticated user');\n }\n requestContext.set(MASTRA_RESOURCE_ID_KEY, resourceId);\n }\n } catch (mapError) {\n mastra.getLogger()?.error('mapUserToResourceId failed', {\n error: mapError instanceof Error ? { message: mapError.message, stack: mapError.stack } : mapError,\n });\n return {\n action: 'error',\n status: 500,\n body: { error: 'Failed to map authenticated user to a resource ID' },\n headers: refreshHeaders,\n };\n }\n }\n\n try {\n // Determine which RBAC provider to use based on auth mode\n const authMode = requestContext.get(MASTRA_AUTH_MODE_KEY);\n const serverConfig = mastra.getServer();\n const studioConfig = mastra.getStudio?.();\n // Use studio RBAC if this is a studio request, otherwise use server RBAC\n const rbacProvider = (authMode === 'studio' ? (studioConfig?.rbac ?? serverConfig?.rbac) : serverConfig?.rbac) as\n | IRBACProvider<EEUser>\n | undefined;\n\n if (rbacProvider) {\n if (!user || typeof user !== 'object' || !('id' in user)) {\n mastra.getLogger()?.warn('RBAC: authenticated user missing required \"id\" field, skipping permission loading');\n } else {\n const permissions = await rbacProvider.getPermissions(user as EEUser);\n requestContext.set(MASTRA_USER_PERMISSIONS_KEY, permissions);\n // Backward-compat alias for callers reading the legacy key.\n requestContext.set('userPermissions', permissions);\n\n const roles = await rbacProvider.getRoles(user as EEUser);\n requestContext.set(MASTRA_USER_ROLES_KEY, roles);\n // Backward-compat alias for callers reading the legacy key.\n requestContext.set('userRoles', roles);\n }\n }\n } catch (rbacError) {\n mastra.getLogger()?.error('RBAC: failed to load user permissions/roles', {\n error: rbacError instanceof Error ? { message: rbacError.message, stack: rbacError.stack } : rbacError,\n });\n }\n } catch (err) {\n mastra.getLogger()?.error('Authentication error', {\n error: err instanceof Error ? { message: err.message, stack: err.stack } : err,\n });\n // Explicit HTTP errors from auth callbacks keep their status/message; anything else is redacted.\n // The HTTPException message is sent to the client, so callers must keep it safe (no internal details).\n if (err instanceof HTTPException && err.status >= 400 && err.status <= 599) {\n return { action: 'error', status: err.status, body: { error: err.message }, headers: refreshHeaders };\n }\n return { action: 'error', status: 401, body: { error: 'Invalid or expired token' }, headers: refreshHeaders };\n }\n\n // ── Authorization ──\n\n if ('authorizeUser' in authConfig && typeof authConfig.authorizeUser === 'function') {\n try {\n const isAuthorized = await authConfig.authorizeUser(user, authRequest);\n\n if (!isAuthorized) {\n return { action: 'error', status: 403, body: { error: 'Access denied' }, headers: refreshHeaders };\n }\n } catch (err) {\n mastra.getLogger()?.error('Authorization error in authorizeUser', {\n error: err instanceof Error ? { message: err.message, stack: err.stack } : err,\n });\n return { action: 'error', status: 500, body: { error: 'Authorization error' }, headers: refreshHeaders };\n }\n } else if ('authorize' in authConfig && typeof authConfig.authorize === 'function') {\n try {\n const authorizeCtx = ctx.buildAuthorizeContext();\n const isAuthorized = await authConfig.authorize(path, method, user, authorizeCtx as any);\n\n if (!isAuthorized) {\n return { action: 'error', status: 403, body: { error: 'Access denied' }, headers: refreshHeaders };\n }\n } catch (err) {\n mastra.getLogger()?.error('Authorization error in authorize', {\n error: err instanceof Error ? { message: err.message, stack: err.stack } : err,\n path,\n method,\n });\n return { action: 'error', status: 500, body: { error: 'Authorization error' }, headers: refreshHeaders };\n }\n } else if ('rules' in authConfig && authConfig.rules && authConfig.rules.length > 0) {\n const isAuthorized = await checkRules(authConfig.rules, path, method, user);\n\n if (!isAuthorized) {\n return { action: 'error', status: 403, body: { error: 'Access denied' }, headers: refreshHeaders };\n }\n } else {\n // No explicit authorization configured (authorizeUser, authorize, or rules)\n // Check if RBAC is configured - if not, allow authenticated users through\n // (auth-only mode = authenticated users get full access)\n const rbacProvider =\n requestContext.get(MASTRA_AUTH_MODE_KEY) === 'studio'\n ? (mastra.getStudio?.()?.rbac ?? mastra.getServer()?.rbac)\n : mastra.getServer()?.rbac;\n if (rbacProvider) {\n if (defaultAuthConfig.rules && defaultAuthConfig.rules.length > 0) {\n const isAuthorized = await checkRules(defaultAuthConfig.rules, path, method, user);\n\n if (!isAuthorized) {\n return { action: 'error', status: 403, body: { error: 'Access denied' }, headers: refreshHeaders };\n }\n } else {\n return { action: 'error', status: 403, body: { error: 'Access denied' }, headers: refreshHeaders };\n }\n }\n }\n\n return refreshHeaders ? { action: 'next', headers: refreshHeaders } : pass;\n};\n\n// Check authorization rules\nexport const checkRules = async (\n rules: MastraAuthConfig['rules'],\n path: string,\n method: string,\n user: unknown,\n): Promise<boolean> => {\n // Go through rules in order (first match wins)\n for (const i in rules || []) {\n const rule = rules?.[i]!;\n // Check if rule applies to this path\n if (!pathMatchesRule(path, rule.path)) {\n continue;\n }\n\n // Check if rule applies to this method\n if (rule.methods && !matchesOrIncludes(rule.methods, method)) {\n continue;\n }\n\n // Rule matches, check conditions\n const condition = rule.condition;\n if (typeof condition === 'function') {\n const allowed = await Promise.resolve()\n .then(() => condition(user))\n .catch(() => false);\n\n if (allowed) {\n return true;\n }\n } else if (rule.allow) {\n return true;\n }\n }\n\n // No matching rules, deny by default\n return false;\n};\n"],"mappings":"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"}
@@ -382,7 +382,7 @@ const coreAuthMiddleware = async (ctx) => {
382
382
  body: { error: "Access denied" },
383
383
  headers: refreshHeaders
384
384
  };
385
- } else if (mastra.getServer()?.rbac) {
385
+ } else if (requestContext.get("mastra__authMode") === "studio" ? mastra.getStudio?.()?.rbac ?? mastra.getServer()?.rbac : mastra.getServer()?.rbac) {
386
386
  if (defaultAuthConfig.rules && defaultAuthConfig.rules.length > 0) {
387
387
  if (!await checkRules(defaultAuthConfig.rules, path, method, user)) return {
388
388
  action: "error",
@@ -417,4 +417,4 @@ const checkRules = async (rules, path, method, user) => {
417
417
  //#endregion
418
418
  export { getAuthenticatedUser as a, isProtectedCustomRoute as c, pathMatchesPattern as d, pathMatchesRule as f, findMatchingCustomRoute as i, isProtectedPath as l, defaultAuthConfig as m, checkRules as n, isCustomRoutePublic as o, supportsSessionRefresh as p, coreAuthMiddleware as r, isDevPlaygroundRequest as s, canAccessPublicly as t, matchesOrIncludes as u };
419
419
 
420
- //# sourceMappingURL=helpers-vrqddDd5.js.map
420
+ //# sourceMappingURL=helpers-gCkmhB9x.js.map