@mastra/nestjs 0.2.29 → 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.
package/dist/index.d.ts CHANGED
@@ -15,6 +15,8 @@ export type { RouteHandlerParams, RouteHandlerResult, RouteMatch } from './servi
15
15
  export { RequestContextService } from './services/request-context.service.js';
16
16
  export { ShutdownService } from './services/shutdown.service.js';
17
17
  export { AuthService } from './services/auth.service.js';
18
+ export type { AuthenticateOptions } from './services/auth.service.js';
19
+ export { CustomRouteService } from './services/custom-route.service.js';
18
20
  export { BodyLimitMiddleware } from './middleware/body-limit.middleware.js';
19
21
  export { JsonBodyMiddleware } from './middleware/json-body.middleware.js';
20
22
  export { parseMultipartFormData } from './utils/parse-multipart.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,YAAY,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAGjH,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGrD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAGrG,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAGrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAG1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,0BAA0B,EAAE,MAAM,6CAA6C,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAGxE,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxF,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC3G,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAGvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,YAAY,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAGjH,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGrD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAGrG,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAGrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAG1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,0BAA0B,EAAE,MAAM,6CAA6C,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAGxE,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxF,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC3G,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAGrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAGvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC"}
package/dist/index.js CHANGED
@@ -2,8 +2,10 @@ import { createRequire } from "module";
2
2
  import { All, BadRequestException, Catch, Controller, ForbiddenException, Get, HttpException, HttpStatus, Inject, Injectable, Logger, Module, NotFoundException, PayloadTooLargeException, Req, Res, Scope, ServiceUnavailableException, SetMetadata, UnauthorizedException, UseFilters, UseGuards, UseInterceptors } from "@nestjs/common";
3
3
  import { HTTPException, MASTRA_CLIENT_TYPE_HEADER, MASTRA_IS_STUDIO_KEY, SERVER_ROUTES, getCustomHTTPExceptionResponse, isReservedRequestContextKey, isStudioClientTypeHeader, isZodError, normalizeQueryParams, redactStreamChunk, serializeStreamChunk } from "@mastra/server/server-adapter";
4
4
  import { formatZodError, isZodError as isZodError$1 } from "@mastra/server/handlers/error";
5
- import { canAccessPublicly, checkRules, defaultAuthConfig, isDevPlaygroundRequest, isProtectedPath } from "@mastra/server/auth";
6
5
  import { RequestContext } from "@mastra/core/request-context";
6
+ import { MASTRA_USER_KEY, coreAuthMiddleware } from "@mastra/server/auth";
7
+ import { Readable } from "stream";
8
+ import { Hono } from "hono";
7
9
  import { HttpAdapterHost, REQUEST, Reflector } from "@nestjs/core";
8
10
  import { randomUUID } from "crypto";
9
11
  import { Busboy } from "@fastify/busboy";
@@ -451,82 +453,224 @@ function toWebRequest(req) {
451
453
  });
452
454
  }
453
455
  //#endregion
454
- //#region src/services/auth.service.ts
455
- var _AuthService;
456
- let AuthService = _AuthService = class AuthService {
456
+ //#region src/services/custom-route.service.ts
457
+ const NOT_FOUND_HEADER = "x-mastra-custom-route-not-found";
458
+ let CustomRouteService = class CustomRouteService {
457
459
  mastra;
458
- options;
459
- logger = new Logger(_AuthService.name);
460
+ routes;
461
+ authConfig;
462
+ fetchPromise;
460
463
  constructor(mastra, options) {
461
464
  this.mastra = mastra;
462
- this.options = options;
465
+ this.routes = (mastra.getServer()?.apiRoutes ?? []).filter((route) => !("_mastraSchemaRoute" in route && route._mastraSchemaRoute === true));
466
+ this.authConfig = new Map(options.customRouteAuthConfig);
467
+ for (const route of this.routes) {
468
+ const key = `${route.method}:${route.path}`;
469
+ if (!this.authConfig.has(key)) this.authConfig.set(key, route.requiresAuth !== false);
470
+ }
471
+ }
472
+ /** Auth config for custom routes, keyed by `METHOD:path`. */
473
+ get customRouteAuthConfig() {
474
+ return this.authConfig;
463
475
  }
464
476
  /**
465
- * Check authentication for a request based on the matched route.
466
- * Returns the authenticated user if auth succeeds, undefined if no auth required.
467
- * Throws UnauthorizedException or ForbiddenException if auth fails.
477
+ * Runs a matched custom route and writes its response.
478
+ * Returns false if no custom route handled the request.
468
479
  *
469
- * Type assertions (`as any`) are used because `@mastra/server/auth` types
470
- * are Hono-centric. The runtime values work with Express requests.
480
+ * `authenticate` runs after Hono's router selects the route, so auth is enforced
481
+ * for exactly the routes Hono dispatches (including regex-constrained params).
471
482
  */
472
- async authenticate(request) {
473
- const authConfig = this.mastra.getServer()?.auth;
474
- const customRouteAuthConfig = this.options.customRouteAuthConfig;
475
- const method = request.method;
476
- const path = request.path;
477
- if (!authConfig) return;
478
- const helperAuthConfig = authConfig;
479
- const getHeader = (name) => {
480
- const value = request.headers[name.toLowerCase()];
481
- return Array.isArray(value) ? value[0] : value;
482
- };
483
- if (isDevPlaygroundRequest(path, method, getHeader, helperAuthConfig, customRouteAuthConfig)) return;
484
- if (!isProtectedPath(path, method, helperAuthConfig, customRouteAuthConfig)) return;
485
- if (canAccessPublicly(path, method, helperAuthConfig)) return;
486
- const token = this.extractToken(request);
487
- if (!token) throw new UnauthorizedException("Authentication required");
483
+ async handle(req, res, requestContext, authenticate) {
484
+ if (this.routes.length === 0) return false;
485
+ this.fetchPromise ??= this.build().catch((err) => {
486
+ this.fetchPromise = void 0;
487
+ throw err;
488
+ });
489
+ const fetch = await this.fetchPromise;
490
+ const env = {
491
+ requestContext,
492
+ authenticate
493
+ };
494
+ const response = await fetch(this.toFetchRequest(req), env);
495
+ if (env.authError !== void 0) throw env.authError;
496
+ if (response.headers.get(NOT_FOUND_HEADER) === "true") return false;
497
+ res.status(response.status);
498
+ response.headers.forEach((value, key) => {
499
+ if (key.toLowerCase() === "set-cookie") return;
500
+ res.setHeader(key, value);
501
+ });
502
+ for (const cookie of response.headers.getSetCookie()) res.append("set-cookie", cookie);
503
+ if (!response.body) {
504
+ res.end();
505
+ return true;
506
+ }
507
+ const reader = response.body.getReader();
508
+ const onClose = () => void reader.cancel().catch(() => {});
509
+ res.once("close", onClose);
488
510
  try {
489
- let user;
490
- if (typeof authConfig?.authenticateToken === "function") user = await authConfig.authenticateToken(token, toWebRequest(request));
491
- else throw new Error("No token verification method configured");
492
- if (!user) throw new UnauthorizedException("Invalid or expired token");
493
- request.user = user;
494
- await this.authorize(request, path, method, user, authConfig);
495
- return user;
496
- } catch (error) {
497
- if (error instanceof UnauthorizedException || error instanceof ForbiddenException) throw error;
498
- this.logger.error("Authentication error:", error instanceof Error ? error.message : "Unknown error");
499
- throw new UnauthorizedException("Authentication failed");
511
+ while (!res.destroyed) {
512
+ const { done, value } = await reader.read();
513
+ if (done) break;
514
+ if (!res.write(value)) await new Promise((resolve) => {
515
+ const resume = () => {
516
+ res.off("drain", resume);
517
+ res.off("close", resume);
518
+ resolve();
519
+ };
520
+ res.once("drain", resume);
521
+ res.once("close", resume);
522
+ });
523
+ }
524
+ } finally {
525
+ res.off("close", onClose);
526
+ res.end();
527
+ }
528
+ return true;
529
+ }
530
+ async build() {
531
+ const mastra = this.mastra;
532
+ const app = new Hono();
533
+ app.use("*", async (c, next) => {
534
+ c.set("mastra", mastra);
535
+ c.set("requestContext", c.env?.requestContext ?? new RequestContext());
536
+ await next();
537
+ });
538
+ const serverOnError = mastra.getServer()?.onError;
539
+ app.onError((err, c) => {
540
+ if (serverOnError) return serverOnError(err, c);
541
+ mastra.getLogger()?.error(`Custom route handler failed: ${c.req.method} ${c.req.path}`, { error: err instanceof Error ? err.stack ?? err.message : String(err) });
542
+ return c.json({ error: "Internal Server Error" }, 500);
543
+ });
544
+ for (const route of this.routes) {
545
+ const handler = "handler" in route && route.handler ? route.handler : "createHandler" in route ? await route.createHandler({ mastra }) : void 0;
546
+ if (!handler) continue;
547
+ const middlewares = route.middleware ? Array.isArray(route.middleware) ? route.middleware : [route.middleware] : [];
548
+ const requiresAuth = this.authConfig.get(`${route.method}:${route.path}`) ?? route.requiresAuth !== false;
549
+ const authMiddleware = async (c, next) => {
550
+ try {
551
+ await c.env.authenticate(requiresAuth);
552
+ } catch (err) {
553
+ c.env.authError = err;
554
+ return c.body(null, 401);
555
+ }
556
+ await next();
557
+ };
558
+ const handlers = [
559
+ authMiddleware,
560
+ ...middlewares,
561
+ handler
562
+ ];
563
+ if (route.method === "ALL") app.all(route.path, handlers[0], ...handlers.slice(1));
564
+ else app.on(route.method, route.path, handlers[0], ...handlers.slice(1));
565
+ }
566
+ app.notFound(() => new Response(null, {
567
+ status: 404,
568
+ headers: { [NOT_FOUND_HEADER]: "true" }
569
+ }));
570
+ return (request, env) => Promise.resolve(app.fetch(request, env));
571
+ }
572
+ toFetchRequest(req) {
573
+ const url = `${req.protocol || "http"}://${req.get("host") || "localhost"}${req.originalUrl || req.url}`;
574
+ const headers = new Headers();
575
+ for (const [key, value] of Object.entries(req.headers)) if (typeof value === "string") headers.set(key, value);
576
+ else if (Array.isArray(value)) value.forEach((v) => headers.append(key, v));
577
+ const init = {
578
+ method: req.method,
579
+ headers
580
+ };
581
+ if (["GET", "HEAD"].includes(req.method)) return new globalThis.Request(url, init);
582
+ const body = req.body;
583
+ if (!(req._body === true) && req.readable && !req.readableEnded) {
584
+ init.body = Readable.toWeb(req);
585
+ init.duplex = "half";
586
+ } else if (typeof body === "string" || body instanceof Uint8Array) init.body = body;
587
+ else if (typeof body === "object" && body !== null) {
588
+ const contentType = headers.get("content-type") ?? "";
589
+ if (contentType.includes("application/x-www-form-urlencoded")) init.body = new URLSearchParams(body).toString();
590
+ else {
591
+ init.body = JSON.stringify(body);
592
+ if (!contentType) headers.set("content-type", "application/json");
593
+ }
594
+ headers.delete("content-length");
500
595
  }
596
+ return new globalThis.Request(url, init);
597
+ }
598
+ };
599
+ CustomRouteService = __decorate([
600
+ Injectable(),
601
+ __decorateParam(0, Inject(MASTRA)),
602
+ __decorateParam(1, Inject(MASTRA_OPTIONS)),
603
+ __decorateMetadata("design:paramtypes", [Object, Object])
604
+ ], CustomRouteService);
605
+ //#endregion
606
+ //#region src/services/auth.service.ts
607
+ let AuthService = class AuthService {
608
+ mastra;
609
+ options;
610
+ customRoutes;
611
+ constructor(mastra, options, customRoutes) {
612
+ this.mastra = mastra;
613
+ this.options = options;
614
+ this.customRoutes = customRoutes;
501
615
  }
502
616
  /**
503
- * Check authorization for an authenticated user.
504
- * `authConfig` is typed as `any` because `@mastra/server/auth` doesn't
505
- * export a standalone type for the auth config object.
617
+ * Whether Mastra auth should run: module options enable it, or the Mastra
618
+ * server has auth configured (unless module options explicitly disable it).
506
619
  */
507
- async authorize(request, path, method, user, authConfig) {
508
- if (typeof authConfig.authorizeUser === "function") {
509
- if (!await authConfig.authorizeUser(user, toWebRequest(request))) throw new ForbiddenException("Access denied");
510
- return;
511
- }
512
- if (typeof authConfig.authorize === "function") {
513
- const context = {
620
+ isEnabled() {
621
+ if (this.options.auth?.enabled === false) return false;
622
+ return Boolean(this.options.auth?.enabled || this.mastra.getServer()?.auth);
623
+ }
624
+ /**
625
+ * Check authentication for a request.
626
+ * Returns the authenticated user if auth succeeds, undefined if no auth required.
627
+ * Throws UnauthorizedException or ForbiddenException if auth fails.
628
+ */
629
+ async authenticate(request, options = {}) {
630
+ const authConfig = this.mastra.getServer()?.auth;
631
+ if (!authConfig) return;
632
+ const requestContext = options.requestContext ?? new RequestContext();
633
+ const path = request.path;
634
+ const method = request.method;
635
+ let customRouteAuthConfig = this.customRoutes.customRouteAuthConfig;
636
+ if (options.customRoute && options.requiresAuth !== void 0) {
637
+ customRouteAuthConfig = new Map(customRouteAuthConfig);
638
+ customRouteAuthConfig.set(`${method.toUpperCase()}:${path}`, options.requiresAuth);
639
+ }
640
+ const webRequest = toWebRequest(request);
641
+ const result = await coreAuthMiddleware({
642
+ path,
643
+ method,
644
+ getHeader: (name) => {
645
+ const value = request.headers[name.toLowerCase()];
646
+ return Array.isArray(value) ? value[0] : value;
647
+ },
648
+ mastra: this.mastra,
649
+ authConfig,
650
+ customRouteAuthConfig,
651
+ requestContext,
652
+ rawRequest: webRequest,
653
+ token: this.extractToken(request) ?? null,
654
+ buildAuthorizeContext: () => ({
514
655
  get: (key) => {
515
656
  if (key === "mastra") return this.mastra;
516
- if (key === "customRouteAuthConfig") return this.options.customRouteAuthConfig;
657
+ if (key === "customRouteAuthConfig") return customRouteAuthConfig;
517
658
  },
518
- req: toWebRequest(request)
519
- };
520
- if (!await authConfig.authorize(path, method, user, context)) throw new ForbiddenException("Access denied");
521
- return;
522
- }
523
- if ("rules" in authConfig && authConfig.rules && authConfig.rules.length > 0) {
524
- if (!await checkRules(authConfig.rules, path, method, user)) throw new ForbiddenException("Access denied");
525
- return;
526
- }
527
- if (defaultAuthConfig.rules && defaultAuthConfig.rules.length > 0) {
528
- if (!await checkRules(defaultAuthConfig.rules, path, method, user)) throw new ForbiddenException("Access denied");
529
- }
659
+ req: webRequest
660
+ }),
661
+ requiresAuth: options.requiresAuth
662
+ });
663
+ if (result.headers && options.response) for (const [key, value] of Object.entries(result.headers)) if (key.toLowerCase() === "set-cookie") options.response.append(key, value);
664
+ else options.response.setHeader(key, value);
665
+ if (result.action === "error") {
666
+ const message = typeof result.body.error === "string" ? result.body.error : "Access denied";
667
+ if (result.status === 401) throw new UnauthorizedException(message);
668
+ if (result.status === 403) throw new ForbiddenException(message);
669
+ throw new HttpException(result.body, result.status);
670
+ }
671
+ const user = requestContext.get(MASTRA_USER_KEY);
672
+ if (user !== void 0) request.user = user;
673
+ return user;
530
674
  }
531
675
  /**
532
676
  * Extract authentication token from request.
@@ -545,11 +689,16 @@ let AuthService = _AuthService = class AuthService {
545
689
  }
546
690
  }
547
691
  };
548
- AuthService = _AuthService = __decorate([
692
+ AuthService = __decorate([
549
693
  Injectable(),
550
694
  __decorateParam(0, Inject(MASTRA)),
551
695
  __decorateParam(1, Inject(MASTRA_OPTIONS)),
552
- __decorateMetadata("design:paramtypes", [Object, Object])
696
+ __decorateParam(2, Inject(CustomRouteService)),
697
+ __decorateMetadata("design:paramtypes", [
698
+ Object,
699
+ Object,
700
+ typeof CustomRouteService === "undefined" ? Object : CustomRouteService
701
+ ])
553
702
  ], AuthService);
554
703
  //#endregion
555
704
  //#region src/services/request-context.service.ts
@@ -828,14 +977,12 @@ MastraThrottleGuard = _MastraThrottleGuard = __decorate([
828
977
  //#endregion
829
978
  //#region src/guards/mastra-route.guard.ts
830
979
  let MastraRouteGuard = class MastraRouteGuard {
831
- mastra;
832
980
  options;
833
981
  routeHandler;
834
982
  requestContext;
835
983
  authService;
836
984
  throttleGuard;
837
- constructor(mastra, options, routeHandler, requestContext, authService, throttleGuard) {
838
- this.mastra = mastra;
985
+ constructor(options, routeHandler, requestContext, authService, throttleGuard) {
839
986
  this.options = options;
840
987
  this.routeHandler = routeHandler;
841
988
  this.requestContext = requestContext;
@@ -846,29 +993,29 @@ let MastraRouteGuard = class MastraRouteGuard {
846
993
  const request = context.switchToHttp().getRequest();
847
994
  const method = request.method.toUpperCase();
848
995
  const routePath = getMastraRoutePath(request.path, this.options.prefix);
849
- if (!routePath) return true;
850
- if (!this.routeHandler.matchRoute(method, routePath)) return true;
851
- if (this.options.auth?.enabled !== false && (this.options.auth?.enabled || this.mastra.getServer()?.auth)) {
852
- const user = await this.authService.authenticate(request);
996
+ if (!(routePath ? this.routeHandler.matchRoute(method, routePath) : void 0)) return true;
997
+ if (this.authService.isEnabled()) {
998
+ const user = await this.authService.authenticate(request, {
999
+ requestContext: this.requestContext.requestContext,
1000
+ response: context.switchToHttp().getResponse()
1001
+ });
853
1002
  if (user !== void 0) this.requestContext.setUser(user);
854
1003
  }
855
1004
  if (this.options.rateLimitOptions?.enabled !== false) {
856
- const { limit, windowMs } = this.throttleGuard.getRateLimitSettings(request, void 0, routePath);
857
- await this.throttleGuard.checkLimit(request, limit, windowMs, routePath);
1005
+ const { limit, windowMs } = this.throttleGuard.getRateLimitSettings(request, void 0, routePath ?? void 0);
1006
+ await this.throttleGuard.checkLimit(request, limit, windowMs, routePath ?? void 0);
858
1007
  }
859
1008
  return true;
860
1009
  }
861
1010
  };
862
1011
  MastraRouteGuard = __decorate([
863
1012
  Injectable({ scope: Scope.REQUEST }),
864
- __decorateParam(0, Inject(MASTRA)),
865
- __decorateParam(1, Inject(MASTRA_OPTIONS)),
866
- __decorateParam(2, Inject(RouteHandlerService)),
867
- __decorateParam(3, Inject(RequestContextService)),
868
- __decorateParam(4, Inject(AuthService)),
869
- __decorateParam(5, Inject(MastraThrottleGuard)),
1013
+ __decorateParam(0, Inject(MASTRA_OPTIONS)),
1014
+ __decorateParam(1, Inject(RouteHandlerService)),
1015
+ __decorateParam(2, Inject(RequestContextService)),
1016
+ __decorateParam(3, Inject(AuthService)),
1017
+ __decorateParam(4, Inject(MastraThrottleGuard)),
870
1018
  __decorateMetadata("design:paramtypes", [
871
- Object,
872
1019
  Object,
873
1020
  typeof RouteHandlerService === "undefined" ? Object : RouteHandlerService,
874
1021
  typeof RequestContextService === "undefined" ? Object : RequestContextService,
@@ -10831,18 +10978,36 @@ let MastraController = class MastraController {
10831
10978
  options;
10832
10979
  routeHandler;
10833
10980
  requestContext;
10834
- constructor(options, routeHandler, requestContext) {
10981
+ customRoutes;
10982
+ authService;
10983
+ constructor(options, routeHandler, requestContext, customRoutes, authService) {
10835
10984
  this.options = options;
10836
10985
  this.routeHandler = routeHandler;
10837
10986
  this.requestContext = requestContext;
10987
+ this.customRoutes = customRoutes;
10988
+ this.authService = authService;
10838
10989
  }
10839
10990
  /**
10840
10991
  * Catch-all handler that matches incoming requests to Mastra routes.
10841
10992
  */
10842
- async handleRequest(req, _res) {
10993
+ async handleRequest(req, res) {
10843
10994
  const path = req.path;
10844
10995
  const method = req.method.toUpperCase();
10845
10996
  const routePath = getMastraRoutePath(path, this.options.prefix);
10997
+ if (!routePath || !this.routeHandler.matchRoute(method, routePath)) {
10998
+ const requestContext = this.requestContext.requestContext;
10999
+ const authenticate = async (requiresAuth) => {
11000
+ if (!this.authService.isEnabled()) return;
11001
+ const user = await this.authService.authenticate(req, {
11002
+ requestContext,
11003
+ response: res,
11004
+ requiresAuth,
11005
+ customRoute: true
11006
+ });
11007
+ if (user !== void 0) this.requestContext.setUser(user);
11008
+ };
11009
+ if (await this.customRoutes.handle(req, res, requestContext, authenticate)) return;
11010
+ }
10846
11011
  if (!routePath) throw new NotFoundException(`Route not found: ${method} ${path}`);
10847
11012
  if (routePath.includes("//")) throw new NotFoundException(`Route not found: ${method} ${path}`);
10848
11013
  const matchResult = this.routeHandler.matchRoute(method, routePath);
@@ -10921,10 +11086,14 @@ MastraController = __decorate([
10921
11086
  __decorateParam(0, Inject(MASTRA_OPTIONS)),
10922
11087
  __decorateParam(1, Inject(RouteHandlerService)),
10923
11088
  __decorateParam(2, Inject(RequestContextService)),
11089
+ __decorateParam(3, Inject(CustomRouteService)),
11090
+ __decorateParam(4, Inject(AuthService)),
10924
11091
  __decorateMetadata("design:paramtypes", [
10925
11092
  Object,
10926
11093
  typeof RouteHandlerService === "undefined" ? Object : RouteHandlerService,
10927
- typeof RequestContextService === "undefined" ? Object : RequestContextService
11094
+ typeof RequestContextService === "undefined" ? Object : RequestContextService,
11095
+ typeof CustomRouteService === "undefined" ? Object : CustomRouteService,
11096
+ typeof AuthService === "undefined" ? Object : AuthService
10928
11097
  ])
10929
11098
  ], MastraController);
10930
11099
  //#endregion
@@ -11085,7 +11254,7 @@ let MastraAuthGuard = _MastraAuthGuard = class MastraAuthGuard {
11085
11254
  if (this.reflector.getAllAndOverride("isPublic", [context.getHandler(), context.getClass()])) return true;
11086
11255
  const request = context.switchToHttp().getRequest();
11087
11256
  try {
11088
- await this.authService.authenticate(request);
11257
+ await this.authService.authenticate(request, { response: context.switchToHttp().getResponse() });
11089
11258
  return true;
11090
11259
  } catch (error) {
11091
11260
  this.logger.error(`Authentication error: ${error instanceof Error ? error.message : String(error)}`);
@@ -11299,6 +11468,7 @@ let MastraModule = _MastraModule = class MastraModule {
11299
11468
  RequestContextService,
11300
11469
  ShutdownService,
11301
11470
  AuthService,
11471
+ CustomRouteService,
11302
11472
  BodyLimitMiddleware,
11303
11473
  JsonBodyMiddleware,
11304
11474
  MastraAuthGuard,
@@ -11373,6 +11543,7 @@ let MastraModule = _MastraModule = class MastraModule {
11373
11543
  RequestContextService,
11374
11544
  ShutdownService,
11375
11545
  AuthService,
11546
+ CustomRouteService,
11376
11547
  BodyLimitMiddleware,
11377
11548
  JsonBodyMiddleware,
11378
11549
  MastraAuthGuard,
@@ -11399,6 +11570,6 @@ let MastraModule = _MastraModule = class MastraModule {
11399
11570
  };
11400
11571
  MastraModule = _MastraModule = __decorate([Module({})], MastraModule);
11401
11572
  //#endregion
11402
- export { AuthService, BodyLimitMiddleware, JsonBodyMiddleware, MASTRA, MASTRA_OPTIONS, MastraAuthGuard, MastraExceptionFilter, MastraModule, MastraService, MastraThrottle, MastraThrottleGuard, NestMastraServer, Public, RequestContextService, RequestTrackingInterceptor, RouteHandlerService, ShutdownService, SkipThrottle, StreamingInterceptor, TracingInterceptor, ValidationError, parseMultipartFormData };
11573
+ export { AuthService, BodyLimitMiddleware, CustomRouteService, JsonBodyMiddleware, MASTRA, MASTRA_OPTIONS, MastraAuthGuard, MastraExceptionFilter, MastraModule, MastraService, MastraThrottle, MastraThrottleGuard, NestMastraServer, Public, RequestContextService, RequestTrackingInterceptor, RouteHandlerService, ShutdownService, SkipThrottle, StreamingInterceptor, TracingInterceptor, ValidationError, parseMultipartFormData };
11403
11574
 
11404
11575
  //# sourceMappingURL=index.js.map