@sanvika/auth 2.5.8 → 2.6.0
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.js +93 -40
- package/dist/server.js +14 -2
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// SanvikaAuthProvider.jsx
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
createContext,
|
|
6
|
+
useContext,
|
|
7
|
+
useEffect,
|
|
8
|
+
useState,
|
|
9
|
+
useCallback,
|
|
10
|
+
useMemo
|
|
11
|
+
} from "react";
|
|
5
12
|
|
|
6
13
|
// constants.js
|
|
7
14
|
var STORAGE_KEYS = {
|
|
@@ -14,29 +21,68 @@ var DEFAULT_AVATAR_SVG = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/200
|
|
|
14
21
|
import { jsx } from "react/jsx-runtime";
|
|
15
22
|
var S_AUTH_URL = "https://accounts.sanvikaproduction.com";
|
|
16
23
|
var SanvikaAuthContext = createContext(null);
|
|
24
|
+
function randomDeviceId() {
|
|
25
|
+
try {
|
|
26
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
27
|
+
return crypto.randomUUID();
|
|
28
|
+
}
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
return `device-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
32
|
+
}
|
|
33
|
+
function createDefaultWebPersistence() {
|
|
34
|
+
return {
|
|
35
|
+
getItem: async (key) => typeof localStorage !== "undefined" ? localStorage.getItem(key) : null,
|
|
36
|
+
setItem: async (key, value) => {
|
|
37
|
+
if (typeof localStorage !== "undefined") {
|
|
38
|
+
localStorage.setItem(key, value);
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
removeItem: async (key) => {
|
|
42
|
+
if (typeof localStorage !== "undefined") {
|
|
43
|
+
localStorage.removeItem(key);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
17
48
|
function SanvikaAuthProvider({
|
|
18
49
|
children,
|
|
19
50
|
clientId,
|
|
20
51
|
redirectUri,
|
|
21
|
-
dashboardPath
|
|
52
|
+
dashboardPath,
|
|
53
|
+
persistence: persistenceProp
|
|
22
54
|
}) {
|
|
55
|
+
const persistence = useMemo(() => {
|
|
56
|
+
return persistenceProp || createDefaultWebPersistence();
|
|
57
|
+
}, [persistenceProp]);
|
|
23
58
|
const [user, setUser] = useState(null);
|
|
24
59
|
const [accessToken, setToken] = useState(null);
|
|
25
60
|
const [loading, setLoading] = useState(true);
|
|
26
61
|
useEffect(() => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
62
|
+
let cancelled = false;
|
|
63
|
+
(async () => {
|
|
64
|
+
try {
|
|
65
|
+
const storedToken = await persistence.getItem(STORAGE_KEYS.ACCESS_TOKEN);
|
|
66
|
+
const storedUser = await persistence.getItem(STORAGE_KEYS.USER);
|
|
67
|
+
if (cancelled) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (storedToken && storedUser) {
|
|
71
|
+
setToken(storedToken);
|
|
72
|
+
setUser(JSON.parse(storedUser));
|
|
73
|
+
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
console.error("[SanvikaAuth] Failed to load session:", e);
|
|
76
|
+
} finally {
|
|
77
|
+
if (!cancelled) {
|
|
78
|
+
setLoading(false);
|
|
79
|
+
}
|
|
33
80
|
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}, []);
|
|
81
|
+
})();
|
|
82
|
+
return () => {
|
|
83
|
+
cancelled = true;
|
|
84
|
+
};
|
|
85
|
+
}, [persistence]);
|
|
40
86
|
const login = async ({ mobile, password, deviceId, deviceName }) => {
|
|
41
87
|
const response = await fetch(`${S_AUTH_URL}/api/auth/login`, {
|
|
42
88
|
method: "POST",
|
|
@@ -44,53 +90,61 @@ function SanvikaAuthProvider({
|
|
|
44
90
|
body: JSON.stringify({
|
|
45
91
|
mobile,
|
|
46
92
|
password,
|
|
47
|
-
deviceId: deviceId ||
|
|
93
|
+
deviceId: deviceId || randomDeviceId(),
|
|
48
94
|
deviceName: deviceName || "Browser"
|
|
49
95
|
})
|
|
50
96
|
});
|
|
51
97
|
const data = await response.json();
|
|
52
|
-
if (!data.success)
|
|
53
|
-
|
|
54
|
-
|
|
98
|
+
if (!data.success) {
|
|
99
|
+
throw new Error(data.error || data.message || "Login failed");
|
|
100
|
+
}
|
|
101
|
+
await persistence.setItem(STORAGE_KEYS.ACCESS_TOKEN, data.accessToken);
|
|
102
|
+
await persistence.setItem(STORAGE_KEYS.USER, JSON.stringify(data.user));
|
|
55
103
|
setToken(data.accessToken);
|
|
56
104
|
setUser(data.user);
|
|
57
105
|
return data;
|
|
58
106
|
};
|
|
59
|
-
const setAuth = (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
107
|
+
const setAuth = useCallback(
|
|
108
|
+
(token, userData) => {
|
|
109
|
+
setToken(token);
|
|
110
|
+
setUser(userData);
|
|
111
|
+
void persistence.setItem(STORAGE_KEYS.ACCESS_TOKEN, token).catch((e) => console.error("[SanvikaAuth] setAuth token persist:", e));
|
|
112
|
+
void persistence.setItem(STORAGE_KEYS.USER, JSON.stringify(userData)).catch((e) => console.error("[SanvikaAuth] setAuth user persist:", e));
|
|
113
|
+
},
|
|
114
|
+
[persistence]
|
|
115
|
+
);
|
|
65
116
|
const logout = async () => {
|
|
66
117
|
try {
|
|
67
118
|
await fetch(`${S_AUTH_URL}/api/auth/logout`, {
|
|
68
119
|
method: "POST",
|
|
69
120
|
headers: {
|
|
70
121
|
"Content-Type": "application/json",
|
|
71
|
-
Authorization: `Bearer ${accessToken}`
|
|
122
|
+
...accessToken ? { Authorization: `Bearer ${accessToken}` } : {}
|
|
72
123
|
}
|
|
73
124
|
});
|
|
74
125
|
} catch (e) {
|
|
75
126
|
console.error("[SanvikaAuth] Logout API error:", e);
|
|
76
127
|
} finally {
|
|
77
|
-
|
|
78
|
-
|
|
128
|
+
await persistence.removeItem(STORAGE_KEYS.ACCESS_TOKEN);
|
|
129
|
+
await persistence.removeItem(STORAGE_KEYS.USER);
|
|
79
130
|
setToken(null);
|
|
80
131
|
setUser(null);
|
|
81
132
|
}
|
|
82
133
|
};
|
|
83
|
-
const authFetch = useCallback(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
134
|
+
const authFetch = useCallback(
|
|
135
|
+
async (url, opts = {}) => {
|
|
136
|
+
const currentToken = await persistence.getItem(STORAGE_KEYS.ACCESS_TOKEN);
|
|
137
|
+
const headers = {
|
|
138
|
+
"Content-Type": "application/json",
|
|
139
|
+
...currentToken && { Authorization: `Bearer ${currentToken}` },
|
|
140
|
+
...opts.headers
|
|
141
|
+
};
|
|
142
|
+
const res = await fetch(url, { ...opts, headers });
|
|
143
|
+
const data = await res.json();
|
|
144
|
+
return { data, success: data.success };
|
|
145
|
+
},
|
|
146
|
+
[persistence]
|
|
147
|
+
);
|
|
94
148
|
const value = {
|
|
95
149
|
user,
|
|
96
150
|
accessToken,
|
|
@@ -109,8 +163,7 @@ function SanvikaAuthProvider({
|
|
|
109
163
|
return /* @__PURE__ */ jsx(SanvikaAuthContext.Provider, { value, children });
|
|
110
164
|
}
|
|
111
165
|
function useSanvikaAuth() {
|
|
112
|
-
|
|
113
|
-
return ctx;
|
|
166
|
+
return useContext(SanvikaAuthContext);
|
|
114
167
|
}
|
|
115
168
|
|
|
116
169
|
// SanvikaAccountButton.jsx
|
package/dist/server.js
CHANGED
|
@@ -302,6 +302,17 @@ async function authenticateAdmin(request) {
|
|
|
302
302
|
return _buildUnauthorized("Invalid or expired token.", "INVALID_TOKEN");
|
|
303
303
|
}
|
|
304
304
|
const uid = saPayload.sub;
|
|
305
|
+
const jwtRole = saPayload.role;
|
|
306
|
+
if (jwtRole === "superadmin" && uid) {
|
|
307
|
+
const adminData2 = {
|
|
308
|
+
uid,
|
|
309
|
+
adminId: null,
|
|
310
|
+
role: "superadmin",
|
|
311
|
+
mobile: saPayload.mobile || null
|
|
312
|
+
};
|
|
313
|
+
_adminCache.set(cacheKey, { adminData: adminData2, expires: Date.now() + _ADMIN_CACHE_TTL });
|
|
314
|
+
return { success: true, admin: adminData2 };
|
|
315
|
+
}
|
|
305
316
|
const admin = await verifyAdminFromAuth(uid);
|
|
306
317
|
if (!admin) {
|
|
307
318
|
return _buildUnauthorized("Unauthorized or admin account not found.", "ADMIN_NOT_FOUND");
|
|
@@ -309,13 +320,14 @@ async function authenticateAdmin(request) {
|
|
|
309
320
|
if (admin.isBlocked) {
|
|
310
321
|
return _buildForbidden("Admin account is blocked.", "ADMIN_BLOCKED");
|
|
311
322
|
}
|
|
312
|
-
|
|
323
|
+
const effectiveRole = admin.role || (jwtRole && ["admin", "superadmin", "moderator"].includes(jwtRole) ? jwtRole : null);
|
|
324
|
+
if (!effectiveRole || !["admin", "superadmin", "moderator"].includes(effectiveRole)) {
|
|
313
325
|
return _buildForbidden("Invalid admin role.", "INVALID_ADMIN_ROLE");
|
|
314
326
|
}
|
|
315
327
|
const adminData = {
|
|
316
328
|
uid: admin.uid,
|
|
317
329
|
adminId: admin.adminId,
|
|
318
|
-
role:
|
|
330
|
+
role: effectiveRole,
|
|
319
331
|
mobile: admin.mobile
|
|
320
332
|
};
|
|
321
333
|
_adminCache.set(cacheKey, { adminData, expires: Date.now() + _ADMIN_CACHE_TTL });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanvika/auth",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Sanvika Auth SDK — React components/hooks + server-side token verification and user proxy",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
"next": ">=16.2.1",
|
|
24
24
|
"react": ">=18"
|
|
25
25
|
},
|
|
26
|
+
"peerDependenciesMeta": {
|
|
27
|
+
"next": {
|
|
28
|
+
"optional": true
|
|
29
|
+
}
|
|
30
|
+
},
|
|
26
31
|
"devDependencies": {
|
|
27
32
|
"tsup": "^8.5.1"
|
|
28
33
|
},
|