@sanvika/auth 2.8.0 → 2.9.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 +184 -23
- package/package.json +7 -6
package/dist/index.js
CHANGED
|
@@ -17,10 +17,9 @@ var STORAGE_KEYS = {
|
|
|
17
17
|
};
|
|
18
18
|
var DEFAULT_AVATAR_SVG = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Ccircle cx='20' cy='20' r='20' fill='%23e5e7eb'/%3E%3Ccircle cx='20' cy='15' r='7' fill='%23adb5bd'/%3E%3Cellipse cx='20' cy='35' rx='12' ry='8' fill='%23adb5bd'/%3E%3C/svg%3E`;
|
|
19
19
|
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
var
|
|
23
|
-
var SanvikaAuthContext = createContext(null);
|
|
20
|
+
// authFlow.js
|
|
21
|
+
var DEFAULT_AUTH_URL = "https://auth.sanvikaproduction.com";
|
|
22
|
+
var DEVICE_ID_STORAGE_KEY = "sanvika_deviceId";
|
|
24
23
|
function randomDeviceId() {
|
|
25
24
|
try {
|
|
26
25
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
@@ -30,6 +29,121 @@ function randomDeviceId() {
|
|
|
30
29
|
}
|
|
31
30
|
return `device-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
32
31
|
}
|
|
32
|
+
function getOrCreateWebDeviceId() {
|
|
33
|
+
var _a, _b;
|
|
34
|
+
if (typeof window === "undefined") return randomDeviceId();
|
|
35
|
+
let deviceId = localStorage.getItem(DEVICE_ID_STORAGE_KEY);
|
|
36
|
+
if (!deviceId) {
|
|
37
|
+
const raw = `${navigator.userAgent}|${((_a = window.screen) == null ? void 0 : _a.width) ?? 0}x${((_b = window.screen) == null ? void 0 : _b.height) ?? 0}|${navigator.language}`;
|
|
38
|
+
let hash = 0;
|
|
39
|
+
for (let i = 0; i < raw.length; i++) {
|
|
40
|
+
hash = Math.imul(31, hash) + raw.charCodeAt(i) | 0;
|
|
41
|
+
}
|
|
42
|
+
deviceId = `d_${Math.abs(hash).toString(36)}_${Date.now().toString(36)}`;
|
|
43
|
+
localStorage.setItem(DEVICE_ID_STORAGE_KEY, deviceId);
|
|
44
|
+
}
|
|
45
|
+
return deviceId;
|
|
46
|
+
}
|
|
47
|
+
async function checkMobile({
|
|
48
|
+
authBaseUrl = DEFAULT_AUTH_URL,
|
|
49
|
+
mobile,
|
|
50
|
+
deviceId,
|
|
51
|
+
clientId,
|
|
52
|
+
callbackUrl
|
|
53
|
+
}) {
|
|
54
|
+
const res = await fetch(`${authBaseUrl}/api/auth/check-mobile`, {
|
|
55
|
+
method: "POST",
|
|
56
|
+
headers: { "Content-Type": "application/json" },
|
|
57
|
+
body: JSON.stringify({
|
|
58
|
+
mobile: String(mobile).trim(),
|
|
59
|
+
deviceId,
|
|
60
|
+
clientId,
|
|
61
|
+
...callbackUrl ? { callbackUrl } : {}
|
|
62
|
+
})
|
|
63
|
+
});
|
|
64
|
+
const data = await res.json();
|
|
65
|
+
if (!data.success) {
|
|
66
|
+
const err = new Error(data.message || data.error || "Check mobile failed");
|
|
67
|
+
err.code = data.error;
|
|
68
|
+
throw err;
|
|
69
|
+
}
|
|
70
|
+
return data;
|
|
71
|
+
}
|
|
72
|
+
async function postLogin({
|
|
73
|
+
authBaseUrl = DEFAULT_AUTH_URL,
|
|
74
|
+
mobile,
|
|
75
|
+
password,
|
|
76
|
+
deviceId,
|
|
77
|
+
userAgent,
|
|
78
|
+
clientId,
|
|
79
|
+
deviceName
|
|
80
|
+
}) {
|
|
81
|
+
const body = {
|
|
82
|
+
mobile: String(mobile).trim(),
|
|
83
|
+
deviceId,
|
|
84
|
+
clientId,
|
|
85
|
+
userAgent: userAgent || deviceName || "Sanvika App"
|
|
86
|
+
};
|
|
87
|
+
if (password) {
|
|
88
|
+
body.password = password;
|
|
89
|
+
}
|
|
90
|
+
const res = await fetch(`${authBaseUrl}/api/auth/login`, {
|
|
91
|
+
method: "POST",
|
|
92
|
+
headers: { "Content-Type": "application/json" },
|
|
93
|
+
body: JSON.stringify(body)
|
|
94
|
+
});
|
|
95
|
+
const data = await res.json();
|
|
96
|
+
if (!data.success) {
|
|
97
|
+
const err = new Error(data.error || data.message || "Login failed");
|
|
98
|
+
err.code = data.error;
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
return data;
|
|
102
|
+
}
|
|
103
|
+
async function deviceAwareLogin({
|
|
104
|
+
authBaseUrl = DEFAULT_AUTH_URL,
|
|
105
|
+
mobile,
|
|
106
|
+
password,
|
|
107
|
+
deviceId,
|
|
108
|
+
userAgent,
|
|
109
|
+
deviceName,
|
|
110
|
+
clientId,
|
|
111
|
+
callbackUrl,
|
|
112
|
+
resolveDeviceId
|
|
113
|
+
}) {
|
|
114
|
+
const resolvedDeviceId = deviceId || (typeof resolveDeviceId === "function" ? await resolveDeviceId() : getOrCreateWebDeviceId());
|
|
115
|
+
const check = await checkMobile({
|
|
116
|
+
authBaseUrl,
|
|
117
|
+
mobile,
|
|
118
|
+
deviceId: resolvedDeviceId,
|
|
119
|
+
clientId,
|
|
120
|
+
callbackUrl
|
|
121
|
+
});
|
|
122
|
+
if (!check.exists) {
|
|
123
|
+
const err = new Error("Mobile number not registered.");
|
|
124
|
+
err.code = "USER_NOT_REGISTERED";
|
|
125
|
+
throw err;
|
|
126
|
+
}
|
|
127
|
+
if (!check.isKnownDevice && !password) {
|
|
128
|
+
const err = new Error("Password is required for this device.");
|
|
129
|
+
err.code = "MISSING_PASSWORD";
|
|
130
|
+
err.requiresPassword = true;
|
|
131
|
+
throw err;
|
|
132
|
+
}
|
|
133
|
+
return postLogin({
|
|
134
|
+
authBaseUrl,
|
|
135
|
+
mobile,
|
|
136
|
+
password: check.isKnownDevice ? void 0 : password,
|
|
137
|
+
deviceId: resolvedDeviceId,
|
|
138
|
+
userAgent,
|
|
139
|
+
deviceName,
|
|
140
|
+
clientId
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// SanvikaAuthProvider.jsx
|
|
145
|
+
import { jsx } from "react/jsx-runtime";
|
|
146
|
+
var SanvikaAuthContext = createContext(null);
|
|
33
147
|
function createDefaultWebPersistence() {
|
|
34
148
|
return {
|
|
35
149
|
getItem: async (key) => typeof localStorage !== "undefined" ? localStorage.getItem(key) : null,
|
|
@@ -50,6 +164,7 @@ function SanvikaAuthProvider({
|
|
|
50
164
|
clientId,
|
|
51
165
|
redirectUri,
|
|
52
166
|
dashboardPath,
|
|
167
|
+
authBaseUrl = DEFAULT_AUTH_URL,
|
|
53
168
|
persistence: persistenceProp
|
|
54
169
|
}) {
|
|
55
170
|
const persistence = useMemo(() => {
|
|
@@ -83,25 +198,62 @@ function SanvikaAuthProvider({
|
|
|
83
198
|
cancelled = true;
|
|
84
199
|
};
|
|
85
200
|
}, [persistence]);
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
201
|
+
const persistSession = useCallback(
|
|
202
|
+
async (token, userData) => {
|
|
203
|
+
await persistence.setItem(STORAGE_KEYS.ACCESS_TOKEN, token);
|
|
204
|
+
await persistence.setItem(STORAGE_KEYS.USER, JSON.stringify(userData));
|
|
205
|
+
setToken(token);
|
|
206
|
+
setUser(userData);
|
|
207
|
+
},
|
|
208
|
+
[persistence]
|
|
209
|
+
);
|
|
210
|
+
const checkMobile2 = useCallback(
|
|
211
|
+
async ({ mobile, deviceId }) => {
|
|
212
|
+
const resolvedDeviceId = deviceId || getOrCreateWebDeviceId();
|
|
213
|
+
return checkMobile({
|
|
214
|
+
authBaseUrl,
|
|
215
|
+
mobile,
|
|
216
|
+
deviceId: resolvedDeviceId,
|
|
217
|
+
clientId,
|
|
218
|
+
callbackUrl: redirectUri
|
|
219
|
+
});
|
|
220
|
+
},
|
|
221
|
+
[authBaseUrl, clientId, redirectUri]
|
|
222
|
+
);
|
|
223
|
+
const login = async ({
|
|
224
|
+
mobile,
|
|
225
|
+
password,
|
|
226
|
+
deviceId,
|
|
227
|
+
deviceName,
|
|
228
|
+
userAgent,
|
|
229
|
+
skipDeviceCheck = false
|
|
230
|
+
}) => {
|
|
231
|
+
const resolveDeviceId = async () => deviceId || getOrCreateWebDeviceId();
|
|
232
|
+
let data;
|
|
233
|
+
if (skipDeviceCheck) {
|
|
234
|
+
data = await postLogin({
|
|
235
|
+
authBaseUrl,
|
|
91
236
|
mobile,
|
|
92
237
|
password,
|
|
93
238
|
deviceId: deviceId || randomDeviceId(),
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
239
|
+
userAgent: userAgent || deviceName,
|
|
240
|
+
clientId,
|
|
241
|
+
deviceName
|
|
242
|
+
});
|
|
243
|
+
} else {
|
|
244
|
+
data = await deviceAwareLogin({
|
|
245
|
+
authBaseUrl,
|
|
246
|
+
mobile,
|
|
247
|
+
password,
|
|
248
|
+
deviceId,
|
|
249
|
+
userAgent: userAgent || (typeof navigator !== "undefined" ? navigator.userAgent : void 0),
|
|
250
|
+
deviceName,
|
|
251
|
+
clientId,
|
|
252
|
+
callbackUrl: redirectUri,
|
|
253
|
+
resolveDeviceId
|
|
254
|
+
});
|
|
100
255
|
}
|
|
101
|
-
await
|
|
102
|
-
await persistence.setItem(STORAGE_KEYS.USER, JSON.stringify(data.user));
|
|
103
|
-
setToken(data.accessToken);
|
|
104
|
-
setUser(data.user);
|
|
256
|
+
await persistSession(data.accessToken, data.user);
|
|
105
257
|
return data;
|
|
106
258
|
};
|
|
107
259
|
const setAuth = useCallback(
|
|
@@ -115,7 +267,7 @@ function SanvikaAuthProvider({
|
|
|
115
267
|
);
|
|
116
268
|
const logout = async () => {
|
|
117
269
|
try {
|
|
118
|
-
await fetch(`${
|
|
270
|
+
await fetch(`${authBaseUrl}/api/auth/logout`, {
|
|
119
271
|
method: "POST",
|
|
120
272
|
headers: {
|
|
121
273
|
"Content-Type": "application/json",
|
|
@@ -153,12 +305,14 @@ function SanvikaAuthProvider({
|
|
|
153
305
|
isAuthenticated: !!user,
|
|
154
306
|
isLoggedIn: !!user,
|
|
155
307
|
login,
|
|
308
|
+
checkMobile: checkMobile2,
|
|
156
309
|
logout,
|
|
157
310
|
setAuth,
|
|
158
311
|
authFetch,
|
|
159
312
|
clientId,
|
|
160
313
|
redirectUri,
|
|
161
|
-
dashboardPath
|
|
314
|
+
dashboardPath,
|
|
315
|
+
authBaseUrl
|
|
162
316
|
};
|
|
163
317
|
return /* @__PURE__ */ jsx(SanvikaAuthContext.Provider, { value, children });
|
|
164
318
|
}
|
|
@@ -196,7 +350,7 @@ styleInject("@keyframes snvk-shimmer {\n 0% {\n background-position: 200% 0;
|
|
|
196
350
|
|
|
197
351
|
// SanvikaAccountButton.jsx
|
|
198
352
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
199
|
-
var
|
|
353
|
+
var S_AUTH_URL = "https://auth.sanvikaproduction.com";
|
|
200
354
|
var SanvikaAccountButtonErrorBoundary = class extends Component {
|
|
201
355
|
constructor(props) {
|
|
202
356
|
super(props);
|
|
@@ -329,7 +483,7 @@ function SanvikaAccountButtonContent({
|
|
|
329
483
|
if (!isAuthenticated || loading) {
|
|
330
484
|
const { clientId } = auth;
|
|
331
485
|
const redirectUri = auth.redirectUri || (typeof window !== "undefined" && window.location ? window.location.origin + "/auth/callback" : "");
|
|
332
|
-
const authorizeUrl = clientId && redirectUri ? `${
|
|
486
|
+
const authorizeUrl = clientId && redirectUri ? `${S_AUTH_URL}/authorize?client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(redirectUri)}` : `${S_AUTH_URL}/authorize`;
|
|
333
487
|
return /* @__PURE__ */ jsxs(
|
|
334
488
|
"button",
|
|
335
489
|
{
|
|
@@ -687,11 +841,18 @@ function SanvikaAdminLogin({
|
|
|
687
841
|
] }) });
|
|
688
842
|
}
|
|
689
843
|
export {
|
|
844
|
+
DEFAULT_AUTH_URL,
|
|
690
845
|
DEFAULT_AVATAR_SVG,
|
|
846
|
+
DEVICE_ID_STORAGE_KEY,
|
|
691
847
|
STORAGE_KEYS,
|
|
692
848
|
SanvikaAccountButton,
|
|
693
849
|
SanvikaAdminLogin,
|
|
694
850
|
SanvikaAuthContext,
|
|
695
851
|
SanvikaAuthProvider,
|
|
852
|
+
checkMobile,
|
|
853
|
+
deviceAwareLogin,
|
|
854
|
+
getOrCreateWebDeviceId,
|
|
855
|
+
postLogin,
|
|
856
|
+
randomDeviceId,
|
|
696
857
|
useSanvikaAuth
|
|
697
858
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanvika/auth",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.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",
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
"dist"
|
|
14
14
|
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
15
19
|
"publishConfig": {
|
|
16
20
|
"access": "public"
|
|
17
21
|
},
|
|
@@ -35,8 +39,5 @@
|
|
|
35
39
|
"nextjs"
|
|
36
40
|
],
|
|
37
41
|
"author": "sanvika",
|
|
38
|
-
"license": "MIT"
|
|
39
|
-
|
|
40
|
-
"build": "tsup"
|
|
41
|
-
}
|
|
42
|
-
}
|
|
42
|
+
"license": "MIT"
|
|
43
|
+
}
|