@mastra/nestjs 0.2.30-alpha.0 → 0.2.30-alpha.1

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.
@@ -1,5 +1,7 @@
1
1
  import type { Request, Response } from 'express';
2
2
  import type { MastraModuleOptions } from '../mastra.module.js';
3
+ import { AuthService } from '../services/auth.service.js';
4
+ import { CustomRouteService } from '../services/custom-route.service.js';
3
5
  import { RequestContextService } from '../services/request-context.service.js';
4
6
  import { RouteHandlerService } from '../services/route-handler.service.js';
5
7
  /**
@@ -13,11 +15,13 @@ export declare class MastraController {
13
15
  private readonly options;
14
16
  private readonly routeHandler;
15
17
  private readonly requestContext;
16
- constructor(options: MastraModuleOptions, routeHandler: RouteHandlerService, requestContext: RequestContextService);
18
+ private readonly customRoutes;
19
+ private readonly authService;
20
+ constructor(options: MastraModuleOptions, routeHandler: RouteHandlerService, requestContext: RequestContextService, customRoutes: CustomRouteService, authService: AuthService);
17
21
  /**
18
22
  * Catch-all handler that matches incoming requests to Mastra routes.
19
23
  */
20
- handleRequest(req: Request, _res: Response): Promise<unknown>;
24
+ handleRequest(req: Request, res: Response): Promise<unknown>;
21
25
  /**
22
26
  * Parse and normalize query parameters.
23
27
  *
@@ -1 +1 @@
1
- {"version":3,"file":"mastra.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/mastra.controller.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAKxE;;;;;;GAMG;AACH,qBAIa,gBAAgB;IAED,OAAO,CAAC,QAAQ,CAAC,OAAO;IACnB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC3B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAHhE,YAC2C,OAAO,EAAE,mBAAmB,EACvB,YAAY,EAAE,mBAAmB,EAC/B,cAAc,EAAE,qBAAqB,EACnF;IAEJ;;OAEG;IAEG,aAAa,CAAQ,GAAG,EAAE,OAAO,EAA8B,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAkCrG;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;OAEG;YACW,SAAS;CAsBxB"}
1
+ {"version":3,"file":"mastra.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/mastra.controller.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAKxE;;;;;;GAMG;AACH,qBAIa,gBAAgB;IAED,OAAO,CAAC,QAAQ,CAAC,OAAO;IACnB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC3B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW;IALnD,YAC2C,OAAO,EAAE,mBAAmB,EACvB,YAAY,EAAE,mBAAmB,EAC/B,cAAc,EAAE,qBAAqB,EACxC,YAAY,EAAE,kBAAkB,EACvC,WAAW,EAAE,WAAW,EAC5D;IAEJ;;OAEG;IAEG,aAAa,CAAQ,GAAG,EAAE,OAAO,EAA8B,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAmDpG;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;OAEG;YACW,SAAS;CAsBxB"}
@@ -7,15 +7,9 @@ import { AuthService } from '../services/auth.service.js';
7
7
  *
8
8
  * **IMPORTANT: This guard is for custom user routes, NOT for Mastra API routes.**
9
9
  *
10
- * Mastra routes (agents, workflows, etc.) use AuthService internally which has
11
- * access to route-specific auth configuration (customRouteAuthConfig, isProtectedPath,
12
- * canAccessPublicly). This guard is a simplified version for when you want to
13
- * protect your own NestJS routes with Mastra's auth config.
14
- *
15
- * Differences from AuthService (used internally for Mastra routes):
16
- * - Does NOT check `customRouteAuthConfig`
17
- * - Does NOT check `isProtectedPath` / `canAccessPublicly` from @mastra/server/auth
18
- * - Has simpler dev playground detection (just checks header + config)
10
+ * Mastra routes (agents, workflows, etc.) and `server.apiRoutes` are protected by
11
+ * MastraRouteGuard. Use this guard to protect your own NestJS routes with the
12
+ * same Mastra auth pipeline (`server.auth`).
19
13
  *
20
14
  * @example
21
15
  * ```typescript
@@ -1 +1 @@
1
- {"version":3,"file":"mastra-auth.guard.d.ts","sourceRoot":"","sources":["../../src/guards/mastra-auth.guard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAIzC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBACa,eAAgB,YAAW,WAAW;IAI5B,OAAO,CAAC,QAAQ,CAAC,SAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAJnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;IAE3D,YACsC,SAAS,EAAE,SAAS,EAClB,WAAW,EAAE,WAAW,EAC5D;IAEE,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAmB7D;CACF"}
1
+ {"version":3,"file":"mastra-auth.guard.d.ts","sourceRoot":"","sources":["../../src/guards/mastra-auth.guard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAIzC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBACa,eAAgB,YAAW,WAAW;IAI5B,OAAO,CAAC,QAAQ,CAAC,SAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAJnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;IAE3D,YACsC,SAAS,EAAE,SAAS,EAClB,WAAW,EAAE,WAAW,EAC5D;IAEE,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAqB7D;CACF"}
@@ -1,4 +1,3 @@
1
- import type { Mastra } from '@mastra/core/mastra';
2
1
  import type { CanActivate, ExecutionContext } from '@nestjs/common';
3
2
  import type { MastraModuleOptions } from '../mastra.module.js';
4
3
  import { AuthService } from '../services/auth.service.js';
@@ -11,13 +10,12 @@ import { MastraThrottleGuard } from './mastra-throttle.guard.js';
11
10
  * then enforces auth + rate limiting for matched Mastra routes.
12
11
  */
13
12
  export declare class MastraRouteGuard implements CanActivate {
14
- private readonly mastra;
15
13
  private readonly options;
16
14
  private readonly routeHandler;
17
15
  private readonly requestContext;
18
16
  private readonly authService;
19
17
  private readonly throttleGuard;
20
- constructor(mastra: Mastra, options: MastraModuleOptions, routeHandler: RouteHandlerService, requestContext: RequestContextService, authService: AuthService, throttleGuard: MastraThrottleGuard);
18
+ constructor(options: MastraModuleOptions, routeHandler: RouteHandlerService, requestContext: RequestContextService, authService: AuthService, throttleGuard: MastraThrottleGuard);
21
19
  canActivate(context: ExecutionContext): Promise<boolean>;
22
20
  }
23
21
  //# sourceMappingURL=mastra-route.guard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mastra-route.guard.d.ts","sourceRoot":"","sources":["../../src/guards/mastra-route.guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAIpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAExE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D;;;;GAIG;AACH,qBACa,gBAAiB,YAAW,WAAW;IAEhC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACf,OAAO,CAAC,QAAQ,CAAC,OAAO;IACnB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC3B,OAAO,CAAC,QAAQ,CAAC,cAAc;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAN7D,YACmC,MAAM,EAAE,MAAM,EACN,OAAO,EAAE,mBAAmB,EACvB,YAAY,EAAE,mBAAmB,EAC/B,cAAc,EAAE,qBAAqB,EAC/C,WAAW,EAAE,WAAW,EAChB,aAAa,EAAE,mBAAmB,EAC9E;IAEE,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CA+B7D;CACF"}
1
+ {"version":3,"file":"mastra-route.guard.d.ts","sourceRoot":"","sources":["../../src/guards/mastra-route.guard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAIpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAExE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D;;;;GAIG;AACH,qBACa,gBAAiB,YAAW,WAAW;IAExB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACnB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC3B,OAAO,CAAC,QAAQ,CAAC,cAAc;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAL7D,YAC2C,OAAO,EAAE,mBAAmB,EACvB,YAAY,EAAE,mBAAmB,EAC/B,cAAc,EAAE,qBAAqB,EAC/C,WAAW,EAAE,WAAW,EAChB,aAAa,EAAE,mBAAmB,EAC9E;IAEE,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CA6B7D;CACF"}
package/dist/index.cjs CHANGED
@@ -25,8 +25,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
  let _nestjs_common = require("@nestjs/common");
26
26
  let _mastra_server_server_adapter = require("@mastra/server/server-adapter");
27
27
  let _mastra_server_handlers_error = require("@mastra/server/handlers/error");
28
- let _mastra_server_auth = require("@mastra/server/auth");
29
28
  let _mastra_core_request_context = require("@mastra/core/request-context");
29
+ let _mastra_server_auth = require("@mastra/server/auth");
30
+ let stream = require("stream");
31
+ let hono = require("hono");
30
32
  let _nestjs_core = require("@nestjs/core");
31
33
  let crypto = require("crypto");
32
34
  let module$1 = require("module");
@@ -473,82 +475,224 @@ function toWebRequest(req) {
473
475
  });
474
476
  }
475
477
  //#endregion
476
- //#region src/services/auth.service.ts
477
- var _AuthService;
478
- let AuthService = _AuthService = class AuthService {
478
+ //#region src/services/custom-route.service.ts
479
+ const NOT_FOUND_HEADER = "x-mastra-custom-route-not-found";
480
+ let CustomRouteService = class CustomRouteService {
479
481
  mastra;
480
- options;
481
- logger = new _nestjs_common.Logger(_AuthService.name);
482
+ routes;
483
+ authConfig;
484
+ fetchPromise;
482
485
  constructor(mastra, options) {
483
486
  this.mastra = mastra;
484
- this.options = options;
487
+ this.routes = (mastra.getServer()?.apiRoutes ?? []).filter((route) => !("_mastraSchemaRoute" in route && route._mastraSchemaRoute === true));
488
+ this.authConfig = new Map(options.customRouteAuthConfig);
489
+ for (const route of this.routes) {
490
+ const key = `${route.method}:${route.path}`;
491
+ if (!this.authConfig.has(key)) this.authConfig.set(key, route.requiresAuth !== false);
492
+ }
493
+ }
494
+ /** Auth config for custom routes, keyed by `METHOD:path`. */
495
+ get customRouteAuthConfig() {
496
+ return this.authConfig;
485
497
  }
486
498
  /**
487
- * Check authentication for a request based on the matched route.
488
- * Returns the authenticated user if auth succeeds, undefined if no auth required.
489
- * Throws UnauthorizedException or ForbiddenException if auth fails.
499
+ * Runs a matched custom route and writes its response.
500
+ * Returns false if no custom route handled the request.
490
501
  *
491
- * Type assertions (`as any`) are used because `@mastra/server/auth` types
492
- * are Hono-centric. The runtime values work with Express requests.
502
+ * `authenticate` runs after Hono's router selects the route, so auth is enforced
503
+ * for exactly the routes Hono dispatches (including regex-constrained params).
493
504
  */
494
- async authenticate(request) {
495
- const authConfig = this.mastra.getServer()?.auth;
496
- const customRouteAuthConfig = this.options.customRouteAuthConfig;
497
- const method = request.method;
498
- const path = request.path;
499
- if (!authConfig) return;
500
- const helperAuthConfig = authConfig;
501
- const getHeader = (name) => {
502
- const value = request.headers[name.toLowerCase()];
503
- return Array.isArray(value) ? value[0] : value;
504
- };
505
- if ((0, _mastra_server_auth.isDevPlaygroundRequest)(path, method, getHeader, helperAuthConfig, customRouteAuthConfig)) return;
506
- if (!(0, _mastra_server_auth.isProtectedPath)(path, method, helperAuthConfig, customRouteAuthConfig)) return;
507
- if ((0, _mastra_server_auth.canAccessPublicly)(path, method, helperAuthConfig)) return;
508
- const token = this.extractToken(request);
509
- if (!token) throw new _nestjs_common.UnauthorizedException("Authentication required");
505
+ async handle(req, res, requestContext, authenticate) {
506
+ if (this.routes.length === 0) return false;
507
+ this.fetchPromise ??= this.build().catch((err) => {
508
+ this.fetchPromise = void 0;
509
+ throw err;
510
+ });
511
+ const fetch = await this.fetchPromise;
512
+ const env = {
513
+ requestContext,
514
+ authenticate
515
+ };
516
+ const response = await fetch(this.toFetchRequest(req), env);
517
+ if (env.authError !== void 0) throw env.authError;
518
+ if (response.headers.get(NOT_FOUND_HEADER) === "true") return false;
519
+ res.status(response.status);
520
+ response.headers.forEach((value, key) => {
521
+ if (key.toLowerCase() === "set-cookie") return;
522
+ res.setHeader(key, value);
523
+ });
524
+ for (const cookie of response.headers.getSetCookie()) res.append("set-cookie", cookie);
525
+ if (!response.body) {
526
+ res.end();
527
+ return true;
528
+ }
529
+ const reader = response.body.getReader();
530
+ const onClose = () => void reader.cancel().catch(() => {});
531
+ res.once("close", onClose);
510
532
  try {
511
- let user;
512
- if (typeof authConfig?.authenticateToken === "function") user = await authConfig.authenticateToken(token, toWebRequest(request));
513
- else throw new Error("No token verification method configured");
514
- if (!user) throw new _nestjs_common.UnauthorizedException("Invalid or expired token");
515
- request.user = user;
516
- await this.authorize(request, path, method, user, authConfig);
517
- return user;
518
- } catch (error) {
519
- if (error instanceof _nestjs_common.UnauthorizedException || error instanceof _nestjs_common.ForbiddenException) throw error;
520
- this.logger.error("Authentication error:", error instanceof Error ? error.message : "Unknown error");
521
- throw new _nestjs_common.UnauthorizedException("Authentication failed");
533
+ while (!res.destroyed) {
534
+ const { done, value } = await reader.read();
535
+ if (done) break;
536
+ if (!res.write(value)) await new Promise((resolve) => {
537
+ const resume = () => {
538
+ res.off("drain", resume);
539
+ res.off("close", resume);
540
+ resolve();
541
+ };
542
+ res.once("drain", resume);
543
+ res.once("close", resume);
544
+ });
545
+ }
546
+ } finally {
547
+ res.off("close", onClose);
548
+ res.end();
522
549
  }
550
+ return true;
551
+ }
552
+ async build() {
553
+ const mastra = this.mastra;
554
+ const app = new hono.Hono();
555
+ app.use("*", async (c, next) => {
556
+ c.set("mastra", mastra);
557
+ c.set("requestContext", c.env?.requestContext ?? new _mastra_core_request_context.RequestContext());
558
+ await next();
559
+ });
560
+ const serverOnError = mastra.getServer()?.onError;
561
+ app.onError((err, c) => {
562
+ if (serverOnError) return serverOnError(err, c);
563
+ mastra.getLogger()?.error(`Custom route handler failed: ${c.req.method} ${c.req.path}`, { error: err instanceof Error ? err.stack ?? err.message : String(err) });
564
+ return c.json({ error: "Internal Server Error" }, 500);
565
+ });
566
+ for (const route of this.routes) {
567
+ const handler = "handler" in route && route.handler ? route.handler : "createHandler" in route ? await route.createHandler({ mastra }) : void 0;
568
+ if (!handler) continue;
569
+ const middlewares = route.middleware ? Array.isArray(route.middleware) ? route.middleware : [route.middleware] : [];
570
+ const requiresAuth = this.authConfig.get(`${route.method}:${route.path}`) ?? route.requiresAuth !== false;
571
+ const authMiddleware = async (c, next) => {
572
+ try {
573
+ await c.env.authenticate(requiresAuth);
574
+ } catch (err) {
575
+ c.env.authError = err;
576
+ return c.body(null, 401);
577
+ }
578
+ await next();
579
+ };
580
+ const handlers = [
581
+ authMiddleware,
582
+ ...middlewares,
583
+ handler
584
+ ];
585
+ if (route.method === "ALL") app.all(route.path, handlers[0], ...handlers.slice(1));
586
+ else app.on(route.method, route.path, handlers[0], ...handlers.slice(1));
587
+ }
588
+ app.notFound(() => new Response(null, {
589
+ status: 404,
590
+ headers: { [NOT_FOUND_HEADER]: "true" }
591
+ }));
592
+ return (request, env) => Promise.resolve(app.fetch(request, env));
593
+ }
594
+ toFetchRequest(req) {
595
+ const url = `${req.protocol || "http"}://${req.get("host") || "localhost"}${req.originalUrl || req.url}`;
596
+ const headers = new Headers();
597
+ for (const [key, value] of Object.entries(req.headers)) if (typeof value === "string") headers.set(key, value);
598
+ else if (Array.isArray(value)) value.forEach((v) => headers.append(key, v));
599
+ const init = {
600
+ method: req.method,
601
+ headers
602
+ };
603
+ if (["GET", "HEAD"].includes(req.method)) return new globalThis.Request(url, init);
604
+ const body = req.body;
605
+ if (!(req._body === true) && req.readable && !req.readableEnded) {
606
+ init.body = stream.Readable.toWeb(req);
607
+ init.duplex = "half";
608
+ } else if (typeof body === "string" || body instanceof Uint8Array) init.body = body;
609
+ else if (typeof body === "object" && body !== null) {
610
+ const contentType = headers.get("content-type") ?? "";
611
+ if (contentType.includes("application/x-www-form-urlencoded")) init.body = new URLSearchParams(body).toString();
612
+ else {
613
+ init.body = JSON.stringify(body);
614
+ if (!contentType) headers.set("content-type", "application/json");
615
+ }
616
+ headers.delete("content-length");
617
+ }
618
+ return new globalThis.Request(url, init);
619
+ }
620
+ };
621
+ CustomRouteService = __decorate([
622
+ (0, _nestjs_common.Injectable)(),
623
+ __decorateParam(0, (0, _nestjs_common.Inject)(MASTRA)),
624
+ __decorateParam(1, (0, _nestjs_common.Inject)(MASTRA_OPTIONS)),
625
+ __decorateMetadata("design:paramtypes", [Object, Object])
626
+ ], CustomRouteService);
627
+ //#endregion
628
+ //#region src/services/auth.service.ts
629
+ let AuthService = class AuthService {
630
+ mastra;
631
+ options;
632
+ customRoutes;
633
+ constructor(mastra, options, customRoutes) {
634
+ this.mastra = mastra;
635
+ this.options = options;
636
+ this.customRoutes = customRoutes;
523
637
  }
524
638
  /**
525
- * Check authorization for an authenticated user.
526
- * `authConfig` is typed as `any` because `@mastra/server/auth` doesn't
527
- * export a standalone type for the auth config object.
639
+ * Whether Mastra auth should run: module options enable it, or the Mastra
640
+ * server has auth configured (unless module options explicitly disable it).
528
641
  */
529
- async authorize(request, path, method, user, authConfig) {
530
- if (typeof authConfig.authorizeUser === "function") {
531
- if (!await authConfig.authorizeUser(user, toWebRequest(request))) throw new _nestjs_common.ForbiddenException("Access denied");
532
- return;
533
- }
534
- if (typeof authConfig.authorize === "function") {
535
- const context = {
642
+ isEnabled() {
643
+ if (this.options.auth?.enabled === false) return false;
644
+ return Boolean(this.options.auth?.enabled || this.mastra.getServer()?.auth);
645
+ }
646
+ /**
647
+ * Check authentication for a request.
648
+ * Returns the authenticated user if auth succeeds, undefined if no auth required.
649
+ * Throws UnauthorizedException or ForbiddenException if auth fails.
650
+ */
651
+ async authenticate(request, options = {}) {
652
+ const authConfig = this.mastra.getServer()?.auth;
653
+ if (!authConfig) return;
654
+ const requestContext = options.requestContext ?? new _mastra_core_request_context.RequestContext();
655
+ const path = request.path;
656
+ const method = request.method;
657
+ let customRouteAuthConfig = this.customRoutes.customRouteAuthConfig;
658
+ if (options.customRoute && options.requiresAuth !== void 0) {
659
+ customRouteAuthConfig = new Map(customRouteAuthConfig);
660
+ customRouteAuthConfig.set(`${method.toUpperCase()}:${path}`, options.requiresAuth);
661
+ }
662
+ const webRequest = toWebRequest(request);
663
+ const result = await (0, _mastra_server_auth.coreAuthMiddleware)({
664
+ path,
665
+ method,
666
+ getHeader: (name) => {
667
+ const value = request.headers[name.toLowerCase()];
668
+ return Array.isArray(value) ? value[0] : value;
669
+ },
670
+ mastra: this.mastra,
671
+ authConfig,
672
+ customRouteAuthConfig,
673
+ requestContext,
674
+ rawRequest: webRequest,
675
+ token: this.extractToken(request) ?? null,
676
+ buildAuthorizeContext: () => ({
536
677
  get: (key) => {
537
678
  if (key === "mastra") return this.mastra;
538
- if (key === "customRouteAuthConfig") return this.options.customRouteAuthConfig;
679
+ if (key === "customRouteAuthConfig") return customRouteAuthConfig;
539
680
  },
540
- req: toWebRequest(request)
541
- };
542
- if (!await authConfig.authorize(path, method, user, context)) throw new _nestjs_common.ForbiddenException("Access denied");
543
- return;
544
- }
545
- if ("rules" in authConfig && authConfig.rules && authConfig.rules.length > 0) {
546
- if (!await (0, _mastra_server_auth.checkRules)(authConfig.rules, path, method, user)) throw new _nestjs_common.ForbiddenException("Access denied");
547
- return;
548
- }
549
- if (_mastra_server_auth.defaultAuthConfig.rules && _mastra_server_auth.defaultAuthConfig.rules.length > 0) {
550
- if (!await (0, _mastra_server_auth.checkRules)(_mastra_server_auth.defaultAuthConfig.rules, path, method, user)) throw new _nestjs_common.ForbiddenException("Access denied");
551
- }
681
+ req: webRequest
682
+ }),
683
+ requiresAuth: options.requiresAuth
684
+ });
685
+ if (result.headers && options.response) for (const [key, value] of Object.entries(result.headers)) if (key.toLowerCase() === "set-cookie") options.response.append(key, value);
686
+ else options.response.setHeader(key, value);
687
+ if (result.action === "error") {
688
+ const message = typeof result.body.error === "string" ? result.body.error : "Access denied";
689
+ if (result.status === 401) throw new _nestjs_common.UnauthorizedException(message);
690
+ if (result.status === 403) throw new _nestjs_common.ForbiddenException(message);
691
+ throw new _nestjs_common.HttpException(result.body, result.status);
692
+ }
693
+ const user = requestContext.get(_mastra_server_auth.MASTRA_USER_KEY);
694
+ if (user !== void 0) request.user = user;
695
+ return user;
552
696
  }
553
697
  /**
554
698
  * Extract authentication token from request.
@@ -567,11 +711,16 @@ let AuthService = _AuthService = class AuthService {
567
711
  }
568
712
  }
569
713
  };
570
- AuthService = _AuthService = __decorate([
714
+ AuthService = __decorate([
571
715
  (0, _nestjs_common.Injectable)(),
572
716
  __decorateParam(0, (0, _nestjs_common.Inject)(MASTRA)),
573
717
  __decorateParam(1, (0, _nestjs_common.Inject)(MASTRA_OPTIONS)),
574
- __decorateMetadata("design:paramtypes", [Object, Object])
718
+ __decorateParam(2, (0, _nestjs_common.Inject)(CustomRouteService)),
719
+ __decorateMetadata("design:paramtypes", [
720
+ Object,
721
+ Object,
722
+ typeof CustomRouteService === "undefined" ? Object : CustomRouteService
723
+ ])
575
724
  ], AuthService);
576
725
  //#endregion
577
726
  //#region src/services/request-context.service.ts
@@ -850,14 +999,12 @@ MastraThrottleGuard = _MastraThrottleGuard = __decorate([
850
999
  //#endregion
851
1000
  //#region src/guards/mastra-route.guard.ts
852
1001
  let MastraRouteGuard = class MastraRouteGuard {
853
- mastra;
854
1002
  options;
855
1003
  routeHandler;
856
1004
  requestContext;
857
1005
  authService;
858
1006
  throttleGuard;
859
- constructor(mastra, options, routeHandler, requestContext, authService, throttleGuard) {
860
- this.mastra = mastra;
1007
+ constructor(options, routeHandler, requestContext, authService, throttleGuard) {
861
1008
  this.options = options;
862
1009
  this.routeHandler = routeHandler;
863
1010
  this.requestContext = requestContext;
@@ -868,29 +1015,29 @@ let MastraRouteGuard = class MastraRouteGuard {
868
1015
  const request = context.switchToHttp().getRequest();
869
1016
  const method = request.method.toUpperCase();
870
1017
  const routePath = getMastraRoutePath(request.path, this.options.prefix);
871
- if (!routePath) return true;
872
- if (!this.routeHandler.matchRoute(method, routePath)) return true;
873
- if (this.options.auth?.enabled !== false && (this.options.auth?.enabled || this.mastra.getServer()?.auth)) {
874
- const user = await this.authService.authenticate(request);
1018
+ if (!(routePath ? this.routeHandler.matchRoute(method, routePath) : void 0)) return true;
1019
+ if (this.authService.isEnabled()) {
1020
+ const user = await this.authService.authenticate(request, {
1021
+ requestContext: this.requestContext.requestContext,
1022
+ response: context.switchToHttp().getResponse()
1023
+ });
875
1024
  if (user !== void 0) this.requestContext.setUser(user);
876
1025
  }
877
1026
  if (this.options.rateLimitOptions?.enabled !== false) {
878
- const { limit, windowMs } = this.throttleGuard.getRateLimitSettings(request, void 0, routePath);
879
- await this.throttleGuard.checkLimit(request, limit, windowMs, routePath);
1027
+ const { limit, windowMs } = this.throttleGuard.getRateLimitSettings(request, void 0, routePath ?? void 0);
1028
+ await this.throttleGuard.checkLimit(request, limit, windowMs, routePath ?? void 0);
880
1029
  }
881
1030
  return true;
882
1031
  }
883
1032
  };
884
1033
  MastraRouteGuard = __decorate([
885
1034
  (0, _nestjs_common.Injectable)({ scope: _nestjs_common.Scope.REQUEST }),
886
- __decorateParam(0, (0, _nestjs_common.Inject)(MASTRA)),
887
- __decorateParam(1, (0, _nestjs_common.Inject)(MASTRA_OPTIONS)),
888
- __decorateParam(2, (0, _nestjs_common.Inject)(RouteHandlerService)),
889
- __decorateParam(3, (0, _nestjs_common.Inject)(RequestContextService)),
890
- __decorateParam(4, (0, _nestjs_common.Inject)(AuthService)),
891
- __decorateParam(5, (0, _nestjs_common.Inject)(MastraThrottleGuard)),
1035
+ __decorateParam(0, (0, _nestjs_common.Inject)(MASTRA_OPTIONS)),
1036
+ __decorateParam(1, (0, _nestjs_common.Inject)(RouteHandlerService)),
1037
+ __decorateParam(2, (0, _nestjs_common.Inject)(RequestContextService)),
1038
+ __decorateParam(3, (0, _nestjs_common.Inject)(AuthService)),
1039
+ __decorateParam(4, (0, _nestjs_common.Inject)(MastraThrottleGuard)),
892
1040
  __decorateMetadata("design:paramtypes", [
893
- Object,
894
1041
  Object,
895
1042
  typeof RouteHandlerService === "undefined" ? Object : RouteHandlerService,
896
1043
  typeof RequestContextService === "undefined" ? Object : RequestContextService,
@@ -10853,18 +11000,36 @@ let MastraController = class MastraController {
10853
11000
  options;
10854
11001
  routeHandler;
10855
11002
  requestContext;
10856
- constructor(options, routeHandler, requestContext) {
11003
+ customRoutes;
11004
+ authService;
11005
+ constructor(options, routeHandler, requestContext, customRoutes, authService) {
10857
11006
  this.options = options;
10858
11007
  this.routeHandler = routeHandler;
10859
11008
  this.requestContext = requestContext;
11009
+ this.customRoutes = customRoutes;
11010
+ this.authService = authService;
10860
11011
  }
10861
11012
  /**
10862
11013
  * Catch-all handler that matches incoming requests to Mastra routes.
10863
11014
  */
10864
- async handleRequest(req, _res) {
11015
+ async handleRequest(req, res) {
10865
11016
  const path = req.path;
10866
11017
  const method = req.method.toUpperCase();
10867
11018
  const routePath = getMastraRoutePath(path, this.options.prefix);
11019
+ if (!routePath || !this.routeHandler.matchRoute(method, routePath)) {
11020
+ const requestContext = this.requestContext.requestContext;
11021
+ const authenticate = async (requiresAuth) => {
11022
+ if (!this.authService.isEnabled()) return;
11023
+ const user = await this.authService.authenticate(req, {
11024
+ requestContext,
11025
+ response: res,
11026
+ requiresAuth,
11027
+ customRoute: true
11028
+ });
11029
+ if (user !== void 0) this.requestContext.setUser(user);
11030
+ };
11031
+ if (await this.customRoutes.handle(req, res, requestContext, authenticate)) return;
11032
+ }
10868
11033
  if (!routePath) throw new _nestjs_common.NotFoundException(`Route not found: ${method} ${path}`);
10869
11034
  if (routePath.includes("//")) throw new _nestjs_common.NotFoundException(`Route not found: ${method} ${path}`);
10870
11035
  const matchResult = this.routeHandler.matchRoute(method, routePath);
@@ -10943,10 +11108,14 @@ MastraController = __decorate([
10943
11108
  __decorateParam(0, (0, _nestjs_common.Inject)(MASTRA_OPTIONS)),
10944
11109
  __decorateParam(1, (0, _nestjs_common.Inject)(RouteHandlerService)),
10945
11110
  __decorateParam(2, (0, _nestjs_common.Inject)(RequestContextService)),
11111
+ __decorateParam(3, (0, _nestjs_common.Inject)(CustomRouteService)),
11112
+ __decorateParam(4, (0, _nestjs_common.Inject)(AuthService)),
10946
11113
  __decorateMetadata("design:paramtypes", [
10947
11114
  Object,
10948
11115
  typeof RouteHandlerService === "undefined" ? Object : RouteHandlerService,
10949
- typeof RequestContextService === "undefined" ? Object : RequestContextService
11116
+ typeof RequestContextService === "undefined" ? Object : RequestContextService,
11117
+ typeof CustomRouteService === "undefined" ? Object : CustomRouteService,
11118
+ typeof AuthService === "undefined" ? Object : AuthService
10950
11119
  ])
10951
11120
  ], MastraController);
10952
11121
  //#endregion
@@ -11107,7 +11276,7 @@ let MastraAuthGuard = _MastraAuthGuard = class MastraAuthGuard {
11107
11276
  if (this.reflector.getAllAndOverride("isPublic", [context.getHandler(), context.getClass()])) return true;
11108
11277
  const request = context.switchToHttp().getRequest();
11109
11278
  try {
11110
- await this.authService.authenticate(request);
11279
+ await this.authService.authenticate(request, { response: context.switchToHttp().getResponse() });
11111
11280
  return true;
11112
11281
  } catch (error) {
11113
11282
  this.logger.error(`Authentication error: ${error instanceof Error ? error.message : String(error)}`);
@@ -11321,6 +11490,7 @@ let MastraModule = _MastraModule = class MastraModule {
11321
11490
  RequestContextService,
11322
11491
  ShutdownService,
11323
11492
  AuthService,
11493
+ CustomRouteService,
11324
11494
  BodyLimitMiddleware,
11325
11495
  JsonBodyMiddleware,
11326
11496
  MastraAuthGuard,
@@ -11395,6 +11565,7 @@ let MastraModule = _MastraModule = class MastraModule {
11395
11565
  RequestContextService,
11396
11566
  ShutdownService,
11397
11567
  AuthService,
11568
+ CustomRouteService,
11398
11569
  BodyLimitMiddleware,
11399
11570
  JsonBodyMiddleware,
11400
11571
  MastraAuthGuard,
@@ -11433,6 +11604,12 @@ Object.defineProperty(exports, "BodyLimitMiddleware", {
11433
11604
  return BodyLimitMiddleware;
11434
11605
  }
11435
11606
  });
11607
+ Object.defineProperty(exports, "CustomRouteService", {
11608
+ enumerable: true,
11609
+ get: function() {
11610
+ return CustomRouteService;
11611
+ }
11612
+ });
11436
11613
  Object.defineProperty(exports, "JsonBodyMiddleware", {
11437
11614
  enumerable: true,
11438
11615
  get: function() {