@mastra/auth-studio 1.3.10 → 1.3.11-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/_types/@internal_auth/dist/_types/@internal_core/dist/base/index.d.ts +2 -5
- package/dist/_types/@internal_auth/dist/_types/@internal_core/dist/{index-Biaf3BmX.d.ts → index-TNVgGNjs.d.ts} +1 -5
- package/dist/_types/@internal_auth/dist/session/index.d.ts +9 -0
- package/dist/index.cjs +133 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +56 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +132 -44
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { i as IMastraLogger, u as RegisteredLogger } from "../index-
|
|
2
|
-
|
|
3
|
-
declare class MastraBase {
|
|
1
|
+
import { i as IMastraLogger, u as RegisteredLogger } from "../index-TNVgGNjs.js";
|
|
2
|
+
export declare class MastraBase {
|
|
4
3
|
#private;
|
|
5
4
|
component: RegisteredLogger;
|
|
6
5
|
protected logger: IMastraLogger;
|
|
@@ -26,6 +25,4 @@ declare class MastraBase {
|
|
|
26
25
|
*/
|
|
27
26
|
__setLogger(logger: IMastraLogger): void;
|
|
28
27
|
}
|
|
29
|
-
//#endregion
|
|
30
|
-
export { MastraBase };
|
|
31
28
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Transform } from "stream";
|
|
2
|
-
//#region src/logger/adapter.d.ts
|
|
3
2
|
/**
|
|
4
3
|
* OpenTelemetry-compatible trace correlation fields, injected at the top
|
|
5
4
|
* level of a logger's native record.
|
|
@@ -91,8 +90,6 @@ declare function exportTrackedException(ctx: LoggerAdapterContext | undefined, e
|
|
|
91
90
|
* so the derived record preserves all context from the native call.
|
|
92
91
|
*/
|
|
93
92
|
declare function buildLogRecordData(args: unknown[]): Record<string, unknown> | undefined;
|
|
94
|
-
//#endregion
|
|
95
|
-
//#region src/logger/index.d.ts
|
|
96
93
|
declare const RegisteredLogger: {
|
|
97
94
|
readonly AGENT: 'AGENT';
|
|
98
95
|
readonly OBSERVABILITY: 'OBSERVABILITY';
|
|
@@ -314,6 +311,5 @@ declare class ConsoleLogger extends MastraLogger {
|
|
|
314
311
|
hasMore: boolean;
|
|
315
312
|
}>;
|
|
316
313
|
}
|
|
317
|
-
//#endregion
|
|
318
314
|
export { buildLogRecordData as _, LogFilter as a, LoggerTransport as c, createCustomTransport as d, AdaptableLogger as f, TraceFields as g, LoggerAdapterOptions as h, IMastraLogger as i, MastraLogger as l, LoggerAdapterContext as m, ConsoleLogger as n, LogFilterContext as o, AdapterLogSink as p, ConsoleLoggerOptions as r, LogLevel as s, BaseLogMessage as t, RegisteredLogger as u, exportTrackedException as v, isAdaptableLogger as y };
|
|
319
|
-
//# sourceMappingURL=index-
|
|
315
|
+
//# sourceMappingURL=index-TNVgGNjs.d.ts.map
|
|
@@ -24,6 +24,15 @@ export interface ISessionProvider<TSession extends Session = Session> {
|
|
|
24
24
|
getSessionIdFromRequest(request: Request): string | null;
|
|
25
25
|
getSessionHeaders(session: TSession): Record<string, string>;
|
|
26
26
|
getClearSessionHeaders(): Record<string, string>;
|
|
27
|
+
/**
|
|
28
|
+
* Optional: `Set-Cookie` values expiring legacy copies of the session cookie
|
|
29
|
+
* (for example one an earlier release scoped to a shared parent `Domain`).
|
|
30
|
+
* A browser only deletes a cookie whose exact `(name, Domain, Path)` match,
|
|
31
|
+
* so servers append these to every response that sets or clears the session
|
|
32
|
+
* cookie; otherwise a stale shared-domain copy keeps being sent to every
|
|
33
|
+
* sibling host until it expires.
|
|
34
|
+
*/
|
|
35
|
+
getLegacySessionClearCookies?(): string[];
|
|
27
36
|
}
|
|
28
37
|
export { MemorySessionProvider, type MemorySessionProviderOptions } from './memory.js';
|
|
29
38
|
export { CookieSessionProvider, type CookieSessionProviderOptions } from './cookie.js';
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let fs = require("fs");
|
|
3
3
|
let path = require("path");
|
|
4
|
-
|
|
4
|
+
// ../../packages/_internals/auth/dist/types/index.js
|
|
5
5
|
function headerFromPlainObject(headers, name) {
|
|
6
6
|
const normalizedName = name.toLowerCase();
|
|
7
7
|
const matchingKey = Object.keys(headers).find((key) => key.toLowerCase() === normalizedName);
|
|
@@ -25,8 +25,7 @@ function getWebRequest(request) {
|
|
|
25
25
|
if (request instanceof Request) return request;
|
|
26
26
|
return request.raw instanceof Request ? request.raw : void 0;
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
//#region ../../packages/_internal-core/dist/logger/index.js
|
|
28
|
+
// ../../packages/_internal-core/dist/logger/index.js
|
|
30
29
|
/**
|
|
31
30
|
* Export a tracked exception through the adapter sink, mirroring the
|
|
32
31
|
* DualLogger dual-write shape (`errorId`/`domain`/`category`/`details`/`cause`
|
|
@@ -259,8 +258,7 @@ var ConsoleLogger = class ConsoleLogger extends MastraLogger {
|
|
|
259
258
|
};
|
|
260
259
|
}
|
|
261
260
|
};
|
|
262
|
-
|
|
263
|
-
//#region ../../packages/_internal-core/dist/base/index.js
|
|
261
|
+
// ../../packages/_internal-core/dist/base/index.js
|
|
264
262
|
var MastraBase = class {
|
|
265
263
|
component = RegisteredLogger.LLM;
|
|
266
264
|
logger;
|
|
@@ -294,8 +292,7 @@ var MastraBase = class {
|
|
|
294
292
|
this.logger = "child" in logger && typeof logger.child === "function" ? logger.child({ component: this.component }) : logger;
|
|
295
293
|
}
|
|
296
294
|
};
|
|
297
|
-
|
|
298
|
-
//#region ../../packages/_internals/auth/dist/provider/index.js
|
|
295
|
+
// ../../packages/_internals/auth/dist/provider/index.js
|
|
299
296
|
var MastraAuthProvider = class extends MastraBase {
|
|
300
297
|
protected;
|
|
301
298
|
public;
|
|
@@ -307,7 +304,7 @@ var MastraAuthProvider = class extends MastraBase {
|
|
|
307
304
|
if (options?.authorizeUser) this.authorizeUser = options.authorizeUser.bind(this);
|
|
308
305
|
this.protected = options?.protected;
|
|
309
306
|
this.public = options?.public;
|
|
310
|
-
this.mapUserToResourceId = options
|
|
307
|
+
if (options?.mapUserToResourceId) this.mapUserToResourceId = options.mapUserToResourceId;
|
|
311
308
|
}
|
|
312
309
|
registerOptions(opts) {
|
|
313
310
|
if (opts?.authorizeUser) this.authorizeUser = opts.authorizeUser.bind(this);
|
|
@@ -316,8 +313,7 @@ var MastraAuthProvider = class extends MastraBase {
|
|
|
316
313
|
if (opts?.public) this.public = opts.public;
|
|
317
314
|
}
|
|
318
315
|
};
|
|
319
|
-
|
|
320
|
-
//#region ../../packages/_internals/auth/dist/ee-XRuijAiF.js
|
|
316
|
+
// ../../packages/_internals/auth/dist/ee-CnZdF0Vm.js
|
|
321
317
|
/**
|
|
322
318
|
* FGA enforcement utility for checking fine-grained authorization.
|
|
323
319
|
*
|
|
@@ -426,10 +422,29 @@ function resolvePermissionsFromMapping(roles, mapping) {
|
|
|
426
422
|
* @license Mastra Enterprise License - see ee/LICENSE
|
|
427
423
|
* @packageDocumentation
|
|
428
424
|
*/
|
|
429
|
-
|
|
430
|
-
//#region src/index.ts
|
|
425
|
+
// src/index.ts
|
|
431
426
|
const DEFAULT_SESSION_MAX_AGE_SECONDS = 1209600;
|
|
427
|
+
/**
|
|
428
|
+
* Name of the sealed session cookie on the shared API. Used for server-to-server
|
|
429
|
+
* calls to the shared API, and as the unprefixed (legacy / insecure-dev /
|
|
430
|
+
* explicit-domain) browser cookie name.
|
|
431
|
+
*/
|
|
432
432
|
const COOKIE_NAME = "wos-session";
|
|
433
|
+
/** Host-only browser session cookie used on secure deployments. */
|
|
434
|
+
const HOST_SESSION_COOKIE_NAME = "__Host-wos-session";
|
|
435
|
+
/** Unprefixed session cookie name earlier releases issued (often with a shared parent `Domain`). */
|
|
436
|
+
const LEGACY_SESSION_COOKIE_NAME = COOKIE_NAME;
|
|
437
|
+
/** A `Domain` attribute value we are willing to emit in a clearing cookie. */
|
|
438
|
+
function normalizeCookieDomain(value) {
|
|
439
|
+
const domain = value?.trim().toLowerCase();
|
|
440
|
+
if (!domain) return void 0;
|
|
441
|
+
if (!/^\.?[a-z0-9-]+(\.[a-z0-9-]+)*$/.test(domain)) return void 0;
|
|
442
|
+
return domain;
|
|
443
|
+
}
|
|
444
|
+
function isLocalhostDomain(domain) {
|
|
445
|
+
const bare = domain.replace(/^\./, "");
|
|
446
|
+
return bare === "localhost" || bare.endsWith(".localhost") || /^[\d.]+$/.test(bare);
|
|
447
|
+
}
|
|
433
448
|
const PROJECT_CONFIG_FILE = ".mastra-project.json";
|
|
434
449
|
/**
|
|
435
450
|
* Read `organizationId` from a project's `.mastra-project.json` in the current
|
|
@@ -479,6 +494,10 @@ var MastraAuthStudio = class extends MastraAuthProvider {
|
|
|
479
494
|
organizationId;
|
|
480
495
|
useProductionCookies;
|
|
481
496
|
cookieDomain;
|
|
497
|
+
/** Browser cookie name this provider issues. */
|
|
498
|
+
sessionCookieName;
|
|
499
|
+
/** `Set-Cookie` values expiring legacy copies of the session cookie. */
|
|
500
|
+
legacyClearCookies;
|
|
482
501
|
sessionMaxAgeSeconds;
|
|
483
502
|
/**
|
|
484
503
|
* `userId → sealed session cookie` cache. The `IOrganizationsProvider`
|
|
@@ -528,7 +547,8 @@ var MastraAuthStudio = class extends MastraAuthProvider {
|
|
|
528
547
|
this.sharedApiUrl = explicitSharedApiUrl || "https://platform.mastra.ai/v1";
|
|
529
548
|
this.organizationId = options?.organizationId || process.env.MASTRA_ORGANIZATION_ID || readOrganizationIdFromProjectConfig();
|
|
530
549
|
if (this.sharedApiUrl.endsWith("/")) this.sharedApiUrl = this.sharedApiUrl.slice(0, -1);
|
|
531
|
-
this.cookieDomain = options?.cookieDomain
|
|
550
|
+
this.cookieDomain = normalizeCookieDomain(options?.cookieDomain);
|
|
551
|
+
const envCookieDomain = normalizeCookieDomain(process.env.MASTRA_COOKIE_DOMAIN);
|
|
532
552
|
const envMaxAge = Number(process.env.MASTRA_SESSION_MAX_AGE);
|
|
533
553
|
const maxAge = options?.sessionMaxAgeSeconds ?? (envMaxAge > 0 ? envMaxAge : void 0);
|
|
534
554
|
this.sessionMaxAgeSeconds = maxAge && Number.isFinite(maxAge) && maxAge > 0 ? Math.floor(maxAge) : DEFAULT_SESSION_MAX_AGE_SECONDS;
|
|
@@ -539,8 +559,31 @@ var MastraAuthStudio = class extends MastraAuthProvider {
|
|
|
539
559
|
} catch {
|
|
540
560
|
autoDetectMastraAi = false;
|
|
541
561
|
}
|
|
542
|
-
this.useProductionCookies = !!this.cookieDomain || autoDetectMastraAi;
|
|
543
|
-
|
|
562
|
+
this.useProductionCookies = options?.secureCookies ?? (!!(this.cookieDomain && !isLocalhostDomain(this.cookieDomain)) || !!(envCookieDomain && !isLocalhostDomain(envCookieDomain)) || autoDetectMastraAi);
|
|
563
|
+
this.sessionCookieName = this.useProductionCookies && !this.cookieDomain ? HOST_SESSION_COOKIE_NAME : LEGACY_SESSION_COOKIE_NAME;
|
|
564
|
+
const legacyDomains = /* @__PURE__ */ new Set();
|
|
565
|
+
const addLegacyDomain = (value) => {
|
|
566
|
+
const domain = normalizeCookieDomain(value);
|
|
567
|
+
if (domain && domain !== this.cookieDomain) legacyDomains.add(domain);
|
|
568
|
+
};
|
|
569
|
+
addLegacyDomain(envCookieDomain);
|
|
570
|
+
if (autoDetectMastraAi) addLegacyDomain(".mastra.ai");
|
|
571
|
+
for (const value of (process.env.MASTRA_LEGACY_COOKIE_DOMAINS ?? "").split(",")) addLegacyDomain(value);
|
|
572
|
+
for (const value of options?.legacyCookieDomains ?? []) addLegacyDomain(value);
|
|
573
|
+
const clearAttributes = [
|
|
574
|
+
"HttpOnly",
|
|
575
|
+
"SameSite=Lax",
|
|
576
|
+
"Path=/",
|
|
577
|
+
"Max-Age=0"
|
|
578
|
+
];
|
|
579
|
+
if (this.useProductionCookies) clearAttributes.push("Secure");
|
|
580
|
+
this.legacyClearCookies = [];
|
|
581
|
+
if (this.sessionCookieName !== "wos-session" || this.cookieDomain) this.legacyClearCookies.push([`${LEGACY_SESSION_COOKIE_NAME}=`, ...clearAttributes].join("; "));
|
|
582
|
+
for (const domain of legacyDomains) this.legacyClearCookies.push([
|
|
583
|
+
`${LEGACY_SESSION_COOKIE_NAME}=`,
|
|
584
|
+
...clearAttributes,
|
|
585
|
+
`Domain=${domain}`
|
|
586
|
+
].join("; "));
|
|
544
587
|
if (options) this.registerOptions(options);
|
|
545
588
|
}
|
|
546
589
|
/**
|
|
@@ -549,8 +592,12 @@ var MastraAuthStudio = class extends MastraAuthProvider {
|
|
|
549
592
|
*/
|
|
550
593
|
async authenticateToken(token, request) {
|
|
551
594
|
let user = null;
|
|
552
|
-
const
|
|
553
|
-
|
|
595
|
+
const cookieHeader = getRequestHeader(request, "Cookie");
|
|
596
|
+
const sessionCookie = this.readSessionCookie(cookieHeader);
|
|
597
|
+
if (sessionCookie) {
|
|
598
|
+
user = await this.verifySessionCookie(sessionCookie.value, request);
|
|
599
|
+
if (user && sessionCookie.legacy) this.queueSessionCookieMigration(request, sessionCookie.value);
|
|
600
|
+
}
|
|
554
601
|
if (!user && token) user = await this.verifyBearerToken(token);
|
|
555
602
|
if (!user) return null;
|
|
556
603
|
if (this.organizationId && !user.memberOrgIds?.includes(this.organizationId)) return null;
|
|
@@ -604,8 +651,7 @@ var MastraAuthStudio = class extends MastraAuthProvider {
|
|
|
604
651
|
};
|
|
605
652
|
}
|
|
606
653
|
async getLogoutUrl(_redirectUri, request) {
|
|
607
|
-
const
|
|
608
|
-
const sessionCookie = parseCookie(cookieHeader, COOKIE_NAME);
|
|
654
|
+
const sessionCookie = this.readSessionCookie(request?.headers.get("Cookie"))?.value;
|
|
609
655
|
if (!sessionCookie) return null;
|
|
610
656
|
try {
|
|
611
657
|
const res = await fetch(`${this.sharedApiUrl}/auth/logout`, {
|
|
@@ -688,39 +734,76 @@ var MastraAuthStudio = class extends MastraAuthProvider {
|
|
|
688
734
|
}
|
|
689
735
|
}
|
|
690
736
|
getSessionIdFromRequest(request) {
|
|
691
|
-
return
|
|
737
|
+
return this.readSessionCookie(request.headers.get("Cookie"))?.value ?? null;
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* The browser session cookie on a request: this provider's cookie
|
|
741
|
+
* (`__Host-wos-session` on secure deployments) first, then — only to migrate
|
|
742
|
+
* sessions issued by earlier releases — the unprefixed `wos-session`.
|
|
743
|
+
*/
|
|
744
|
+
readSessionCookie(cookieHeader) {
|
|
745
|
+
const current = parseCookie(cookieHeader, this.sessionCookieName);
|
|
746
|
+
if (current) return {
|
|
747
|
+
value: current,
|
|
748
|
+
legacy: false
|
|
749
|
+
};
|
|
750
|
+
if (this.sessionCookieName === "wos-session") return null;
|
|
751
|
+
const legacy = parseCookie(cookieHeader, LEGACY_SESSION_COOKIE_NAME);
|
|
752
|
+
return legacy ? {
|
|
753
|
+
value: legacy,
|
|
754
|
+
legacy: true
|
|
755
|
+
} : null;
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* A request authenticated with a legacy `wos-session` cookie: re-issue the
|
|
759
|
+
* session under this provider's cookie so the browser stops depending on the
|
|
760
|
+
* legacy (possibly shared-domain) copy. The legacy copy itself is expired on
|
|
761
|
+
* the next sign-in, refresh or sign-out (see `getLegacySessionClearCookies`).
|
|
762
|
+
*/
|
|
763
|
+
queueSessionCookieMigration(request, sessionId) {
|
|
764
|
+
const rawRequest = getWebRequest(request);
|
|
765
|
+
if (!rawRequest || this.pendingResponseHeaders.has(rawRequest)) return;
|
|
766
|
+
this.pendingResponseHeaders.set(rawRequest, this.getSessionHeaders({
|
|
767
|
+
id: sessionId,
|
|
768
|
+
userId: "",
|
|
769
|
+
expiresAt: /* @__PURE__ */ new Date(),
|
|
770
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
771
|
+
}));
|
|
692
772
|
}
|
|
693
773
|
getSessionHeaders(session) {
|
|
694
|
-
|
|
695
|
-
`${COOKIE_NAME}=${session.id}`,
|
|
696
|
-
"HttpOnly",
|
|
697
|
-
"SameSite=Lax",
|
|
698
|
-
"Path=/",
|
|
699
|
-
`Max-Age=${this.sessionMaxAgeSeconds}`
|
|
700
|
-
];
|
|
701
|
-
if (this.useProductionCookies && this.cookieDomain) {
|
|
702
|
-
parts.push("Secure");
|
|
703
|
-
parts.push(`Domain=${this.cookieDomain}`);
|
|
704
|
-
}
|
|
705
|
-
return { "Set-Cookie": parts.join("; ") };
|
|
774
|
+
return { "Set-Cookie": this.buildSessionCookie(`${this.sessionCookieName}=${session.id}`, [`Max-Age=${this.sessionMaxAgeSeconds}`]) };
|
|
706
775
|
}
|
|
707
776
|
getClearSessionHeaders() {
|
|
777
|
+
return { "Set-Cookie": this.buildSessionCookie(`${this.sessionCookieName}=`, ["Max-Age=0"]) };
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* `Set-Cookie` values expiring legacy copies of the session cookie: the
|
|
781
|
+
* unprefixed `wos-session` on this host and on every domain an earlier
|
|
782
|
+
* release (or the platform) scoped it to. Servers send these with every
|
|
783
|
+
* response that sets or clears the session cookie.
|
|
784
|
+
*/
|
|
785
|
+
getLegacySessionClearCookies() {
|
|
786
|
+
return [...this.legacyClearCookies];
|
|
787
|
+
}
|
|
788
|
+
buildSessionCookie(nameValue, extra) {
|
|
708
789
|
const parts = [
|
|
709
|
-
|
|
790
|
+
nameValue,
|
|
710
791
|
"HttpOnly",
|
|
711
792
|
"SameSite=Lax",
|
|
712
793
|
"Path=/",
|
|
713
|
-
|
|
794
|
+
...extra
|
|
714
795
|
];
|
|
715
|
-
if (this.useProductionCookies
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
}
|
|
719
|
-
return { "Set-Cookie": parts.join("; ") };
|
|
796
|
+
if (this.useProductionCookies) parts.push("Secure");
|
|
797
|
+
if (this.cookieDomain && this.sessionCookieName !== "__Host-wos-session") parts.push(`Domain=${this.cookieDomain}`);
|
|
798
|
+
return parts.join("; ");
|
|
720
799
|
}
|
|
721
800
|
async getCurrentUser(request) {
|
|
722
|
-
const sessionCookie =
|
|
723
|
-
if (sessionCookie)
|
|
801
|
+
const sessionCookie = this.readSessionCookie(request.headers.get("Cookie"));
|
|
802
|
+
if (sessionCookie) {
|
|
803
|
+
const user = await this.verifySessionCookie(sessionCookie.value, request);
|
|
804
|
+
if (user && sessionCookie.legacy) this.queueSessionCookieMigration(request, sessionCookie.value);
|
|
805
|
+
return user;
|
|
806
|
+
}
|
|
724
807
|
const authHeader = request.headers.get("Authorization");
|
|
725
808
|
if (authHeader?.startsWith("Bearer ")) return this.verifyBearerToken(authHeader.slice(7));
|
|
726
809
|
return null;
|
|
@@ -1038,7 +1121,13 @@ var MastraAuthStudio = class extends MastraAuthProvider {
|
|
|
1038
1121
|
};
|
|
1039
1122
|
function parseCookie(cookieHeader, name) {
|
|
1040
1123
|
if (!cookieHeader) return null;
|
|
1041
|
-
|
|
1124
|
+
for (const pair of cookieHeader.split(";")) {
|
|
1125
|
+
const eq = pair.indexOf("=");
|
|
1126
|
+
if (eq === -1 || pair.slice(0, eq).trim() !== name) continue;
|
|
1127
|
+
const value = pair.slice(eq + 1).trim();
|
|
1128
|
+
if (value) return value;
|
|
1129
|
+
}
|
|
1130
|
+
return null;
|
|
1042
1131
|
}
|
|
1043
1132
|
/**
|
|
1044
1133
|
* WorkOS AuthKit conventionally uses `admin` / `owner` for admin-equivalent
|
|
@@ -1096,7 +1185,8 @@ var MastraRBACStudio = class {
|
|
|
1096
1185
|
return permissions.some((required) => userPermissions.some((p) => matchesPermission(p, required)));
|
|
1097
1186
|
}
|
|
1098
1187
|
};
|
|
1099
|
-
|
|
1188
|
+
exports.HOST_SESSION_COOKIE_NAME = HOST_SESSION_COOKIE_NAME;
|
|
1189
|
+
exports.LEGACY_SESSION_COOKIE_NAME = LEGACY_SESSION_COOKIE_NAME;
|
|
1100
1190
|
exports.MastraAuthStudio = MastraAuthStudio;
|
|
1101
1191
|
exports.MastraRBACStudio = MastraRBACStudio;
|
|
1102
1192
|
|