@bagelink/auth 1.12.25 → 1.12.29
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/api.d.ts +9 -1
- package/dist/index.cjs +44 -39
- package/dist/index.mjs +44 -39
- package/dist/router.d.ts +3 -3
- package/dist/routes.d.ts +1 -1
- package/dist/useAuth.d.ts +2 -1
- package/package.json +1 -1
- package/src/api.ts +23 -1
- package/src/router.ts +16 -36
- package/src/routes.ts +3 -4
- package/src/useAuth.ts +9 -10
package/dist/api.d.ts
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
import { AxiosInstance } from 'axios';
|
|
1
2
|
import { RegisterRequest, UpdateAccountRequest, ChangePasswordRequest, ForgotPasswordRequest, ResetPasswordRequest, SendVerificationRequest, VerifyEmailRequest, AuthenticationAccount, PasswordLoginRequest, EmailTokenSendRequest, EmailTokenVerifyRequest, OTPSendRequest, OTPVerifyRequest, SMSSendRequest, SMSVerifyRequest, GenerateTokenRequest, RedeemTokenRequest, SSOLoginRequest, LoginResponse, RegisterResponse, LogoutResponse, GetMeResponse, UpdateMeResponse, DeleteMeResponse, ChangePasswordResponse, ForgotPasswordResponse, ResetPasswordResponse, VerifyResetTokenResponse, SendVerificationResponse, VerifyEmailResponse, RefreshSessionResponse, GetSessionsResponse, DeleteSessionResponse, DeleteAllSessionsResponse, CleanupSessionsResponse, GetMethodsResponse, GetAuthStatusResponse, SendEmailTokenResponse, VerifyEmailTokenResponse, SendOTPResponse, VerifyOTPResponse, SendSMSResponse, VerifySMSResponse, GenerateLoginTokenResponse, RedeemLoginTokenResponse, LegacySSOLoginResponse, SSOProvider, SSOInitiateRequest, SSOCallbackRequest, SSOLinkRequest, InitiateSSOResponse, CallbackSSOResponse, LinkSSOResponse, UnlinkSSOResponse, GetTenantsResponse, GetTenantResponse, CreateTenantResponse, UpdateTenantResponse, DeleteTenantResponse, GetTenantMembersResponse, AddTenantMemberResponse, UpdateTenantMemberResponse, DeleteTenantMemberResponse, GetTenantRolesResponse, CreateInvitationResponse, GetInvitationResponse, AcceptInvitationResponse, CreateTenantRequest, UpdateTenantRequest, AddMemberRequest, UpdateMemberRequest, CreateInvitationRequest, AcceptInvitationRequest } from './types';
|
|
2
3
|
export declare class AuthApi {
|
|
3
4
|
private api;
|
|
4
5
|
private currentTenantId;
|
|
6
|
+
private externalAxiosInstances;
|
|
5
7
|
constructor(baseURL?: string);
|
|
6
8
|
/**
|
|
7
|
-
*
|
|
9
|
+
* Register an external axios instance so that tenant headers
|
|
10
|
+
* are automatically applied to it when setTenantId() is called.
|
|
11
|
+
*/
|
|
12
|
+
registerAxios(instance: AxiosInstance): void;
|
|
13
|
+
/**
|
|
14
|
+
* Set the current tenant ID for multi-tenant requests.
|
|
15
|
+
* Also updates the header on any externally registered axios instances.
|
|
8
16
|
*/
|
|
9
17
|
setTenantId(tenantId: string | null): void;
|
|
10
18
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -64,14 +64,33 @@ class AuthApi {
|
|
|
64
64
|
constructor(baseURL = "") {
|
|
65
65
|
__publicField(this, "api");
|
|
66
66
|
__publicField(this, "currentTenantId", null);
|
|
67
|
+
__publicField(this, "externalAxiosInstances", /* @__PURE__ */ new Set());
|
|
67
68
|
this.api = createAxiosInstance(baseURL);
|
|
68
69
|
this.setupInterceptors();
|
|
69
70
|
}
|
|
70
71
|
/**
|
|
71
|
-
*
|
|
72
|
+
* Register an external axios instance so that tenant headers
|
|
73
|
+
* are automatically applied to it when setTenantId() is called.
|
|
74
|
+
*/
|
|
75
|
+
registerAxios(instance) {
|
|
76
|
+
this.externalAxiosInstances.add(instance);
|
|
77
|
+
if (this.currentTenantId !== null) {
|
|
78
|
+
instance.defaults.headers.common["X-Tenant-ID"] = this.currentTenantId;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Set the current tenant ID for multi-tenant requests.
|
|
83
|
+
* Also updates the header on any externally registered axios instances.
|
|
72
84
|
*/
|
|
73
85
|
setTenantId(tenantId) {
|
|
74
86
|
this.currentTenantId = tenantId;
|
|
87
|
+
for (const instance of this.externalAxiosInstances) {
|
|
88
|
+
if (tenantId !== null) {
|
|
89
|
+
instance.defaults.headers.common["X-Tenant-ID"] = tenantId;
|
|
90
|
+
} else {
|
|
91
|
+
delete instance.defaults.headers.common["X-Tenant-ID"];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
75
94
|
}
|
|
76
95
|
/**
|
|
77
96
|
* Get the current tenant ID
|
|
@@ -1041,11 +1060,11 @@ function createAuth(params) {
|
|
|
1041
1060
|
*
|
|
1042
1061
|
* // Manual guard control (for custom composition)
|
|
1043
1062
|
* auth.use(router, { guard: false })
|
|
1044
|
-
* router.beforeEach(async (to, from
|
|
1063
|
+
* router.beforeEach(async (to, from) => {
|
|
1045
1064
|
* // Custom logic first
|
|
1046
|
-
* if (!hasOrgAccess(to)) return
|
|
1065
|
+
* if (!hasOrgAccess(to)) return '/no-access'
|
|
1047
1066
|
* // Then run auth guard
|
|
1048
|
-
* return auth.routerGuard()(to, from
|
|
1067
|
+
* return auth.routerGuard()(to, from)
|
|
1049
1068
|
* })
|
|
1050
1069
|
* ```
|
|
1051
1070
|
*/
|
|
@@ -1074,11 +1093,11 @@ function createAuth(params) {
|
|
|
1074
1093
|
*/
|
|
1075
1094
|
routerGuard() {
|
|
1076
1095
|
if (cachedAuthGuard === null) {
|
|
1077
|
-
cachedAuthGuard = async (to, from
|
|
1096
|
+
cachedAuthGuard = async (to, from) => {
|
|
1078
1097
|
const { authGuard: authGuard2 } = await Promise.resolve().then(() => router);
|
|
1079
1098
|
const guard = authGuard2();
|
|
1080
1099
|
cachedAuthGuard = guard;
|
|
1081
|
-
return guard(to, from
|
|
1100
|
+
return guard(to, from);
|
|
1082
1101
|
};
|
|
1083
1102
|
}
|
|
1084
1103
|
return cachedAuthGuard;
|
|
@@ -1255,13 +1274,10 @@ function useAuth() {
|
|
|
1255
1274
|
try {
|
|
1256
1275
|
const { data } = await api.getTenants();
|
|
1257
1276
|
tenants.value = data;
|
|
1258
|
-
console.log("[Auth] Loaded tenants:", tenants.value);
|
|
1259
1277
|
if (currentTenant.value === null && tenants.value.length > 0) {
|
|
1260
1278
|
const firstActiveTenant = tenants.value.find((t) => t.status === "active");
|
|
1261
1279
|
if (firstActiveTenant !== void 0) {
|
|
1262
|
-
console.log("[Auth] Auto-selecting tenant:", firstActiveTenant.id);
|
|
1263
1280
|
setTenant(firstActiveTenant.id);
|
|
1264
|
-
console.log("[Auth] Tenant set. Current tenant ID in API:", api.getTenantId());
|
|
1265
1281
|
}
|
|
1266
1282
|
}
|
|
1267
1283
|
return tenants.value;
|
|
@@ -1510,7 +1526,9 @@ function useAuth() {
|
|
|
1510
1526
|
// Invitations
|
|
1511
1527
|
createInvitation,
|
|
1512
1528
|
getInvitation,
|
|
1513
|
-
acceptInvitation
|
|
1529
|
+
acceptInvitation,
|
|
1530
|
+
// Axios integration
|
|
1531
|
+
registerAxios: (instance) => api.registerAxios(instance)
|
|
1514
1532
|
};
|
|
1515
1533
|
}
|
|
1516
1534
|
const useAuth$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
@@ -1524,7 +1542,7 @@ function resetAuthState() {
|
|
|
1524
1542
|
authInitialized = false;
|
|
1525
1543
|
}
|
|
1526
1544
|
function authGuard() {
|
|
1527
|
-
return async function guard(to, _from
|
|
1545
|
+
return async function guard(to, _from) {
|
|
1528
1546
|
const auth = useAuth();
|
|
1529
1547
|
const config = getRedirectConfig();
|
|
1530
1548
|
const requiresAuth = to.meta[config.authMetaKey];
|
|
@@ -1536,43 +1554,31 @@ function authGuard() {
|
|
|
1536
1554
|
}
|
|
1537
1555
|
const isAuthenticated = !!auth.user.value;
|
|
1538
1556
|
if (isAuthenticated && requiresNoAuth) {
|
|
1539
|
-
|
|
1540
|
-
return;
|
|
1557
|
+
return config.authenticatedRedirect;
|
|
1541
1558
|
}
|
|
1542
1559
|
if (!isAuthenticated && requiresAuth) {
|
|
1543
1560
|
const query = buildLoginQuery(to.fullPath, config);
|
|
1544
|
-
|
|
1561
|
+
return {
|
|
1545
1562
|
name: config.loginRoute,
|
|
1546
1563
|
query
|
|
1547
|
-
}
|
|
1548
|
-
return;
|
|
1564
|
+
};
|
|
1549
1565
|
}
|
|
1550
|
-
|
|
1566
|
+
return true;
|
|
1551
1567
|
} catch (error) {
|
|
1552
1568
|
console.error("[Auth Guard] Error:", error);
|
|
1553
|
-
|
|
1569
|
+
return true;
|
|
1554
1570
|
}
|
|
1555
1571
|
};
|
|
1556
1572
|
}
|
|
1557
1573
|
function composeGuards(guards) {
|
|
1558
|
-
return async (to, from
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
if (
|
|
1562
|
-
|
|
1563
|
-
return;
|
|
1574
|
+
return async (to, from) => {
|
|
1575
|
+
for (const guard of guards) {
|
|
1576
|
+
const result = await guard(to, from);
|
|
1577
|
+
if (result !== void 0 && result !== true) {
|
|
1578
|
+
return result;
|
|
1564
1579
|
}
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
await guard(to, from, (result) => {
|
|
1568
|
-
if (result !== void 0) {
|
|
1569
|
-
next(result);
|
|
1570
|
-
} else {
|
|
1571
|
-
runNextGuard();
|
|
1572
|
-
}
|
|
1573
|
-
});
|
|
1574
|
-
};
|
|
1575
|
-
await runNextGuard();
|
|
1580
|
+
}
|
|
1581
|
+
return true;
|
|
1576
1582
|
};
|
|
1577
1583
|
}
|
|
1578
1584
|
const router = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
@@ -1583,14 +1589,13 @@ const router = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProper
|
|
|
1583
1589
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
1584
1590
|
function createAuthGuard(config = {}) {
|
|
1585
1591
|
const { redirectTo = "/" } = config;
|
|
1586
|
-
return async (to,
|
|
1592
|
+
return async (to, _) => {
|
|
1587
1593
|
const { useAuth: useAuth2 } = await Promise.resolve().then(() => useAuth$1);
|
|
1588
1594
|
const { user } = useAuth2();
|
|
1589
1595
|
if (to.meta.requiresAuth === false && user.value) {
|
|
1590
|
-
|
|
1591
|
-
} else {
|
|
1592
|
-
next();
|
|
1596
|
+
return redirectTo;
|
|
1593
1597
|
}
|
|
1598
|
+
return true;
|
|
1594
1599
|
};
|
|
1595
1600
|
}
|
|
1596
1601
|
exports.AuthApi = AuthApi;
|
package/dist/index.mjs
CHANGED
|
@@ -62,14 +62,33 @@ class AuthApi {
|
|
|
62
62
|
constructor(baseURL = "") {
|
|
63
63
|
__publicField(this, "api");
|
|
64
64
|
__publicField(this, "currentTenantId", null);
|
|
65
|
+
__publicField(this, "externalAxiosInstances", /* @__PURE__ */ new Set());
|
|
65
66
|
this.api = createAxiosInstance(baseURL);
|
|
66
67
|
this.setupInterceptors();
|
|
67
68
|
}
|
|
68
69
|
/**
|
|
69
|
-
*
|
|
70
|
+
* Register an external axios instance so that tenant headers
|
|
71
|
+
* are automatically applied to it when setTenantId() is called.
|
|
72
|
+
*/
|
|
73
|
+
registerAxios(instance) {
|
|
74
|
+
this.externalAxiosInstances.add(instance);
|
|
75
|
+
if (this.currentTenantId !== null) {
|
|
76
|
+
instance.defaults.headers.common["X-Tenant-ID"] = this.currentTenantId;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Set the current tenant ID for multi-tenant requests.
|
|
81
|
+
* Also updates the header on any externally registered axios instances.
|
|
70
82
|
*/
|
|
71
83
|
setTenantId(tenantId) {
|
|
72
84
|
this.currentTenantId = tenantId;
|
|
85
|
+
for (const instance of this.externalAxiosInstances) {
|
|
86
|
+
if (tenantId !== null) {
|
|
87
|
+
instance.defaults.headers.common["X-Tenant-ID"] = tenantId;
|
|
88
|
+
} else {
|
|
89
|
+
delete instance.defaults.headers.common["X-Tenant-ID"];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
73
92
|
}
|
|
74
93
|
/**
|
|
75
94
|
* Get the current tenant ID
|
|
@@ -1039,11 +1058,11 @@ function createAuth(params) {
|
|
|
1039
1058
|
*
|
|
1040
1059
|
* // Manual guard control (for custom composition)
|
|
1041
1060
|
* auth.use(router, { guard: false })
|
|
1042
|
-
* router.beforeEach(async (to, from
|
|
1061
|
+
* router.beforeEach(async (to, from) => {
|
|
1043
1062
|
* // Custom logic first
|
|
1044
|
-
* if (!hasOrgAccess(to)) return
|
|
1063
|
+
* if (!hasOrgAccess(to)) return '/no-access'
|
|
1045
1064
|
* // Then run auth guard
|
|
1046
|
-
* return auth.routerGuard()(to, from
|
|
1065
|
+
* return auth.routerGuard()(to, from)
|
|
1047
1066
|
* })
|
|
1048
1067
|
* ```
|
|
1049
1068
|
*/
|
|
@@ -1072,11 +1091,11 @@ function createAuth(params) {
|
|
|
1072
1091
|
*/
|
|
1073
1092
|
routerGuard() {
|
|
1074
1093
|
if (cachedAuthGuard === null) {
|
|
1075
|
-
cachedAuthGuard = async (to, from
|
|
1094
|
+
cachedAuthGuard = async (to, from) => {
|
|
1076
1095
|
const { authGuard: authGuard2 } = await Promise.resolve().then(() => router);
|
|
1077
1096
|
const guard = authGuard2();
|
|
1078
1097
|
cachedAuthGuard = guard;
|
|
1079
|
-
return guard(to, from
|
|
1098
|
+
return guard(to, from);
|
|
1080
1099
|
};
|
|
1081
1100
|
}
|
|
1082
1101
|
return cachedAuthGuard;
|
|
@@ -1253,13 +1272,10 @@ function useAuth() {
|
|
|
1253
1272
|
try {
|
|
1254
1273
|
const { data } = await api.getTenants();
|
|
1255
1274
|
tenants.value = data;
|
|
1256
|
-
console.log("[Auth] Loaded tenants:", tenants.value);
|
|
1257
1275
|
if (currentTenant.value === null && tenants.value.length > 0) {
|
|
1258
1276
|
const firstActiveTenant = tenants.value.find((t) => t.status === "active");
|
|
1259
1277
|
if (firstActiveTenant !== void 0) {
|
|
1260
|
-
console.log("[Auth] Auto-selecting tenant:", firstActiveTenant.id);
|
|
1261
1278
|
setTenant(firstActiveTenant.id);
|
|
1262
|
-
console.log("[Auth] Tenant set. Current tenant ID in API:", api.getTenantId());
|
|
1263
1279
|
}
|
|
1264
1280
|
}
|
|
1265
1281
|
return tenants.value;
|
|
@@ -1508,7 +1524,9 @@ function useAuth() {
|
|
|
1508
1524
|
// Invitations
|
|
1509
1525
|
createInvitation,
|
|
1510
1526
|
getInvitation,
|
|
1511
|
-
acceptInvitation
|
|
1527
|
+
acceptInvitation,
|
|
1528
|
+
// Axios integration
|
|
1529
|
+
registerAxios: (instance) => api.registerAxios(instance)
|
|
1512
1530
|
};
|
|
1513
1531
|
}
|
|
1514
1532
|
const useAuth$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
@@ -1522,7 +1540,7 @@ function resetAuthState() {
|
|
|
1522
1540
|
authInitialized = false;
|
|
1523
1541
|
}
|
|
1524
1542
|
function authGuard() {
|
|
1525
|
-
return async function guard(to, _from
|
|
1543
|
+
return async function guard(to, _from) {
|
|
1526
1544
|
const auth = useAuth();
|
|
1527
1545
|
const config = getRedirectConfig();
|
|
1528
1546
|
const requiresAuth = to.meta[config.authMetaKey];
|
|
@@ -1534,43 +1552,31 @@ function authGuard() {
|
|
|
1534
1552
|
}
|
|
1535
1553
|
const isAuthenticated = !!auth.user.value;
|
|
1536
1554
|
if (isAuthenticated && requiresNoAuth) {
|
|
1537
|
-
|
|
1538
|
-
return;
|
|
1555
|
+
return config.authenticatedRedirect;
|
|
1539
1556
|
}
|
|
1540
1557
|
if (!isAuthenticated && requiresAuth) {
|
|
1541
1558
|
const query = buildLoginQuery(to.fullPath, config);
|
|
1542
|
-
|
|
1559
|
+
return {
|
|
1543
1560
|
name: config.loginRoute,
|
|
1544
1561
|
query
|
|
1545
|
-
}
|
|
1546
|
-
return;
|
|
1562
|
+
};
|
|
1547
1563
|
}
|
|
1548
|
-
|
|
1564
|
+
return true;
|
|
1549
1565
|
} catch (error) {
|
|
1550
1566
|
console.error("[Auth Guard] Error:", error);
|
|
1551
|
-
|
|
1567
|
+
return true;
|
|
1552
1568
|
}
|
|
1553
1569
|
};
|
|
1554
1570
|
}
|
|
1555
1571
|
function composeGuards(guards) {
|
|
1556
|
-
return async (to, from
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
if (
|
|
1560
|
-
|
|
1561
|
-
return;
|
|
1572
|
+
return async (to, from) => {
|
|
1573
|
+
for (const guard of guards) {
|
|
1574
|
+
const result = await guard(to, from);
|
|
1575
|
+
if (result !== void 0 && result !== true) {
|
|
1576
|
+
return result;
|
|
1562
1577
|
}
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
await guard(to, from, (result) => {
|
|
1566
|
-
if (result !== void 0) {
|
|
1567
|
-
next(result);
|
|
1568
|
-
} else {
|
|
1569
|
-
runNextGuard();
|
|
1570
|
-
}
|
|
1571
|
-
});
|
|
1572
|
-
};
|
|
1573
|
-
await runNextGuard();
|
|
1578
|
+
}
|
|
1579
|
+
return true;
|
|
1574
1580
|
};
|
|
1575
1581
|
}
|
|
1576
1582
|
const router = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
@@ -1581,14 +1587,13 @@ const router = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProper
|
|
|
1581
1587
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
1582
1588
|
function createAuthGuard(config = {}) {
|
|
1583
1589
|
const { redirectTo = "/" } = config;
|
|
1584
|
-
return async (to,
|
|
1590
|
+
return async (to, _) => {
|
|
1585
1591
|
const { useAuth: useAuth2 } = await Promise.resolve().then(() => useAuth$1);
|
|
1586
1592
|
const { user } = useAuth2();
|
|
1587
1593
|
if (to.meta.requiresAuth === false && user.value) {
|
|
1588
|
-
|
|
1589
|
-
} else {
|
|
1590
|
-
next();
|
|
1594
|
+
return redirectTo;
|
|
1591
1595
|
}
|
|
1596
|
+
return true;
|
|
1592
1597
|
};
|
|
1593
1598
|
}
|
|
1594
1599
|
export {
|
package/dist/router.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NavigationGuard,
|
|
1
|
+
import { NavigationGuard, RouteLocationNormalized, RouteLocationRaw } from 'vue-router';
|
|
2
2
|
/**
|
|
3
3
|
* Reset auth initialization state
|
|
4
4
|
* Useful for testing or app reload scenarios
|
|
@@ -19,10 +19,10 @@ export declare function resetAuthState(): void;
|
|
|
19
19
|
* router.beforeEach(authGuard())
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
|
-
export declare function authGuard(): (to: RouteLocationNormalized, _from: RouteLocationNormalized
|
|
22
|
+
export declare function authGuard(): (to: RouteLocationNormalized, _from: RouteLocationNormalized) => Promise<RouteLocationRaw | boolean | void>;
|
|
23
23
|
/**
|
|
24
24
|
* Compose multiple navigation guards into one
|
|
25
|
-
* Guards are executed in order, stopping at the first one that
|
|
25
|
+
* Guards are executed in order, stopping at the first one that returns a redirect
|
|
26
26
|
*
|
|
27
27
|
* @example
|
|
28
28
|
* ```ts
|
package/dist/routes.d.ts
CHANGED
package/dist/useAuth.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export interface AuthInstance extends ObjectPlugin<[]> {
|
|
|
25
25
|
use: (dependency: any, options?: {
|
|
26
26
|
guard?: boolean;
|
|
27
27
|
}) => AuthInstance;
|
|
28
|
-
routerGuard: () => (to: any, from: any
|
|
28
|
+
routerGuard: () => (to: any, from: any) => Promise<any>;
|
|
29
29
|
install: (app: App) => void;
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
@@ -218,5 +218,6 @@ export declare function useAuth(): {
|
|
|
218
218
|
last_name?: string | null;
|
|
219
219
|
}>;
|
|
220
220
|
acceptInvitation: (token: string, data?: AcceptInvitationRequest) => Promise<void>;
|
|
221
|
+
registerAxios: (instance: any) => void;
|
|
221
222
|
};
|
|
222
223
|
export {};
|
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -79,6 +79,7 @@ import { createAxiosInstance } from './utils'
|
|
|
79
79
|
export class AuthApi {
|
|
80
80
|
private api: AxiosInstance
|
|
81
81
|
private currentTenantId: string | null = null
|
|
82
|
+
private externalAxiosInstances: Set<AxiosInstance> = new Set()
|
|
82
83
|
|
|
83
84
|
constructor(baseURL: string = '') {
|
|
84
85
|
this.api = createAxiosInstance(baseURL)
|
|
@@ -86,10 +87,31 @@ export class AuthApi {
|
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
/**
|
|
89
|
-
*
|
|
90
|
+
* Register an external axios instance so that tenant headers
|
|
91
|
+
* are automatically applied to it when setTenantId() is called.
|
|
92
|
+
*/
|
|
93
|
+
registerAxios(instance: AxiosInstance) {
|
|
94
|
+
this.externalAxiosInstances.add(instance)
|
|
95
|
+
// Apply current tenant immediately if already set
|
|
96
|
+
if (this.currentTenantId !== null) {
|
|
97
|
+
instance.defaults.headers.common['X-Tenant-ID'] = this.currentTenantId
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Set the current tenant ID for multi-tenant requests.
|
|
103
|
+
* Also updates the header on any externally registered axios instances.
|
|
90
104
|
*/
|
|
91
105
|
setTenantId(tenantId: string | null) {
|
|
92
106
|
this.currentTenantId = tenantId
|
|
107
|
+
// Update all registered external axios instances
|
|
108
|
+
for (const instance of this.externalAxiosInstances) {
|
|
109
|
+
if (tenantId !== null) {
|
|
110
|
+
instance.defaults.headers.common['X-Tenant-ID'] = tenantId
|
|
111
|
+
} else {
|
|
112
|
+
delete instance.defaults.headers.common['X-Tenant-ID']
|
|
113
|
+
}
|
|
114
|
+
}
|
|
93
115
|
}
|
|
94
116
|
|
|
95
117
|
/**
|
package/src/router.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NavigationGuard,
|
|
1
|
+
import type { NavigationGuard, RouteLocationNormalized, RouteLocationRaw } from 'vue-router'
|
|
2
2
|
import { buildLoginQuery } from './redirect'
|
|
3
3
|
import { useAuth, getRedirectConfig } from './useAuth'
|
|
4
4
|
|
|
@@ -34,11 +34,9 @@ export function resetAuthState() {
|
|
|
34
34
|
*/
|
|
35
35
|
export function authGuard() {
|
|
36
36
|
return async function guard(
|
|
37
|
-
|
|
38
37
|
to: RouteLocationNormalized,
|
|
39
38
|
_from: RouteLocationNormalized,
|
|
40
|
-
|
|
41
|
-
): Promise<void> {
|
|
39
|
+
): Promise<RouteLocationRaw | boolean | void> {
|
|
42
40
|
const auth = useAuth()
|
|
43
41
|
const config = getRedirectConfig()
|
|
44
42
|
|
|
@@ -60,34 +58,32 @@ export function authGuard() {
|
|
|
60
58
|
|
|
61
59
|
// Redirect authenticated users away from auth pages
|
|
62
60
|
if (isAuthenticated && requiresNoAuth) {
|
|
63
|
-
|
|
64
|
-
return
|
|
61
|
+
return config.authenticatedRedirect
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
// Redirect unauthenticated users to login for protected pages
|
|
68
65
|
if (!isAuthenticated && requiresAuth) {
|
|
69
66
|
const query = buildLoginQuery(to.fullPath, config)
|
|
70
67
|
|
|
71
|
-
|
|
68
|
+
return {
|
|
72
69
|
name: config.loginRoute,
|
|
73
70
|
query,
|
|
74
|
-
}
|
|
75
|
-
return
|
|
71
|
+
}
|
|
76
72
|
}
|
|
77
73
|
|
|
78
74
|
// Allow navigation
|
|
79
|
-
|
|
75
|
+
return true
|
|
80
76
|
} catch (error) {
|
|
81
77
|
console.error('[Auth Guard] Error:', error)
|
|
82
78
|
// On error, allow navigation but log the issue
|
|
83
|
-
|
|
79
|
+
return true
|
|
84
80
|
}
|
|
85
81
|
}
|
|
86
82
|
}
|
|
87
83
|
|
|
88
84
|
/**
|
|
89
85
|
* Compose multiple navigation guards into one
|
|
90
|
-
* Guards are executed in order, stopping at the first one that
|
|
86
|
+
* Guards are executed in order, stopping at the first one that returns a redirect
|
|
91
87
|
*
|
|
92
88
|
* @example
|
|
93
89
|
* ```ts
|
|
@@ -99,31 +95,15 @@ export function authGuard() {
|
|
|
99
95
|
* ```
|
|
100
96
|
*/
|
|
101
97
|
export function composeGuards(guards: NavigationGuard[]): NavigationGuard {
|
|
102
|
-
return async (to, from
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
next()
|
|
109
|
-
return
|
|
98
|
+
return async (to, from) => {
|
|
99
|
+
for (const guard of guards) {
|
|
100
|
+
const result = await (guard as (to: RouteLocationNormalized, from: RouteLocationNormalized) => Promise<RouteLocationRaw | boolean | void>)(to, from)
|
|
101
|
+
if (result !== undefined && result !== true) {
|
|
102
|
+
// Guard blocked or redirected, stop here
|
|
103
|
+
return result
|
|
110
104
|
}
|
|
111
|
-
|
|
112
|
-
const guard = guards[guardIndex]
|
|
113
|
-
guardIndex++
|
|
114
|
-
|
|
115
|
-
// Run the current guard
|
|
116
|
-
await guard(to, from, (result?: any) => {
|
|
117
|
-
if (result !== undefined) {
|
|
118
|
-
// Guard blocked or redirected, stop here
|
|
119
|
-
next(result)
|
|
120
|
-
} else {
|
|
121
|
-
// Guard passed, run next guard
|
|
122
|
-
runNextGuard()
|
|
123
|
-
}
|
|
124
|
-
})
|
|
125
105
|
}
|
|
126
|
-
|
|
127
|
-
|
|
106
|
+
// All guards passed, allow navigation
|
|
107
|
+
return true
|
|
128
108
|
}
|
|
129
109
|
}
|
package/src/routes.ts
CHANGED
|
@@ -11,16 +11,15 @@
|
|
|
11
11
|
export function createAuthGuard(config: { redirectTo?: string } = {}) {
|
|
12
12
|
const { redirectTo = '/' } = config
|
|
13
13
|
|
|
14
|
-
return async (to: any,
|
|
14
|
+
return async (to: any, _: any) => {
|
|
15
15
|
// Import dynamically to avoid circular dependencies
|
|
16
16
|
const { useAuth } = await import('./useAuth')
|
|
17
17
|
const { user } = useAuth()
|
|
18
18
|
|
|
19
19
|
// If route doesn't require auth and user is authenticated, redirect
|
|
20
20
|
if (to.meta.requiresAuth === false && user.value) {
|
|
21
|
-
|
|
22
|
-
} else {
|
|
23
|
-
next()
|
|
21
|
+
return redirectTo
|
|
24
22
|
}
|
|
23
|
+
return true
|
|
25
24
|
}
|
|
26
25
|
}
|
package/src/useAuth.ts
CHANGED
|
@@ -69,7 +69,7 @@ export interface AuthInstance extends ObjectPlugin<[]> {
|
|
|
69
69
|
off: <K extends AuthState>(event: K, handler: AuthEventMap[K]) => void
|
|
70
70
|
removeAllListeners: <K extends AuthState>(event?: K) => void
|
|
71
71
|
use: (dependency: any, options?: { guard?: boolean }) => AuthInstance
|
|
72
|
-
routerGuard: () => (to: any, from: any
|
|
72
|
+
routerGuard: () => (to: any, from: any) => Promise<any>
|
|
73
73
|
install: (app: App) => void
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -139,11 +139,11 @@ export function createAuth(params: InitParams): AuthInstance {
|
|
|
139
139
|
*
|
|
140
140
|
* // Manual guard control (for custom composition)
|
|
141
141
|
* auth.use(router, { guard: false })
|
|
142
|
-
* router.beforeEach(async (to, from
|
|
142
|
+
* router.beforeEach(async (to, from) => {
|
|
143
143
|
* // Custom logic first
|
|
144
|
-
* if (!hasOrgAccess(to)) return
|
|
144
|
+
* if (!hasOrgAccess(to)) return '/no-access'
|
|
145
145
|
* // Then run auth guard
|
|
146
|
-
* return auth.routerGuard()(to, from
|
|
146
|
+
* return auth.routerGuard()(to, from)
|
|
147
147
|
* })
|
|
148
148
|
* ```
|
|
149
149
|
*/
|
|
@@ -177,12 +177,12 @@ export function createAuth(params: InitParams): AuthInstance {
|
|
|
177
177
|
routerGuard() {
|
|
178
178
|
// Return factory that lazily loads authGuard to avoid circular dependency
|
|
179
179
|
if (cachedAuthGuard === null) {
|
|
180
|
-
cachedAuthGuard = async (to: any, from: any
|
|
180
|
+
cachedAuthGuard = async (to: any, from: any) => {
|
|
181
181
|
const { authGuard } = await import('./router')
|
|
182
182
|
const guard = authGuard()
|
|
183
183
|
// Cache the actual guard for next time
|
|
184
184
|
cachedAuthGuard = guard
|
|
185
|
-
return guard(to, from
|
|
185
|
+
return guard(to, from)
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
return cachedAuthGuard
|
|
@@ -436,15 +436,11 @@ export function useAuth() {
|
|
|
436
436
|
const { data } = await api.getTenants()
|
|
437
437
|
tenants.value = data
|
|
438
438
|
|
|
439
|
-
console.log('[Auth] Loaded tenants:', tenants.value)
|
|
440
|
-
|
|
441
439
|
// Auto-select first tenant if none selected and tenants available
|
|
442
440
|
if (currentTenant.value === null && tenants.value.length > 0) {
|
|
443
441
|
const firstActiveTenant = tenants.value.find(t => t.status === 'active')
|
|
444
442
|
if (firstActiveTenant !== undefined) {
|
|
445
|
-
console.log('[Auth] Auto-selecting tenant:', firstActiveTenant.id)
|
|
446
443
|
setTenant(firstActiveTenant.id)
|
|
447
|
-
console.log('[Auth] Tenant set. Current tenant ID in API:', api.getTenantId())
|
|
448
444
|
}
|
|
449
445
|
}
|
|
450
446
|
|
|
@@ -787,5 +783,8 @@ export function useAuth() {
|
|
|
787
783
|
createInvitation,
|
|
788
784
|
getInvitation,
|
|
789
785
|
acceptInvitation,
|
|
786
|
+
|
|
787
|
+
// Axios integration
|
|
788
|
+
registerAxios: (instance: any) => api.registerAxios(instance),
|
|
790
789
|
}
|
|
791
790
|
}
|