@mastra/nestjs 0.2.38 → 0.2.39-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/controllers/mastra.controller.d.ts.map +1 -1
- package/dist/filters/mastra-exception.filter.d.ts.map +1 -1
- package/dist/index.cjs +101 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +102 -15
- package/dist/index.js.map +1 -1
- package/dist/mastra.service.d.ts +2 -0
- package/dist/mastra.service.d.ts.map +1 -1
- package/dist/services/auth.service.d.ts +6 -1
- package/dist/services/auth.service.d.ts.map +1 -1
- package/dist/services/custom-route.service.d.ts +4 -3
- package/dist/services/custom-route.service.d.ts.map +1 -1
- package/dist/services/route-handler.service.d.ts +15 -0
- package/dist/services/route-handler.service.d.ts.map +1 -1
- package/package.json +10 -10
|
@@ -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,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;
|
|
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;AAEtE,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,CA2EpG;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;OAEG;YACW,SAAS;CAsBxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mastra-exception.filter.d.ts","sourceRoot":"","sources":["../../src/filters/mastra-exception.filter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mastra-exception.filter.d.ts","sourceRoot":"","sources":["../../src/filters/mastra-exception.filter.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAYrE;;;;;;;;;;;;;GAaG;AACH,qBACa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IAE3D,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DlE;IAED;;OAEG;IACH,OAAO,CAAC,cAAc;IAgHtB;;OAEG;IACH,OAAO,CAAC,YAAY;CAkCrB"}
|
package/dist/index.cjs
CHANGED
|
@@ -25,6 +25,7 @@ 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_core_auth_ee = require("@mastra/core/auth/ee");
|
|
28
29
|
let _mastra_core_request_context = require("@mastra/core/request-context");
|
|
29
30
|
let _mastra_server_auth = require("@mastra/server/auth");
|
|
30
31
|
let stream = require("stream");
|
|
@@ -225,6 +226,11 @@ let RouteHandlerService = _RouteHandlerService = class RouteHandlerService {
|
|
|
225
226
|
if ((0, _mastra_server_server_adapter.isZodError)(error)) throw this.createValidationError(route, error, "body");
|
|
226
227
|
throw error;
|
|
227
228
|
}
|
|
229
|
+
await this.authorizeRoute(route, params.requestContext, {
|
|
230
|
+
...validatedPathParams,
|
|
231
|
+
...validatedQueryParams,
|
|
232
|
+
...typeof validatedBody === "object" && validatedBody !== null ? validatedBody : {}
|
|
233
|
+
});
|
|
228
234
|
const context = {
|
|
229
235
|
mastra: this.mastra,
|
|
230
236
|
requestContext: params.requestContext,
|
|
@@ -247,6 +253,39 @@ let RouteHandlerService = _RouteHandlerService = class RouteHandlerService {
|
|
|
247
253
|
sseFlushOnConnect: route.sseFlushOnConnect
|
|
248
254
|
};
|
|
249
255
|
}
|
|
256
|
+
/**
|
|
257
|
+
* Enforce the route's RBAC permission and FGA check, matching the other server adapters.
|
|
258
|
+
* Relies on the auth guard having stored the user, permissions, and auth mode in the request context.
|
|
259
|
+
*/
|
|
260
|
+
async authorizeRoute(route, requestContext, params) {
|
|
261
|
+
await this.enforceRoutePermission(route, requestContext);
|
|
262
|
+
await this.enforceRouteFGA(route, requestContext, params);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Throws 403 when the user lacks the route's effective RBAC permission.
|
|
266
|
+
* Skipped when Mastra auth is explicitly disabled (`auth.enabled: false`), since no Mastra user is resolved.
|
|
267
|
+
*/
|
|
268
|
+
async enforceRoutePermission(route, requestContext) {
|
|
269
|
+
if (this.options.auth?.enabled === false) return;
|
|
270
|
+
const studio = this.mastra.getStudio?.();
|
|
271
|
+
const server = this.mastra.getServer();
|
|
272
|
+
if (!studio?.auth && !server?.auth) return;
|
|
273
|
+
const requiredPermission = (requestContext.get(_mastra_server_server_adapter.MASTRA_AUTH_MODE_KEY) === "studio" ? studio?.rbac ?? server?.rbac : server?.rbac) ? (0, _mastra_server_server_adapter.getEffectivePermission)(route) : null;
|
|
274
|
+
if (requiredPermission) {
|
|
275
|
+
const required = Array.isArray(requiredPermission) ? requiredPermission : [requiredPermission];
|
|
276
|
+
const userPermissions = requestContext.get("mastra__userPermissions");
|
|
277
|
+
if (!userPermissions || !required.some((permission) => (0, _mastra_core_auth_ee.hasPermission)(userPermissions, permission))) throw new _nestjs_common.ForbiddenException(`Missing required permission: ${required.join(" or ")}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Throws when the FGA provider denies the route's resource.
|
|
282
|
+
* Skipped when Mastra auth is explicitly disabled (`auth.enabled: false`), since no Mastra user is resolved.
|
|
283
|
+
*/
|
|
284
|
+
async enforceRouteFGA(route, requestContext, params) {
|
|
285
|
+
if (this.options.auth?.enabled === false) return;
|
|
286
|
+
const fgaError = await (0, _mastra_server_server_adapter.checkRouteFGA)(this.mastra, route, requestContext, params);
|
|
287
|
+
if (fgaError) throw new _nestjs_common.HttpException(fgaError.message, fgaError.status);
|
|
288
|
+
}
|
|
250
289
|
async parseBody(route, body) {
|
|
251
290
|
const bodySchema = route.bodySchema;
|
|
252
291
|
if (!bodySchema) return body;
|
|
@@ -340,7 +379,8 @@ let MastraExceptionFilter = _MastraExceptionFilter = class MastraExceptionFilter
|
|
|
340
379
|
return;
|
|
341
380
|
}
|
|
342
381
|
if (exception instanceof _mastra_server_server_adapter.HTTPException) {
|
|
343
|
-
|
|
382
|
+
const { status, body } = (0, _mastra_server_server_adapter.getHTTPErrorResponse)(exception);
|
|
383
|
+
response.status(status).json(body);
|
|
344
384
|
return;
|
|
345
385
|
}
|
|
346
386
|
const normalized = this.normalizeError(exception);
|
|
@@ -500,7 +540,7 @@ let CustomRouteService = class CustomRouteService {
|
|
|
500
540
|
* Runs a matched custom route and writes its response.
|
|
501
541
|
* Returns false if no custom route handled the request.
|
|
502
542
|
*
|
|
503
|
-
* `authenticate` runs after Hono's router selects the route, so auth
|
|
543
|
+
* `authenticate` runs after Hono's router selects the route, so auth, RBAC, and FGA are enforced
|
|
504
544
|
* for exactly the routes Hono dispatches (including regex-constrained params).
|
|
505
545
|
*/
|
|
506
546
|
async handle(req, res, requestContext, authenticate) {
|
|
@@ -561,6 +601,8 @@ let CustomRouteService = class CustomRouteService {
|
|
|
561
601
|
const serverOnError = mastra.getServer()?.onError;
|
|
562
602
|
app.onError((err, c) => {
|
|
563
603
|
if (serverOnError) return serverOnError(err, c);
|
|
604
|
+
const httpExceptionResponse = (0, _mastra_server_server_adapter.getCustomRouteHTTPExceptionResponse)(err);
|
|
605
|
+
if (httpExceptionResponse) return httpExceptionResponse;
|
|
564
606
|
mastra.getLogger()?.error(`Custom route handler failed: ${c.req.method} ${c.req.path}`, { error: err instanceof Error ? err.stack ?? err.message : String(err) });
|
|
565
607
|
return c.json({ error: "Internal Server Error" }, 500);
|
|
566
608
|
});
|
|
@@ -571,7 +613,7 @@ let CustomRouteService = class CustomRouteService {
|
|
|
571
613
|
const requiresAuth = this.authConfig.get(`${route.method}:${route.path}`) ?? route.requiresAuth !== false;
|
|
572
614
|
const authMiddleware = async (c, next) => {
|
|
573
615
|
try {
|
|
574
|
-
await c.env.authenticate(requiresAuth);
|
|
616
|
+
await c.env.authenticate(route, requiresAuth, c.req.param());
|
|
575
617
|
} catch (err) {
|
|
576
618
|
c.env.authError = err;
|
|
577
619
|
return c.body(null, 401);
|
|
@@ -638,11 +680,29 @@ let AuthService = class AuthService {
|
|
|
638
680
|
}
|
|
639
681
|
/**
|
|
640
682
|
* Whether Mastra auth should run: module options enable it, or the Mastra
|
|
641
|
-
* server has auth configured (unless module options explicitly disable it).
|
|
683
|
+
* server or Studio has auth configured (unless module options explicitly disable it).
|
|
642
684
|
*/
|
|
643
685
|
isEnabled() {
|
|
644
686
|
if (this.options.auth?.enabled === false) return false;
|
|
645
|
-
return Boolean(this.options.auth?.enabled || this.mastra.getServer()?.auth);
|
|
687
|
+
return Boolean(this.options.auth?.enabled || this.mastra.getServer()?.auth || this.mastra.getStudio?.()?.auth);
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Studio requests (`x-mastra-client-type: studio`) use `studio.auth` exclusively when it is
|
|
691
|
+
* configured, without falling back to `server.auth`; all other requests use `server.auth`.
|
|
692
|
+
*/
|
|
693
|
+
getEffectiveAuthConfig(request) {
|
|
694
|
+
const clientType = request.headers[_mastra_server_server_adapter.MASTRA_CLIENT_TYPE_HEADER];
|
|
695
|
+
const isStudioRequest = (0, _mastra_server_server_adapter.isStudioClientTypeHeader)(Array.isArray(clientType) ? clientType[0] : clientType);
|
|
696
|
+
const studioAuth = this.mastra.getStudio?.()?.auth;
|
|
697
|
+
if (isStudioRequest && studioAuth) return {
|
|
698
|
+
authConfig: studioAuth,
|
|
699
|
+
authMode: "studio"
|
|
700
|
+
};
|
|
701
|
+
const serverAuth = this.mastra.getServer()?.auth;
|
|
702
|
+
return serverAuth ? {
|
|
703
|
+
authConfig: serverAuth,
|
|
704
|
+
authMode: "server"
|
|
705
|
+
} : null;
|
|
646
706
|
}
|
|
647
707
|
/**
|
|
648
708
|
* Check authentication for a request.
|
|
@@ -650,9 +710,11 @@ let AuthService = class AuthService {
|
|
|
650
710
|
* Throws UnauthorizedException or ForbiddenException if auth fails.
|
|
651
711
|
*/
|
|
652
712
|
async authenticate(request, options = {}) {
|
|
653
|
-
const
|
|
654
|
-
if (!
|
|
713
|
+
const effectiveAuth = this.getEffectiveAuthConfig(request);
|
|
714
|
+
if (!effectiveAuth) return;
|
|
715
|
+
const { authConfig, authMode } = effectiveAuth;
|
|
655
716
|
const requestContext = options.requestContext ?? new _mastra_core_request_context.RequestContext();
|
|
717
|
+
requestContext.set(_mastra_server_server_adapter.MASTRA_AUTH_MODE_KEY, authMode);
|
|
656
718
|
const path = request.path;
|
|
657
719
|
const method = request.method;
|
|
658
720
|
let customRouteAuthConfig = this.customRoutes.customRouteAuthConfig;
|
|
@@ -11030,15 +11092,31 @@ let MastraController = class MastraController {
|
|
|
11030
11092
|
const routePath = getMastraRoutePath(path, this.options.prefix);
|
|
11031
11093
|
if (!routePath || !this.routeHandler.matchRoute(method, routePath)) {
|
|
11032
11094
|
const requestContext = this.requestContext.requestContext;
|
|
11033
|
-
const authenticate = async (requiresAuth) => {
|
|
11034
|
-
if (
|
|
11035
|
-
|
|
11036
|
-
|
|
11037
|
-
|
|
11095
|
+
const authenticate = async (customRoute, requiresAuth, pathParams) => {
|
|
11096
|
+
if (this.authService.isEnabled()) {
|
|
11097
|
+
const user = await this.authService.authenticate(req, {
|
|
11098
|
+
requestContext,
|
|
11099
|
+
response: res,
|
|
11100
|
+
requiresAuth,
|
|
11101
|
+
customRoute: true
|
|
11102
|
+
});
|
|
11103
|
+
if (user !== void 0) this.requestContext.setUser(user);
|
|
11104
|
+
}
|
|
11105
|
+
const serverRoute = {
|
|
11106
|
+
method: customRoute.method,
|
|
11107
|
+
path: customRoute.path,
|
|
11108
|
+
responseType: "json",
|
|
11109
|
+
handler: async () => {},
|
|
11038
11110
|
requiresAuth,
|
|
11039
|
-
|
|
11111
|
+
requiresPermission: customRoute.requiresPermission,
|
|
11112
|
+
fga: customRoute.fga
|
|
11113
|
+
};
|
|
11114
|
+
if (requiresAuth) await this.routeHandler.enforceRoutePermission(serverRoute, requestContext);
|
|
11115
|
+
if (customRoute.fga) await this.routeHandler.enforceRouteFGA(serverRoute, requestContext, {
|
|
11116
|
+
...typeof req.body === "object" && req.body !== null ? req.body : {},
|
|
11117
|
+
...req.query,
|
|
11118
|
+
...pathParams
|
|
11040
11119
|
});
|
|
11041
|
-
if (user !== void 0) this.requestContext.setUser(user);
|
|
11042
11120
|
};
|
|
11043
11121
|
if (await this.customRoutes.handle(req, res, requestContext, authenticate)) return;
|
|
11044
11122
|
}
|
|
@@ -11359,6 +11437,15 @@ let MastraService = _MastraService = class MastraService {
|
|
|
11359
11437
|
}
|
|
11360
11438
|
this.serverAdapter = new NestMastraServer(app, this.routeHandler);
|
|
11361
11439
|
this.mastra.setMastraServer(this.serverAdapter);
|
|
11440
|
+
this.warnIfServerMiddlewareConfigured();
|
|
11441
|
+
}
|
|
11442
|
+
/** Mastra server middleware uses Hono's `(c, next)` signature, so NestJS cannot run it. */
|
|
11443
|
+
warnIfServerMiddlewareConfigured() {
|
|
11444
|
+
const instanceMiddleware = this.mastra.getServerMiddleware?.() ?? [];
|
|
11445
|
+
const configMiddleware = this.mastra.getServer()?.middleware;
|
|
11446
|
+
const hasConfigMiddleware = Array.isArray(configMiddleware) ? configMiddleware.length > 0 : !!configMiddleware;
|
|
11447
|
+
if (instanceMiddleware.length === 0 && !hasConfigMiddleware) return;
|
|
11448
|
+
this.mastra.getLogger()?.warn("Mastra server middleware (`server.middleware` or `setServerMiddleware()`) is configured, but this server adapter cannot run Hono middleware handlers. The configured middleware will not run — register middleware through your server framework instead.");
|
|
11362
11449
|
}
|
|
11363
11450
|
/**
|
|
11364
11451
|
* Get the Mastra instance.
|