@vaiftech/auth 1.0.4 → 1.1.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/README.md +391 -69
- package/dist/chunk-VKUCT6DW.mjs +2 -0
- package/dist/{client-28ISGmu6.d.mts → client-DYj4LiUx.d.mts} +10 -0
- package/dist/{client-28ISGmu6.d.ts → client-DYj4LiUx.d.ts} +10 -0
- package/dist/index.d.mts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +2 -1
- package/dist/index.mjs +1 -1
- package/dist/react.d.mts +15 -3
- package/dist/react.d.ts +15 -3
- package/dist/react.js +1 -1
- package/dist/react.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-JF55RF72.mjs +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# @vaiftech/auth
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@vaiftech/auth)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
|
|
7
|
+
Comprehensive authentication SDK for VAIF Studio - session management, OAuth, MFA, magic links, and React hooks.
|
|
4
8
|
|
|
5
9
|
## Installation
|
|
6
10
|
|
|
@@ -30,13 +34,13 @@ const { session, user } = await auth.signUp({
|
|
|
30
34
|
});
|
|
31
35
|
|
|
32
36
|
// Sign in
|
|
33
|
-
const
|
|
37
|
+
const result = await auth.signInWithPassword({
|
|
34
38
|
email: 'user@example.com',
|
|
35
39
|
password: 'secure-password',
|
|
36
40
|
});
|
|
37
41
|
|
|
38
|
-
// Listen to auth changes
|
|
39
|
-
auth.onAuthStateChange((event) => {
|
|
42
|
+
// Listen to auth state changes
|
|
43
|
+
const { unsubscribe } = auth.onAuthStateChange((event) => {
|
|
40
44
|
console.log('Auth event:', event.event);
|
|
41
45
|
console.log('User:', event.session?.user);
|
|
42
46
|
});
|
|
@@ -47,15 +51,202 @@ await auth.signOut();
|
|
|
47
51
|
|
|
48
52
|
## Features
|
|
49
53
|
|
|
50
|
-
- **
|
|
51
|
-
- **
|
|
52
|
-
- **
|
|
53
|
-
- **
|
|
54
|
-
- **
|
|
55
|
-
- **
|
|
56
|
-
- **
|
|
54
|
+
- **Email/Password** - Sign up, sign in, password reset
|
|
55
|
+
- **OAuth** - Google, GitHub, Microsoft, Apple, Discord, Slack, Twitter, Facebook, LinkedIn, Spotify, Twitch, Notion, Figma, Zoom
|
|
56
|
+
- **Magic Link** - Passwordless email authentication
|
|
57
|
+
- **OTP** - One-time password via SMS, WhatsApp, or email
|
|
58
|
+
- **Anonymous Auth** - Guest sessions with optional conversion
|
|
59
|
+
- **SSO** - SAML and OIDC enterprise single sign-on
|
|
60
|
+
- **MFA** - TOTP, SMS, and email second factors with backup codes
|
|
61
|
+
- **Session Management** - Auto-refresh, multi-tab sync, session listing/revocation
|
|
62
|
+
- **React Integration** - Provider, hooks, and SSR support
|
|
63
|
+
- **Storage Adapters** - localStorage, sessionStorage, cookies, memory, or custom
|
|
64
|
+
- **PKCE Flow** - Secure OAuth with code challenge
|
|
65
|
+
|
|
66
|
+
## Authentication Methods
|
|
67
|
+
|
|
68
|
+
### Email/Password
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// Sign up
|
|
72
|
+
const { session, user } = await auth.signUp({
|
|
73
|
+
email: 'user@example.com',
|
|
74
|
+
password: 'secure-password',
|
|
75
|
+
name: 'Jane Doe',
|
|
76
|
+
metadata: { role: 'developer' },
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Sign in
|
|
80
|
+
const result = await auth.signInWithPassword({
|
|
81
|
+
email: 'user@example.com',
|
|
82
|
+
password: 'secure-password',
|
|
83
|
+
rememberMe: true,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Handle MFA challenge if enabled
|
|
87
|
+
if ('mfaRequired' in result) {
|
|
88
|
+
const session = await auth.verifyMFAChallenge(result.mfaToken, '123456');
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### OAuth
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// Redirect to OAuth provider
|
|
96
|
+
await auth.signInWithOAuth({
|
|
97
|
+
provider: 'google',
|
|
98
|
+
redirectTo: 'https://myapp.com/auth/callback',
|
|
99
|
+
scopes: ['email', 'profile'],
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Link additional provider to existing account
|
|
103
|
+
await auth.linkIdentity('github', { redirectTo: 'https://myapp.com/settings' });
|
|
104
|
+
|
|
105
|
+
// Get linked identities
|
|
106
|
+
const identities = await auth.getUserIdentities();
|
|
107
|
+
|
|
108
|
+
// Unlink provider
|
|
109
|
+
await auth.unlinkIdentity('github');
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Magic Link
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
await auth.signInWithMagicLink({
|
|
116
|
+
email: 'user@example.com',
|
|
117
|
+
redirectTo: 'https://myapp.com/dashboard',
|
|
118
|
+
shouldCreateUser: true,
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### OTP (One-Time Password)
|
|
57
123
|
|
|
58
|
-
|
|
124
|
+
```typescript
|
|
125
|
+
// Send OTP
|
|
126
|
+
await auth.signInWithOTP({
|
|
127
|
+
phone: '+1234567890',
|
|
128
|
+
channel: 'sms', // 'sms' | 'whatsapp' | 'email'
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Verify OTP
|
|
132
|
+
const { session, user } = await auth.verifyOTP({
|
|
133
|
+
phone: '+1234567890',
|
|
134
|
+
token: '123456',
|
|
135
|
+
type: 'magiclink',
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Anonymous Auth
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
const { session, user } = await auth.signInAnonymously({
|
|
143
|
+
metadata: { source: 'landing-page' },
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### SSO (Enterprise)
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
await auth.signInWithSSO({
|
|
151
|
+
domain: 'acme.com',
|
|
152
|
+
redirectTo: 'https://myapp.com/auth/callback',
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## MFA (Multi-Factor Authentication)
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// List enrolled factors
|
|
160
|
+
const factors = await auth.listMFAFactors();
|
|
161
|
+
|
|
162
|
+
// Enroll TOTP
|
|
163
|
+
const { qrCode, secret, backupCodes } = await auth.enrollMFA({
|
|
164
|
+
type: 'totp',
|
|
165
|
+
friendlyName: 'My Authenticator',
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Verify and activate factor
|
|
169
|
+
await auth.verifyMFA({ factorId: factor.id, code: '123456' });
|
|
170
|
+
|
|
171
|
+
// Regenerate backup codes
|
|
172
|
+
const { backupCodes } = await auth.regenerateBackupCodes();
|
|
173
|
+
|
|
174
|
+
// Unenroll factor
|
|
175
|
+
await auth.unenrollMFA(factorId, '123456');
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Session Management
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
// Get current session and user
|
|
182
|
+
const session = await auth.getSession();
|
|
183
|
+
const user = await auth.getUser();
|
|
184
|
+
|
|
185
|
+
// Manually set session (SSR)
|
|
186
|
+
await auth.setSession(accessToken, refreshToken);
|
|
187
|
+
|
|
188
|
+
// Refresh session
|
|
189
|
+
await auth.refreshSession();
|
|
190
|
+
|
|
191
|
+
// List all active sessions
|
|
192
|
+
const sessions = await auth.listSessions();
|
|
193
|
+
|
|
194
|
+
// Revoke a specific session
|
|
195
|
+
await auth.revokeSession(sessionId);
|
|
196
|
+
|
|
197
|
+
// Revoke all sessions except current
|
|
198
|
+
await auth.revokeOtherSessions();
|
|
199
|
+
|
|
200
|
+
// Sign out from all devices
|
|
201
|
+
await auth.signOutAll();
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Password Management
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
// Request password reset email
|
|
208
|
+
await auth.resetPasswordForEmail({
|
|
209
|
+
email: 'user@example.com',
|
|
210
|
+
redirectTo: 'https://myapp.com/reset-password',
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// Update password (authenticated)
|
|
214
|
+
await auth.updatePassword({
|
|
215
|
+
currentPassword: 'old-password',
|
|
216
|
+
newPassword: 'new-password',
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Set password with recovery token
|
|
220
|
+
await auth.setPassword({
|
|
221
|
+
token: 'recovery-token-from-email',
|
|
222
|
+
password: 'new-password',
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## User Management
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
// Update user profile
|
|
230
|
+
const user = await auth.updateUser({
|
|
231
|
+
name: 'Updated Name',
|
|
232
|
+
avatarUrl: 'https://example.com/avatar.jpg',
|
|
233
|
+
metadata: { theme: 'dark' },
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Resend email verification
|
|
237
|
+
await auth.resendEmailVerification({
|
|
238
|
+
redirectTo: 'https://myapp.com/verify',
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Verify email
|
|
242
|
+
await auth.verifyEmail(token);
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## React Integration
|
|
246
|
+
|
|
247
|
+
The package includes a complete React integration via the `@vaiftech/auth/react` subpath.
|
|
248
|
+
|
|
249
|
+
### AuthProvider
|
|
59
250
|
|
|
60
251
|
```tsx
|
|
61
252
|
import { AuthProvider, useAuth } from '@vaiftech/auth/react';
|
|
@@ -68,11 +259,41 @@ function App() {
|
|
|
68
259
|
);
|
|
69
260
|
}
|
|
70
261
|
|
|
262
|
+
// Or pass a pre-configured client
|
|
263
|
+
import { createAuthClient } from '@vaiftech/auth';
|
|
264
|
+
|
|
265
|
+
const client = createAuthClient({ url: '...', apiKey: '...' });
|
|
266
|
+
|
|
267
|
+
function App() {
|
|
268
|
+
return (
|
|
269
|
+
<AuthProvider client={client}>
|
|
270
|
+
<YourApp />
|
|
271
|
+
</AuthProvider>
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### useAuth
|
|
277
|
+
|
|
278
|
+
```tsx
|
|
71
279
|
function LoginPage() {
|
|
72
|
-
const {
|
|
280
|
+
const {
|
|
281
|
+
user,
|
|
282
|
+
session,
|
|
283
|
+
isLoading,
|
|
284
|
+
isAuthenticated,
|
|
285
|
+
error,
|
|
286
|
+
signUp,
|
|
287
|
+
signInWithPassword,
|
|
288
|
+
signInWithOAuth,
|
|
289
|
+
signInWithMagicLink,
|
|
290
|
+
signOut,
|
|
291
|
+
refreshSession,
|
|
292
|
+
client, // for advanced usage
|
|
293
|
+
} = useAuth();
|
|
73
294
|
|
|
74
295
|
if (isLoading) return <Loading />;
|
|
75
|
-
if (
|
|
296
|
+
if (isAuthenticated) return <Redirect to="/dashboard" />;
|
|
76
297
|
|
|
77
298
|
return (
|
|
78
299
|
<div>
|
|
@@ -93,85 +314,186 @@ function LoginPage() {
|
|
|
93
314
|
}
|
|
94
315
|
```
|
|
95
316
|
|
|
96
|
-
|
|
317
|
+
### Convenience Hooks
|
|
97
318
|
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
319
|
+
```tsx
|
|
320
|
+
import {
|
|
321
|
+
useUser,
|
|
322
|
+
useSession,
|
|
323
|
+
useIsAuthenticated,
|
|
324
|
+
useAuthClient,
|
|
325
|
+
usePassword,
|
|
326
|
+
useMFA,
|
|
327
|
+
useIdentities,
|
|
328
|
+
useSessions,
|
|
329
|
+
useSSO,
|
|
330
|
+
} from '@vaiftech/auth/react';
|
|
105
331
|
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
const session = await auth.handleOAuthCallback(code, state);
|
|
332
|
+
// Get current user
|
|
333
|
+
const user = useUser();
|
|
109
334
|
|
|
110
|
-
//
|
|
111
|
-
|
|
335
|
+
// Get current session
|
|
336
|
+
const session = useSession();
|
|
112
337
|
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
```
|
|
338
|
+
// Check auth status
|
|
339
|
+
const isAuthenticated = useIsAuthenticated();
|
|
116
340
|
|
|
117
|
-
|
|
341
|
+
// Password management
|
|
342
|
+
const { resetPassword, updatePassword, isLoading } = usePassword();
|
|
118
343
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const { qrCode, secret, backupCodes } = await auth.enrollMFA({ type: 'totp' });
|
|
344
|
+
// MFA management
|
|
345
|
+
const { factors, enrollTOTP, verifyMFA, unenroll, isLoading } = useMFA();
|
|
122
346
|
|
|
123
|
-
//
|
|
124
|
-
|
|
347
|
+
// OAuth identities
|
|
348
|
+
const { identities, linkIdentity, unlinkIdentity } = useIdentities();
|
|
125
349
|
|
|
126
|
-
//
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
350
|
+
// Session management
|
|
351
|
+
const { sessions, revokeSession, revokeOtherSessions } = useSessions();
|
|
352
|
+
|
|
353
|
+
// SSO
|
|
354
|
+
const { signInWithSSO, isLoading } = useSSO();
|
|
131
355
|
```
|
|
132
356
|
|
|
133
|
-
##
|
|
357
|
+
## Auth State Events
|
|
134
358
|
|
|
135
359
|
```typescript
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
360
|
+
const { unsubscribe } = auth.onAuthStateChange((event) => {
|
|
361
|
+
switch (event.event) {
|
|
362
|
+
case 'SIGNED_IN':
|
|
363
|
+
console.log('User signed in:', event.session?.user.email);
|
|
364
|
+
break;
|
|
365
|
+
case 'SIGNED_OUT':
|
|
366
|
+
console.log('User signed out');
|
|
367
|
+
break;
|
|
368
|
+
case 'TOKEN_REFRESHED':
|
|
369
|
+
console.log('Token refreshed');
|
|
370
|
+
break;
|
|
371
|
+
case 'USER_UPDATED':
|
|
372
|
+
console.log('User updated:', event.session?.user);
|
|
373
|
+
break;
|
|
374
|
+
case 'PASSWORD_RECOVERY':
|
|
375
|
+
console.log('Password recovery flow completed');
|
|
376
|
+
break;
|
|
377
|
+
case 'MFA_CHALLENGE_VERIFIED':
|
|
378
|
+
console.log('MFA challenge verified');
|
|
379
|
+
break;
|
|
380
|
+
case 'INITIAL_SESSION':
|
|
381
|
+
console.log('Session restored from storage');
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
});
|
|
150
385
|
|
|
151
|
-
//
|
|
152
|
-
|
|
386
|
+
// Unsubscribe when done
|
|
387
|
+
unsubscribe();
|
|
153
388
|
```
|
|
154
389
|
|
|
155
390
|
## Configuration
|
|
156
391
|
|
|
157
392
|
```typescript
|
|
393
|
+
import { createAuthClient, cookieStorage } from '@vaiftech/auth';
|
|
394
|
+
|
|
158
395
|
const auth = createAuthClient({
|
|
159
396
|
// Required
|
|
160
397
|
url: 'https://api.vaif.studio',
|
|
161
398
|
|
|
162
|
-
//
|
|
163
|
-
apiKey: 'your-project-key',
|
|
164
|
-
headers: {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
399
|
+
// Authentication
|
|
400
|
+
apiKey: 'your-project-key', // Publishable project key
|
|
401
|
+
headers: {}, // Custom request headers
|
|
402
|
+
|
|
403
|
+
// Session persistence
|
|
404
|
+
storage: cookieStorage({ // localStorage (default), sessionStorage, cookieStorage, or custom
|
|
405
|
+
secure: true,
|
|
406
|
+
sameSite: 'lax',
|
|
407
|
+
domain: '.myapp.com',
|
|
408
|
+
}),
|
|
409
|
+
storageKey: 'vaif.auth.', // Storage key prefix
|
|
410
|
+
persistSession: true, // Persist session to storage
|
|
411
|
+
autoRefreshToken: true, // Auto-refresh before expiry
|
|
412
|
+
|
|
413
|
+
// OAuth
|
|
414
|
+
detectSessionInUrl: true, // Auto-detect OAuth callbacks
|
|
415
|
+
flowType: 'pkce', // 'implicit' or 'pkce'
|
|
416
|
+
|
|
417
|
+
// Debug
|
|
418
|
+
debug: false, // Log auth events to console
|
|
172
419
|
});
|
|
173
420
|
```
|
|
174
421
|
|
|
422
|
+
## Error Handling
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
import { AuthError, SessionExpiredError, InvalidCredentialsError } from '@vaiftech/auth';
|
|
426
|
+
|
|
427
|
+
try {
|
|
428
|
+
await auth.signInWithPassword({ email, password });
|
|
429
|
+
} catch (error) {
|
|
430
|
+
if (error instanceof InvalidCredentialsError) {
|
|
431
|
+
showError('Invalid email or password');
|
|
432
|
+
} else if (error instanceof SessionExpiredError) {
|
|
433
|
+
redirectTo('/login');
|
|
434
|
+
} else if (AuthError.isAuthError(error)) {
|
|
435
|
+
switch (error.code) {
|
|
436
|
+
case 'user_already_exists':
|
|
437
|
+
showError('Account already exists');
|
|
438
|
+
break;
|
|
439
|
+
case 'weak_password':
|
|
440
|
+
showError('Password is too weak');
|
|
441
|
+
break;
|
|
442
|
+
case 'rate_limited':
|
|
443
|
+
showError('Too many attempts, please try later');
|
|
444
|
+
break;
|
|
445
|
+
case 'mfa_required':
|
|
446
|
+
showMFAPrompt();
|
|
447
|
+
break;
|
|
448
|
+
default:
|
|
449
|
+
showError(error.message);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Error Codes
|
|
456
|
+
|
|
457
|
+
| Code | Description |
|
|
458
|
+
|------|-------------|
|
|
459
|
+
| `invalid_credentials` | Wrong email or password |
|
|
460
|
+
| `user_not_found` | No user with that email |
|
|
461
|
+
| `user_already_exists` | Email already registered |
|
|
462
|
+
| `email_not_verified` | Email verification required |
|
|
463
|
+
| `invalid_token` | Invalid or malformed token |
|
|
464
|
+
| `token_expired` | Access or refresh token expired |
|
|
465
|
+
| `session_expired` | Session no longer valid |
|
|
466
|
+
| `mfa_required` | MFA verification needed |
|
|
467
|
+
| `mfa_invalid` | Invalid MFA code |
|
|
468
|
+
| `rate_limited` | Too many requests |
|
|
469
|
+
| `weak_password` | Password doesn't meet requirements |
|
|
470
|
+
| `network_error` | Network connectivity issue |
|
|
471
|
+
|
|
472
|
+
## Storage Adapters
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
import {
|
|
476
|
+
memoryStorage, // In-memory (default for Node.js)
|
|
477
|
+
localStorage, // Browser localStorage (default for browser)
|
|
478
|
+
sessionStorage, // Browser sessionStorage
|
|
479
|
+
cookieStorage, // Secure cookies
|
|
480
|
+
} from '@vaiftech/auth';
|
|
481
|
+
|
|
482
|
+
// Custom adapter
|
|
483
|
+
const customStorage = {
|
|
484
|
+
getItem: (key: string) => redis.get(key),
|
|
485
|
+
setItem: (key: string, value: string) => redis.set(key, value),
|
|
486
|
+
removeItem: (key: string) => redis.del(key),
|
|
487
|
+
};
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
## Related Packages
|
|
491
|
+
|
|
492
|
+
- [@vaiftech/client](https://www.npmjs.com/package/@vaiftech/client) - Full VAIF Studio SDK (includes auth)
|
|
493
|
+
- [@vaiftech/react](https://www.npmjs.com/package/@vaiftech/react) - React hooks for all VAIF services
|
|
494
|
+
- [@vaiftech/sdk-expo](https://www.npmjs.com/package/@vaiftech/sdk-expo) - React Native/Expo SDK
|
|
495
|
+
- [@vaiftech/cli](https://www.npmjs.com/package/@vaiftech/cli) - CLI tools
|
|
496
|
+
|
|
175
497
|
## License
|
|
176
498
|
|
|
177
|
-
MIT
|
|
499
|
+
MIT
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function l(r){return "mfaRequired"in r&&r.mfaRequired===true}var h=class r extends Error{constructor(e,t,s,i){super(e),this.name="AuthError",this.code=t,this.status=s,this.details=i;}static isAuthError(e){return e instanceof r}},m=class extends h{constructor(e="Session has expired"){super(e,"session_expired",401),this.name="SessionExpiredError";}},S=class extends h{constructor(e="Invalid email or password"){super(e,"invalid_credentials",401),this.name="InvalidCredentialsError";}};function n(){return typeof window<"u"&&typeof window.document<"u"}function y(){if(!n())return false;try{let r="__vaif_test__";return window.localStorage.setItem(r,r),window.localStorage.removeItem(r),!0}catch{return false}}var c=class{constructor(){this.storage=new Map;}getItem(e){return this.storage.get(e)??null}setItem(e,t){this.storage.set(e,t);}removeItem(e){this.storage.delete(e);}clear(){this.storage.clear();}},u=class{getItem(e){if(!n())return null;try{return window.localStorage.getItem(e)}catch{return null}}setItem(e,t){if(n())try{window.localStorage.setItem(e,t);}catch{}}removeItem(e){if(n())try{window.localStorage.removeItem(e);}catch{}}},p=class{getItem(e){if(!n())return null;try{return window.sessionStorage.getItem(e)}catch{return null}}setItem(e,t){if(n())try{window.sessionStorage.setItem(e,t);}catch{}}removeItem(e){if(n())try{window.sessionStorage.removeItem(e);}catch{}}},g=class{constructor(e){this.options={secure:n()&&window.location.protocol==="https:",sameSite:"lax",path:"/",...e};}getItem(e){if(!n())return null;try{let t=document.cookie.split(";");for(let s of t){let[i,o]=s.trim().split("=");if(i===e)return decodeURIComponent(o)}return null}catch{return null}}setItem(e,t){if(n())try{let s=`${e}=${encodeURIComponent(t)}`;s+=`; path=${this.options.path}`,s+=`; samesite=${this.options.sameSite}`,this.options.secure&&(s+="; secure"),this.options.domain&&(s+=`; domain=${this.options.domain}`),this.options.maxAge&&(s+=`; max-age=${this.options.maxAge}`),document.cookie=s;}catch{}}removeItem(e){if(n())try{document.cookie=`${e}=; path=${this.options.path}; expires=Thu, 01 Jan 1970 00:00:00 GMT`;}catch{}}};function _(){return y()?new u:new c}var d=class{constructor(e,t="vaif.auth."){this.adapter=e,this.keyPrefix=t;}key(e){return `${this.keyPrefix}${e}`}async getSession(){try{let e=await this.adapter.getItem(this.key("session"));if(!e)return null;let t=JSON.parse(e);return t.expiresAt&&t.expiresAt<Date.now()?(await this.removeSession(),null):t}catch{return null}}async setSession(e){try{await this.adapter.setItem(this.key("session"),JSON.stringify(e));}catch{}}async removeSession(){try{await this.adapter.removeItem(this.key("session"));}catch{}}async getRefreshToken(){try{return await this.adapter.getItem(this.key("refresh_token"))}catch{return null}}async setRefreshToken(e){try{await this.adapter.setItem(this.key("refresh_token"),e);}catch{}}async removeRefreshToken(){try{await this.adapter.removeItem(this.key("refresh_token"));}catch{}}async clear(){await this.removeSession(),await this.removeRefreshToken();}},A=new c,P=y()?new u:A,T=n()?new p:A,I=r=>new g(r);function R(){if(typeof crypto<"u"&&crypto.getRandomValues){let r=new Uint8Array(32);return crypto.getRandomValues(r),Array.from(r,e=>e.toString(16).padStart(2,"0")).join("")}return Array.from({length:64},()=>Math.floor(Math.random()*36).toString(36)).join("")}async function b(r){if(typeof crypto<"u"&&crypto.subtle){let t=new TextEncoder().encode(r),s=await crypto.subtle.digest("SHA-256",t);return btoa(String.fromCharCode(...new Uint8Array(s))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}return r}var v={storageKey:"vaif.auth.",autoRefreshToken:true,persistSession:true,detectSessionInUrl:true,flowType:"implicit",debug:false},O=60*1e3,f=class{constructor(e){this.refreshTimer=null;this.listeners=new Set;this.initialized=false;this.initPromise=null;this.currentSession=null;this.broadcastChannel=null;this.config={...v,...e,headers:e.headers||{},storage:e.storage||_()},this.storage=new d(this.config.storage,this.config.storageKey);}async initialize(){return this.initPromise?this.initPromise.then(()=>this.currentSession):(this.initPromise=this._initialize(),await this.initPromise,this.currentSession)}async _initialize(){if(!this.initialized){if(this.config.detectSessionInUrl&&n()){let e=await this._handleUrlSession();if(e){this.currentSession=e,await this._persistSession(e),this._notifyListeners("SIGNED_IN",e),this._setupAutoRefresh(e),this.initialized=true;return}}if(this.config.persistSession){let e=await this.storage.getSession();e&&(this.currentSession=e,this._notifyListeners("INITIAL_SESSION",e),this._setupAutoRefresh(e));}this.initialized=true,n()&&typeof BroadcastChannel<"u"&&(this.broadcastChannel=new BroadcastChannel(`${this.config.storageKey}sync`),this.broadcastChannel.onmessage=e=>{let{type:t,session:s}=e.data;t==="SESSION_UPDATE"&&(this.currentSession=s,this._notifyListeners(s?"TOKEN_REFRESHED":"SIGNED_OUT",s),s?this._setupAutoRefresh(s):this._clearRefreshTimer());});}}async getSession(){return await this.initialize(),this.currentSession}async getUser(){return (await this.getSession())?.user??null}async setSession(e,t){let s=await this._fetchUser(e),i={accessToken:e,refreshToken:t,expiresAt:Date.now()+3600*1e3,expiresIn:3600,tokenType:"bearer",user:s};return this.currentSession=i,await this._persistSession(i),this._notifyListeners("SIGNED_IN",i),this._setupAutoRefresh(i),{session:i,user:s}}async refreshSession(){let e=await this.getSession();if(!e?.refreshToken)return null;try{let t=await this._refreshToken(e.refreshToken),s={...e,accessToken:t.accessToken,refreshToken:t.refreshToken||e.refreshToken,expiresAt:t.expiresAt,expiresIn:t.expiresIn};return this.currentSession=s,await this._persistSession(s),this._notifyListeners("TOKEN_REFRESHED",s),this._setupAutoRefresh(s),s}catch(t){return this._log("Failed to refresh session:",t),await this.signOut(),null}}async signUp(e){let t=await this._fetch("/auth/signup",{method:"POST",body:JSON.stringify({email:e.email,password:e.password,name:e.name,phone:e.phone,metadata:e.metadata,redirectUrl:e.redirectUrl||e.emailRedirectTo})});return l(t)||(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session)),t}async signInWithPassword(e){let t=await this._fetch("/auth/login",{method:"POST",body:JSON.stringify({email:e.email,password:e.password,mfaCode:e.mfaCode,rememberMe:e.rememberMe})});return l(t)||(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session)),t}async signInWithOAuth(e){let t=await this._fetch("/auth/oauth/authorize",{method:"POST",body:JSON.stringify({provider:e.provider,redirectUrl:e.redirectTo,scopes:e.scopes,queryParams:e.queryParams,flowType:this.config.flowType})});return n()&&(window.location.href=t.url),t}async signInWithMagicLink(e){return this._fetch("/auth/magic-link/send",{method:"POST",body:JSON.stringify({email:e.email,redirectUrl:e.redirectTo,shouldCreateUser:e.shouldCreateUser})})}async signInWithOTP(e){let t=e.phone?"/auth/phone/send":"/auth/otp/send";return this._fetch(t,{method:"POST",body:JSON.stringify({email:e.email,phone:e.phone,channel:e.channel,shouldCreateUser:e.shouldCreateUser})})}async verifyOTP(e){let t=await this._fetch("/auth/otp/verify",{method:"POST",body:JSON.stringify({email:e.email,phone:e.phone,token:e.token,type:e.type})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session),t}async signInAnonymously(e){let t=await this._fetch("/auth/anonymous",{method:"POST",body:JSON.stringify({metadata:e?.metadata})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session),t}async signInWithSSO(e){let t=await this._fetch("/auth/sso/authorize",{method:"POST",body:JSON.stringify({domain:e.domain,providerId:e.providerId,redirectUrl:e.redirectTo})});return n()&&(window.location.href=t.url),t}async signOut(){try{this.currentSession&&await this._fetch("/auth/logout",{method:"POST"});}catch{}this._clearRefreshTimer(),this.currentSession=null,await this.storage.clear(),this._notifyListeners("SIGNED_OUT",null),this._broadcastSessionUpdate(null);}async signOutAll(){try{await this._fetch("/auth/logout-all",{method:"POST"});}catch{}this._clearRefreshTimer(),this.currentSession=null,await this.storage.clear(),this._notifyListeners("SIGNED_OUT",null);}async resetPasswordForEmail(e){return this._fetch("/auth/forgot-password",{method:"POST",body:JSON.stringify({email:e.email,redirectUrl:e.redirectTo})})}async updatePassword(e){return this._fetch("/users/me/change-password",{method:"POST",body:JSON.stringify({currentPassword:e.currentPassword,newPassword:e.newPassword})})}async setPassword(e){let t=await this._fetch("/auth/reset-password",{method:"POST",body:JSON.stringify({token:e.token,password:e.password})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("PASSWORD_RECOVERY",t.session),this._setupAutoRefresh(t.session),t}async updateUser(e){let t=await this._fetch("/users/me",{method:"PATCH",body:JSON.stringify(e)});return this.currentSession&&(this.currentSession={...this.currentSession,user:t.user},await this._persistSession(this.currentSession),this._notifyListeners("USER_UPDATED",this.currentSession)),t.user}async getUserIdentities(){return (await this._fetch("/auth/oauth/providers")).identities}async linkIdentity(e,t){let s=await this._fetch("/auth/oauth/link",{method:"POST",body:JSON.stringify({provider:e,redirectUrl:t?.redirectTo})});return n()&&(window.location.href=s.url),s}async unlinkIdentity(e){return this._fetch(`/auth/oauth/unlink/${e}`,{method:"POST"})}async listMFAFactors(){return (await this._fetch("/auth/mfa/factors")).factors}async enrollMFA(e){return this._fetch("/auth/mfa/setup",{method:"POST",body:JSON.stringify({method:e.type,friendlyName:e.friendlyName})})}async verifyMFA(e){return this._fetch("/auth/mfa/enable",{method:"POST",body:JSON.stringify({factorId:e.factorId,code:e.code})})}async challengeMFA(e){return this._fetch("/auth/mfa/challenge",{method:"POST",body:JSON.stringify({factorId:e.factorId})})}async verifyMFAChallenge(e,t){let s=await this._fetch("/auth/mfa/verify",{method:"POST",body:JSON.stringify({mfaToken:e,code:t})});return this.currentSession=s.session,await this._persistSession(s.session),this._notifyListeners("MFA_CHALLENGE_VERIFIED",s.session),this._setupAutoRefresh(s.session),s}async unenrollMFA(e,t){return this._fetch("/auth/mfa/disable",{method:"POST",body:JSON.stringify({factorId:e,code:t})})}async regenerateBackupCodes(){return this._fetch("/auth/mfa/backup-codes",{method:"POST"})}async listSessions(){return (await this._fetch("/auth/sessions")).sessions}async revokeSession(e){return this._fetch(`/auth/sessions/${e}`,{method:"DELETE"})}async revokeOtherSessions(){return this._fetch("/auth/sessions/revoke-others",{method:"POST"})}async resendEmailVerification(e){return this._fetch("/auth/verify-email/send",{method:"POST",body:JSON.stringify({redirectUrl:e?.redirectTo})})}async verifyEmail(e){let t=await this._fetch("/auth/verify-email/confirm",{method:"POST",body:JSON.stringify({token:e})});return this.currentSession&&(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("USER_UPDATED",t.session)),t}onAuthStateChange(e){return this.listeners.add(e),this.initialized&&e({event:this.currentSession?"INITIAL_SESSION":"SIGNED_OUT",session:this.currentSession}),{unsubscribe:()=>{this.listeners.delete(e);}}}async _fetch(e,t={}){let s=`${this.config.url}${e}`,i={"Content-Type":"application/json",...this.config.headers};this.config.apiKey&&(i["x-vaif-key"]=this.config.apiKey),this.currentSession?.accessToken&&(i.Authorization=`Bearer ${this.currentSession.accessToken}`);let o;try{o=await fetch(s,{...t,headers:i});}catch(a){throw new h(a instanceof Error?a.message:"Network request failed","network_error")}if(!o.ok){let a=await o.json().catch(()=>({}));throw new h(a.message||"Request failed",this._mapErrorCode(o.status,a.code),o.status,a)}return o.json()}async _fetchUser(e){let t=await fetch(`${this.config.url}/auth/me`,{headers:{Authorization:`Bearer ${e}`,...this.config.headers}});if(!t.ok)throw new h("Failed to fetch user","invalid_token",t.status);return (await t.json()).user}async _refreshToken(e){let t=await fetch(`${this.config.url}/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json",...this.config.headers},body:JSON.stringify({refreshToken:e})});if(!t.ok)throw new h("Failed to refresh token","token_expired",t.status);return t.json()}async _handleUrlSession(){if(!n())return null;let e=new URLSearchParams(window.location.hash.substring(1)),t=new URLSearchParams(window.location.search),s=e.get("access_token")||t.get("access_token"),i=e.get("refresh_token")||t.get("refresh_token"),o=e.get("expires_in")||t.get("expires_in");if(!s)return null;try{let a=await this._fetchUser(s),w={accessToken:s,refreshToken:i||void 0,expiresAt:Date.now()+(o?parseInt(o,10)*1e3:36e5),expiresIn:o?parseInt(o,10):3600,tokenType:"bearer",user:a};return window.history.replaceState(null,"",window.location.pathname),w}catch(a){return this._log("Failed to handle URL session:",a),null}}async _persistSession(e){this.config.persistSession&&(await this.storage.setSession(e),e.refreshToken&&await this.storage.setRefreshToken(e.refreshToken),this._broadcastSessionUpdate(e));}_setupAutoRefresh(e){if(!this.config.autoRefreshToken||!e.refreshToken)return;this._clearRefreshTimer();let t=e.expiresAt,s=Date.now(),i=Math.max(0,t-s-O);this._log(`Setting up auto refresh in ${Math.round(i/1e3)}s`),this.refreshTimer=setTimeout(()=>{this.refreshSession();},i);}_clearRefreshTimer(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null);}_notifyListeners(e,t){let s={event:e,session:t};this.listeners.forEach(i=>{try{i(s);}catch(o){this._log("Error in auth state change listener:",o);}});}_mapErrorCode(e,t){if(t){let s={invalid_credentials:"invalid_credentials",user_not_found:"user_not_found",user_already_exists:"user_already_exists",email_not_verified:"email_not_verified",phone_not_verified:"phone_not_verified",invalid_token:"invalid_token",token_expired:"token_expired",mfa_required:"mfa_required",mfa_invalid:"mfa_invalid",rate_limited:"rate_limited",weak_password:"weak_password",invalid_email:"invalid_email",invalid_phone:"invalid_phone"};if(s[t])return s[t]}switch(e){case 401:return "invalid_credentials";case 403:return "token_expired";case 404:return "user_not_found";case 409:return "user_already_exists";case 429:return "rate_limited";default:return "unknown_error"}}_broadcastSessionUpdate(e){try{this.broadcastChannel?.postMessage({type:"SESSION_UPDATE",session:e});}catch{}}destroy(){this._clearRefreshTimer(),this.broadcastChannel?.close(),this.broadcastChannel=null,this.listeners.clear();}_log(...e){this.config.debug&&console.log("[VaifAuth]",...e);}};function U(r){return new f(r)}
|
|
2
|
+
export{l as a,h as b,m as c,S as d,n as e,_ as f,d as g,A as h,P as i,T as j,I as k,R as l,b as m,f as n,U as o};
|
|
@@ -423,6 +423,7 @@ declare class VaifAuthClient {
|
|
|
423
423
|
private initialized;
|
|
424
424
|
private initPromise;
|
|
425
425
|
private currentSession;
|
|
426
|
+
private broadcastChannel;
|
|
426
427
|
constructor(config: AuthClientConfig);
|
|
427
428
|
/**
|
|
428
429
|
* Initialize the auth client
|
|
@@ -478,6 +479,10 @@ declare class VaifAuthClient {
|
|
|
478
479
|
* Sign in anonymously
|
|
479
480
|
*/
|
|
480
481
|
signInAnonymously(options?: SignInAnonymouslyOptions): Promise<AuthResponse>;
|
|
482
|
+
/**
|
|
483
|
+
* Sign in with SSO (SAML/OIDC)
|
|
484
|
+
*/
|
|
485
|
+
signInWithSSO(options: SignInWithSSOOptions): Promise<OAuthResponse>;
|
|
481
486
|
/**
|
|
482
487
|
* Sign out the current user
|
|
483
488
|
*/
|
|
@@ -601,6 +606,11 @@ declare class VaifAuthClient {
|
|
|
601
606
|
private _clearRefreshTimer;
|
|
602
607
|
private _notifyListeners;
|
|
603
608
|
private _mapErrorCode;
|
|
609
|
+
private _broadcastSessionUpdate;
|
|
610
|
+
/**
|
|
611
|
+
* Clean up resources (timers, broadcast channel)
|
|
612
|
+
*/
|
|
613
|
+
destroy(): void;
|
|
604
614
|
private _log;
|
|
605
615
|
}
|
|
606
616
|
/**
|
|
@@ -423,6 +423,7 @@ declare class VaifAuthClient {
|
|
|
423
423
|
private initialized;
|
|
424
424
|
private initPromise;
|
|
425
425
|
private currentSession;
|
|
426
|
+
private broadcastChannel;
|
|
426
427
|
constructor(config: AuthClientConfig);
|
|
427
428
|
/**
|
|
428
429
|
* Initialize the auth client
|
|
@@ -478,6 +479,10 @@ declare class VaifAuthClient {
|
|
|
478
479
|
* Sign in anonymously
|
|
479
480
|
*/
|
|
480
481
|
signInAnonymously(options?: SignInAnonymouslyOptions): Promise<AuthResponse>;
|
|
482
|
+
/**
|
|
483
|
+
* Sign in with SSO (SAML/OIDC)
|
|
484
|
+
*/
|
|
485
|
+
signInWithSSO(options: SignInWithSSOOptions): Promise<OAuthResponse>;
|
|
481
486
|
/**
|
|
482
487
|
* Sign out the current user
|
|
483
488
|
*/
|
|
@@ -601,6 +606,11 @@ declare class VaifAuthClient {
|
|
|
601
606
|
private _clearRefreshTimer;
|
|
602
607
|
private _notifyListeners;
|
|
603
608
|
private _mapErrorCode;
|
|
609
|
+
private _broadcastSessionUpdate;
|
|
610
|
+
/**
|
|
611
|
+
* Clean up resources (timers, broadcast channel)
|
|
612
|
+
*/
|
|
613
|
+
destroy(): void;
|
|
604
614
|
private _log;
|
|
605
615
|
}
|
|
606
616
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as StorageAdapter, A as AsyncStorageAdapter, a as Session } from './client-
|
|
2
|
-
export { z as AuthChangeEvent, E as AuthClientConfig, G as AuthError, F as AuthErrorCode, y as AuthEventType, e as AuthResponse, B as AuthStateChangeCallback, D as AuthSubscription, C as ConfirmEmailChangeOptions, I as InvalidCredentialsError, M as MFAChallenge, w as MFAChallengeOptions, x as MFAChallengeResponse, t as MFAFactor, s as MFAMethod, u as MFASetupResponse, v as MFAVerifyOptions, r as OAuthIdentity, O as OAuthProviderType, q as OAuthResponse, R as ResetPasswordOptions, H as SessionExpiredError, d as SessionInfo, o as SetPasswordOptions, m as SignInAnonymouslyOptions, i as SignInWithMagicLinkOptions, h as SignInWithOAuthOptions, j as SignInWithOTPOptions, g as SignInWithPasswordOptions, l as SignInWithSSOOptions, f as SignUpOptions, T as TokenRefreshResponse, n as UpdatePasswordOptions, p as UpdateUserOptions, U as User, b as UserInfo, V as VaifAuthClient, k as VerifyOTPOptions, c as createAuthClient, J as isMFAChallenge } from './client-
|
|
1
|
+
import { S as StorageAdapter, A as AsyncStorageAdapter, a as Session } from './client-DYj4LiUx.mjs';
|
|
2
|
+
export { z as AuthChangeEvent, E as AuthClientConfig, G as AuthError, F as AuthErrorCode, y as AuthEventType, e as AuthResponse, B as AuthStateChangeCallback, D as AuthSubscription, C as ConfirmEmailChangeOptions, I as InvalidCredentialsError, M as MFAChallenge, w as MFAChallengeOptions, x as MFAChallengeResponse, t as MFAFactor, s as MFAMethod, u as MFASetupResponse, v as MFAVerifyOptions, r as OAuthIdentity, O as OAuthProviderType, q as OAuthResponse, R as ResetPasswordOptions, H as SessionExpiredError, d as SessionInfo, o as SetPasswordOptions, m as SignInAnonymouslyOptions, i as SignInWithMagicLinkOptions, h as SignInWithOAuthOptions, j as SignInWithOTPOptions, g as SignInWithPasswordOptions, l as SignInWithSSOOptions, f as SignUpOptions, T as TokenRefreshResponse, n as UpdatePasswordOptions, p as UpdateUserOptions, U as User, b as UserInfo, V as VaifAuthClient, k as VerifyOTPOptions, c as createAuthClient, J as isMFAChallenge } from './client-DYj4LiUx.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @vaiftech/auth - Storage utilities
|
|
@@ -79,5 +79,13 @@ declare const memoryStorage: MemoryStorage;
|
|
|
79
79
|
declare const localStorage: MemoryStorage | LocalStorageAdapter;
|
|
80
80
|
declare const sessionStorage: MemoryStorage | SessionStorageAdapter;
|
|
81
81
|
declare const cookieStorage: (options?: CookieStorageOptions) => CookieStorageAdapter;
|
|
82
|
+
/**
|
|
83
|
+
* Generate a random PKCE code verifier
|
|
84
|
+
*/
|
|
85
|
+
declare function generateCodeVerifier(): string;
|
|
86
|
+
/**
|
|
87
|
+
* Generate a PKCE code challenge from a verifier
|
|
88
|
+
*/
|
|
89
|
+
declare function generateCodeChallenge(verifier: string): Promise<string>;
|
|
82
90
|
|
|
83
|
-
export { AsyncStorageAdapter, type CookieStorageOptions, Session, SessionStorage, StorageAdapter, cookieStorage, getDefaultStorage, isBrowser, localStorage, memoryStorage, sessionStorage };
|
|
91
|
+
export { AsyncStorageAdapter, type CookieStorageOptions, Session, SessionStorage, StorageAdapter, cookieStorage, generateCodeChallenge, generateCodeVerifier, getDefaultStorage, isBrowser, localStorage, memoryStorage, sessionStorage };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as StorageAdapter, A as AsyncStorageAdapter, a as Session } from './client-
|
|
2
|
-
export { z as AuthChangeEvent, E as AuthClientConfig, G as AuthError, F as AuthErrorCode, y as AuthEventType, e as AuthResponse, B as AuthStateChangeCallback, D as AuthSubscription, C as ConfirmEmailChangeOptions, I as InvalidCredentialsError, M as MFAChallenge, w as MFAChallengeOptions, x as MFAChallengeResponse, t as MFAFactor, s as MFAMethod, u as MFASetupResponse, v as MFAVerifyOptions, r as OAuthIdentity, O as OAuthProviderType, q as OAuthResponse, R as ResetPasswordOptions, H as SessionExpiredError, d as SessionInfo, o as SetPasswordOptions, m as SignInAnonymouslyOptions, i as SignInWithMagicLinkOptions, h as SignInWithOAuthOptions, j as SignInWithOTPOptions, g as SignInWithPasswordOptions, l as SignInWithSSOOptions, f as SignUpOptions, T as TokenRefreshResponse, n as UpdatePasswordOptions, p as UpdateUserOptions, U as User, b as UserInfo, V as VaifAuthClient, k as VerifyOTPOptions, c as createAuthClient, J as isMFAChallenge } from './client-
|
|
1
|
+
import { S as StorageAdapter, A as AsyncStorageAdapter, a as Session } from './client-DYj4LiUx.js';
|
|
2
|
+
export { z as AuthChangeEvent, E as AuthClientConfig, G as AuthError, F as AuthErrorCode, y as AuthEventType, e as AuthResponse, B as AuthStateChangeCallback, D as AuthSubscription, C as ConfirmEmailChangeOptions, I as InvalidCredentialsError, M as MFAChallenge, w as MFAChallengeOptions, x as MFAChallengeResponse, t as MFAFactor, s as MFAMethod, u as MFASetupResponse, v as MFAVerifyOptions, r as OAuthIdentity, O as OAuthProviderType, q as OAuthResponse, R as ResetPasswordOptions, H as SessionExpiredError, d as SessionInfo, o as SetPasswordOptions, m as SignInAnonymouslyOptions, i as SignInWithMagicLinkOptions, h as SignInWithOAuthOptions, j as SignInWithOTPOptions, g as SignInWithPasswordOptions, l as SignInWithSSOOptions, f as SignUpOptions, T as TokenRefreshResponse, n as UpdatePasswordOptions, p as UpdateUserOptions, U as User, b as UserInfo, V as VaifAuthClient, k as VerifyOTPOptions, c as createAuthClient, J as isMFAChallenge } from './client-DYj4LiUx.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @vaiftech/auth - Storage utilities
|
|
@@ -79,5 +79,13 @@ declare const memoryStorage: MemoryStorage;
|
|
|
79
79
|
declare const localStorage: MemoryStorage | LocalStorageAdapter;
|
|
80
80
|
declare const sessionStorage: MemoryStorage | SessionStorageAdapter;
|
|
81
81
|
declare const cookieStorage: (options?: CookieStorageOptions) => CookieStorageAdapter;
|
|
82
|
+
/**
|
|
83
|
+
* Generate a random PKCE code verifier
|
|
84
|
+
*/
|
|
85
|
+
declare function generateCodeVerifier(): string;
|
|
86
|
+
/**
|
|
87
|
+
* Generate a PKCE code challenge from a verifier
|
|
88
|
+
*/
|
|
89
|
+
declare function generateCodeChallenge(verifier: string): Promise<string>;
|
|
82
90
|
|
|
83
|
-
export { AsyncStorageAdapter, type CookieStorageOptions, Session, SessionStorage, StorageAdapter, cookieStorage, getDefaultStorage, isBrowser, localStorage, memoryStorage, sessionStorage };
|
|
91
|
+
export { AsyncStorageAdapter, type CookieStorageOptions, Session, SessionStorage, StorageAdapter, cookieStorage, generateCodeChallenge, generateCodeVerifier, getDefaultStorage, isBrowser, localStorage, memoryStorage, sessionStorage };
|
package/dist/index.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
'use strict';function c(i){return "mfaRequired"in i&&i.mfaRequired===true}var a=class i extends Error{constructor(e,t,s,r){super(e),this.name="AuthError",this.code=t,this.status=s,this.details=r;}static isAuthError(e){return e instanceof i}},g=class extends a{constructor(e="Session has expired"){super(e,"session_expired",401),this.name="SessionExpiredError";}},f=class extends a{constructor(e="Invalid email or password"){super(e,"invalid_credentials",401),this.name="InvalidCredentialsError";}};function n(){return typeof window<"u"&&typeof window.document<"u"}function _(){if(!n())return false;try{let i="__vaif_test__";return window.localStorage.setItem(i,i),window.localStorage.removeItem(i),!0}catch{return false}}var p=class{constructor(){this.storage=new Map;}getItem(e){return this.storage.get(e)??null}setItem(e,t){this.storage.set(e,t);}removeItem(e){this.storage.delete(e);}clear(){this.storage.clear();}},l=class{getItem(e){if(!n())return null;try{return window.localStorage.getItem(e)}catch{return null}}setItem(e,t){if(n())try{window.localStorage.setItem(e,t);}catch{}}removeItem(e){if(n())try{window.localStorage.removeItem(e);}catch{}}},m=class{getItem(e){if(!n())return null;try{return window.sessionStorage.getItem(e)}catch{return null}}setItem(e,t){if(n())try{window.sessionStorage.setItem(e,t);}catch{}}removeItem(e){if(n())try{window.sessionStorage.removeItem(e);}catch{}}},S=class{constructor(e){this.options={secure:n()&&window.location.protocol==="https:",sameSite:"lax",path:"/",...e};}getItem(e){if(!n())return null;try{let t=document.cookie.split(";");for(let s of t){let[r,o]=s.trim().split("=");if(r===e)return decodeURIComponent(o)}return null}catch{return null}}setItem(e,t){if(n())try{let s=`${e}=${encodeURIComponent(t)}`;s+=`; path=${this.options.path}`,s+=`; samesite=${this.options.sameSite}`,this.options.secure&&(s+="; secure"),this.options.domain&&(s+=`; domain=${this.options.domain}`),this.options.maxAge&&(s+=`; max-age=${this.options.maxAge}`),document.cookie=s;}catch{}}removeItem(e){if(n())try{document.cookie=`${e}=; path=${this.options.path}; expires=Thu, 01 Jan 1970 00:00:00 GMT`;}catch{}}};function y(){return _()?new l:new p}var u=class{constructor(e,t="vaif.auth."){this.adapter=e,this.keyPrefix=t;}key(e){return `${this.keyPrefix}${e}`}async getSession(){try{let e=await this.adapter.getItem(this.key("session"));if(!e)return null;let t=JSON.parse(e);return t.expiresAt&&t.expiresAt<Date.now()?(await this.removeSession(),null):t}catch{return null}}async setSession(e){try{await this.adapter.setItem(this.key("session"),JSON.stringify(e));}catch{}}async removeSession(){try{await this.adapter.removeItem(this.key("session"));}catch{}}async getRefreshToken(){try{return await this.adapter.getItem(this.key("refresh_token"))}catch{return null}}async setRefreshToken(e){try{await this.adapter.setItem(this.key("refresh_token"),e);}catch{}}async removeRefreshToken(){try{await this.adapter.removeItem(this.key("refresh_token"));}catch{}}async clear(){await this.removeSession(),await this.removeRefreshToken();}},A=new p,O=_()?new l:A,k=n()?new m:A,v=i=>new S(i);var P={storageKey:"vaif.auth.",autoRefreshToken:true,persistSession:true,detectSessionInUrl:true,flowType:"implicit",debug:false},I=60*1e3,d=class{constructor(e){this.refreshTimer=null;this.listeners=new Set;this.initialized=false;this.initPromise=null;this.currentSession=null;this.config={...P,...e,headers:e.headers||{},storage:e.storage||y()},this.storage=new u(this.config.storage,this.config.storageKey);}async initialize(){return this.initPromise?this.initPromise.then(()=>this.currentSession):(this.initPromise=this._initialize(),await this.initPromise,this.currentSession)}async _initialize(){if(!this.initialized){if(this.config.detectSessionInUrl&&n()){let e=await this._handleUrlSession();if(e){this.currentSession=e,await this._persistSession(e),this._notifyListeners("SIGNED_IN",e),this._setupAutoRefresh(e),this.initialized=true;return}}if(this.config.persistSession){let e=await this.storage.getSession();e&&(this.currentSession=e,this._notifyListeners("INITIAL_SESSION",e),this._setupAutoRefresh(e));}this.initialized=true;}}async getSession(){return await this.initialize(),this.currentSession}async getUser(){return (await this.getSession())?.user??null}async setSession(e,t){let s=await this._fetchUser(e),r={accessToken:e,refreshToken:t,expiresAt:Date.now()+3600*1e3,expiresIn:3600,tokenType:"bearer",user:s};return this.currentSession=r,await this._persistSession(r),this._notifyListeners("SIGNED_IN",r),this._setupAutoRefresh(r),{session:r,user:s}}async refreshSession(){let e=await this.getSession();if(!e?.refreshToken)return null;try{let t=await this._refreshToken(e.refreshToken),s={...e,accessToken:t.accessToken,refreshToken:t.refreshToken||e.refreshToken,expiresAt:t.expiresAt,expiresIn:t.expiresIn};return this.currentSession=s,await this._persistSession(s),this._notifyListeners("TOKEN_REFRESHED",s),this._setupAutoRefresh(s),s}catch(t){return this._log("Failed to refresh session:",t),await this.signOut(),null}}async signUp(e){let t=await this._fetch("/auth/signup",{method:"POST",body:JSON.stringify({email:e.email,password:e.password,name:e.name,phone:e.phone,metadata:e.metadata,redirectUrl:e.redirectUrl||e.emailRedirectTo})});return c(t)||(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session)),t}async signInWithPassword(e){let t=await this._fetch("/auth/login",{method:"POST",body:JSON.stringify({email:e.email,password:e.password,mfaCode:e.mfaCode,rememberMe:e.rememberMe})});return c(t)||(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session)),t}async signInWithOAuth(e){let t=await this._fetch("/auth/oauth/authorize",{method:"POST",body:JSON.stringify({provider:e.provider,redirectUrl:e.redirectTo,scopes:e.scopes,queryParams:e.queryParams,flowType:this.config.flowType})});return n()&&(window.location.href=t.url),t}async signInWithMagicLink(e){return this._fetch("/auth/magic-link/send",{method:"POST",body:JSON.stringify({email:e.email,redirectUrl:e.redirectTo,shouldCreateUser:e.shouldCreateUser})})}async signInWithOTP(e){let t=e.phone?"/auth/phone/send":"/auth/otp/send";return this._fetch(t,{method:"POST",body:JSON.stringify({email:e.email,phone:e.phone,channel:e.channel,shouldCreateUser:e.shouldCreateUser})})}async verifyOTP(e){let t=await this._fetch("/auth/otp/verify",{method:"POST",body:JSON.stringify({email:e.email,phone:e.phone,token:e.token,type:e.type})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session),t}async signInAnonymously(e){let t=await this._fetch("/auth/anonymous",{method:"POST",body:JSON.stringify({metadata:e?.metadata})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session),t}async signOut(){try{this.currentSession&&await this._fetch("/auth/logout",{method:"POST"});}catch{}this._clearRefreshTimer(),this.currentSession=null,await this.storage.clear(),this._notifyListeners("SIGNED_OUT",null);}async signOutAll(){try{await this._fetch("/auth/logout-all",{method:"POST"});}catch{}this._clearRefreshTimer(),this.currentSession=null,await this.storage.clear(),this._notifyListeners("SIGNED_OUT",null);}async resetPasswordForEmail(e){return this._fetch("/auth/forgot-password",{method:"POST",body:JSON.stringify({email:e.email,redirectUrl:e.redirectTo})})}async updatePassword(e){return this._fetch("/users/me/change-password",{method:"POST",body:JSON.stringify({currentPassword:e.currentPassword,newPassword:e.newPassword})})}async setPassword(e){let t=await this._fetch("/auth/reset-password",{method:"POST",body:JSON.stringify({token:e.token,password:e.password})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("PASSWORD_RECOVERY",t.session),this._setupAutoRefresh(t.session),t}async updateUser(e){let t=await this._fetch("/users/me",{method:"PATCH",body:JSON.stringify(e)});return this.currentSession&&(this.currentSession={...this.currentSession,user:t.user},await this._persistSession(this.currentSession),this._notifyListeners("USER_UPDATED",this.currentSession)),t.user}async getUserIdentities(){return (await this._fetch("/auth/oauth/providers")).identities}async linkIdentity(e,t){let s=await this._fetch("/auth/oauth/link",{method:"POST",body:JSON.stringify({provider:e,redirectUrl:t?.redirectTo})});return n()&&(window.location.href=s.url),s}async unlinkIdentity(e){return this._fetch(`/auth/oauth/unlink/${e}`,{method:"POST"})}async listMFAFactors(){return (await this._fetch("/auth/mfa/factors")).factors}async enrollMFA(e){return this._fetch("/auth/mfa/setup",{method:"POST",body:JSON.stringify({method:e.type,friendlyName:e.friendlyName})})}async verifyMFA(e){return this._fetch("/auth/mfa/enable",{method:"POST",body:JSON.stringify({factorId:e.factorId,code:e.code})})}async challengeMFA(e){return this._fetch("/auth/mfa/challenge",{method:"POST",body:JSON.stringify({factorId:e.factorId})})}async verifyMFAChallenge(e,t){let s=await this._fetch("/auth/mfa/verify",{method:"POST",body:JSON.stringify({mfaToken:e,code:t})});return this.currentSession=s.session,await this._persistSession(s.session),this._notifyListeners("MFA_CHALLENGE_VERIFIED",s.session),this._setupAutoRefresh(s.session),s}async unenrollMFA(e,t){return this._fetch("/auth/mfa/disable",{method:"POST",body:JSON.stringify({factorId:e,code:t})})}async regenerateBackupCodes(){return this._fetch("/auth/mfa/backup-codes",{method:"POST"})}async listSessions(){return (await this._fetch("/auth/sessions")).sessions}async revokeSession(e){return this._fetch(`/auth/sessions/${e}`,{method:"DELETE"})}async revokeOtherSessions(){return this._fetch("/auth/sessions/revoke-others",{method:"POST"})}async resendEmailVerification(e){return this._fetch("/auth/verify-email/send",{method:"POST",body:JSON.stringify({redirectUrl:e?.redirectTo})})}async verifyEmail(e){let t=await this._fetch("/auth/verify-email/confirm",{method:"POST",body:JSON.stringify({token:e})});return this.currentSession&&(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("USER_UPDATED",t.session)),t}onAuthStateChange(e){return this.listeners.add(e),this.initialized&&e({event:this.currentSession?"INITIAL_SESSION":"SIGNED_OUT",session:this.currentSession}),{unsubscribe:()=>{this.listeners.delete(e);}}}async _fetch(e,t={}){let s=`${this.config.url}${e}`,r={"Content-Type":"application/json",...this.config.headers};this.config.apiKey&&(r["x-vaif-key"]=this.config.apiKey),this.currentSession?.accessToken&&(r.Authorization=`Bearer ${this.currentSession.accessToken}`);let o=await fetch(s,{...t,headers:r});if(!o.ok){let h=await o.json().catch(()=>({}));throw new a(h.message||"Request failed",this._mapErrorCode(o.status,h.code),o.status,h)}return o.json()}async _fetchUser(e){let t=await fetch(`${this.config.url}/auth/me`,{headers:{Authorization:`Bearer ${e}`,...this.config.headers}});if(!t.ok)throw new a("Failed to fetch user","invalid_token",t.status);return (await t.json()).user}async _refreshToken(e){let t=await fetch(`${this.config.url}/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json",...this.config.headers},body:JSON.stringify({refreshToken:e})});if(!t.ok)throw new a("Failed to refresh token","token_expired",t.status);return t.json()}async _handleUrlSession(){if(!n())return null;let e=new URLSearchParams(window.location.hash.substring(1)),t=new URLSearchParams(window.location.search),s=e.get("access_token")||t.get("access_token"),r=e.get("refresh_token")||t.get("refresh_token"),o=e.get("expires_in")||t.get("expires_in");if(!s)return null;try{let h=await this._fetchUser(s),w={accessToken:s,refreshToken:r||void 0,expiresAt:Date.now()+(o?parseInt(o,10)*1e3:36e5),expiresIn:o?parseInt(o,10):3600,tokenType:"bearer",user:h};return window.history.replaceState(null,"",window.location.pathname),w}catch(h){return this._log("Failed to handle URL session:",h),null}}async _persistSession(e){this.config.persistSession&&(await this.storage.setSession(e),e.refreshToken&&await this.storage.setRefreshToken(e.refreshToken));}_setupAutoRefresh(e){if(!this.config.autoRefreshToken||!e.refreshToken)return;this._clearRefreshTimer();let t=e.expiresAt,s=Date.now(),r=Math.max(0,t-s-I);this._log(`Setting up auto refresh in ${Math.round(r/1e3)}s`),this.refreshTimer=setTimeout(()=>{this.refreshSession();},r);}_clearRefreshTimer(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null);}_notifyListeners(e,t){let s={event:e,session:t};this.listeners.forEach(r=>{try{r(s);}catch(o){this._log("Error in auth state change listener:",o);}});}_mapErrorCode(e,t){if(t){let s={invalid_credentials:"invalid_credentials",user_not_found:"user_not_found",user_already_exists:"user_already_exists",email_not_verified:"email_not_verified",phone_not_verified:"phone_not_verified",invalid_token:"invalid_token",token_expired:"token_expired",mfa_required:"mfa_required",mfa_invalid:"mfa_invalid",rate_limited:"rate_limited",weak_password:"weak_password",invalid_email:"invalid_email",invalid_phone:"invalid_phone"};if(s[t])return s[t]}switch(e){case 401:return "invalid_credentials";case 403:return "token_expired";case 404:return "user_not_found";case 409:return "user_already_exists";case 429:return "rate_limited";default:return "unknown_error"}}_log(...e){this.config.debug&&console.log("[VaifAuth]",...e);}};function T(i){return new d(i)}exports.AuthError=a;exports.InvalidCredentialsError=f;exports.SessionExpiredError=g;exports.SessionStorage=u;exports.VaifAuthClient=d;exports.cookieStorage=v;exports.createAuthClient=T;exports.getDefaultStorage=y;exports.isBrowser=n;exports.isMFAChallenge=c;exports.localStorage=O;exports.memoryStorage=A;exports.sessionStorage=k;
|
|
1
|
+
'use strict';function u(r){return "mfaRequired"in r&&r.mfaRequired===true}var h=class r extends Error{constructor(e,t,s,i){super(e),this.name="AuthError",this.code=t,this.status=s,this.details=i;}static isAuthError(e){return e instanceof r}},g=class extends h{constructor(e="Session has expired"){super(e,"session_expired",401),this.name="SessionExpiredError";}},f=class extends h{constructor(e="Invalid email or password"){super(e,"invalid_credentials",401),this.name="InvalidCredentialsError";}};function n(){return typeof window<"u"&&typeof window.document<"u"}function _(){if(!n())return false;try{let r="__vaif_test__";return window.localStorage.setItem(r,r),window.localStorage.removeItem(r),!0}catch{return false}}var d=class{constructor(){this.storage=new Map;}getItem(e){return this.storage.get(e)??null}setItem(e,t){this.storage.set(e,t);}removeItem(e){this.storage.delete(e);}clear(){this.storage.clear();}},l=class{getItem(e){if(!n())return null;try{return window.localStorage.getItem(e)}catch{return null}}setItem(e,t){if(n())try{window.localStorage.setItem(e,t);}catch{}}removeItem(e){if(n())try{window.localStorage.removeItem(e);}catch{}}},m=class{getItem(e){if(!n())return null;try{return window.sessionStorage.getItem(e)}catch{return null}}setItem(e,t){if(n())try{window.sessionStorage.setItem(e,t);}catch{}}removeItem(e){if(n())try{window.sessionStorage.removeItem(e);}catch{}}},S=class{constructor(e){this.options={secure:n()&&window.location.protocol==="https:",sameSite:"lax",path:"/",...e};}getItem(e){if(!n())return null;try{let t=document.cookie.split(";");for(let s of t){let[i,o]=s.trim().split("=");if(i===e)return decodeURIComponent(o)}return null}catch{return null}}setItem(e,t){if(n())try{let s=`${e}=${encodeURIComponent(t)}`;s+=`; path=${this.options.path}`,s+=`; samesite=${this.options.sameSite}`,this.options.secure&&(s+="; secure"),this.options.domain&&(s+=`; domain=${this.options.domain}`),this.options.maxAge&&(s+=`; max-age=${this.options.maxAge}`),document.cookie=s;}catch{}}removeItem(e){if(n())try{document.cookie=`${e}=; path=${this.options.path}; expires=Thu, 01 Jan 1970 00:00:00 GMT`;}catch{}}};function y(){return _()?new l:new d}var c=class{constructor(e,t="vaif.auth."){this.adapter=e,this.keyPrefix=t;}key(e){return `${this.keyPrefix}${e}`}async getSession(){try{let e=await this.adapter.getItem(this.key("session"));if(!e)return null;let t=JSON.parse(e);return t.expiresAt&&t.expiresAt<Date.now()?(await this.removeSession(),null):t}catch{return null}}async setSession(e){try{await this.adapter.setItem(this.key("session"),JSON.stringify(e));}catch{}}async removeSession(){try{await this.adapter.removeItem(this.key("session"));}catch{}}async getRefreshToken(){try{return await this.adapter.getItem(this.key("refresh_token"))}catch{return null}}async setRefreshToken(e){try{await this.adapter.setItem(this.key("refresh_token"),e);}catch{}}async removeRefreshToken(){try{await this.adapter.removeItem(this.key("refresh_token"));}catch{}}async clear(){await this.removeSession(),await this.removeRefreshToken();}},A=new d,O=_()?new l:A,k=n()?new m:A,v=r=>new S(r);function P(){if(typeof crypto<"u"&&crypto.getRandomValues){let r=new Uint8Array(32);return crypto.getRandomValues(r),Array.from(r,e=>e.toString(16).padStart(2,"0")).join("")}return Array.from({length:64},()=>Math.floor(Math.random()*36).toString(36)).join("")}async function I(r){if(typeof crypto<"u"&&crypto.subtle){let t=new TextEncoder().encode(r),s=await crypto.subtle.digest("SHA-256",t);return btoa(String.fromCharCode(...new Uint8Array(s))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}return r}var T={storageKey:"vaif.auth.",autoRefreshToken:true,persistSession:true,detectSessionInUrl:true,flowType:"implicit",debug:false},R=60*1e3,p=class{constructor(e){this.refreshTimer=null;this.listeners=new Set;this.initialized=false;this.initPromise=null;this.currentSession=null;this.broadcastChannel=null;this.config={...T,...e,headers:e.headers||{},storage:e.storage||y()},this.storage=new c(this.config.storage,this.config.storageKey);}async initialize(){return this.initPromise?this.initPromise.then(()=>this.currentSession):(this.initPromise=this._initialize(),await this.initPromise,this.currentSession)}async _initialize(){if(!this.initialized){if(this.config.detectSessionInUrl&&n()){let e=await this._handleUrlSession();if(e){this.currentSession=e,await this._persistSession(e),this._notifyListeners("SIGNED_IN",e),this._setupAutoRefresh(e),this.initialized=true;return}}if(this.config.persistSession){let e=await this.storage.getSession();e&&(this.currentSession=e,this._notifyListeners("INITIAL_SESSION",e),this._setupAutoRefresh(e));}this.initialized=true,n()&&typeof BroadcastChannel<"u"&&(this.broadcastChannel=new BroadcastChannel(`${this.config.storageKey}sync`),this.broadcastChannel.onmessage=e=>{let{type:t,session:s}=e.data;t==="SESSION_UPDATE"&&(this.currentSession=s,this._notifyListeners(s?"TOKEN_REFRESHED":"SIGNED_OUT",s),s?this._setupAutoRefresh(s):this._clearRefreshTimer());});}}async getSession(){return await this.initialize(),this.currentSession}async getUser(){return (await this.getSession())?.user??null}async setSession(e,t){let s=await this._fetchUser(e),i={accessToken:e,refreshToken:t,expiresAt:Date.now()+3600*1e3,expiresIn:3600,tokenType:"bearer",user:s};return this.currentSession=i,await this._persistSession(i),this._notifyListeners("SIGNED_IN",i),this._setupAutoRefresh(i),{session:i,user:s}}async refreshSession(){let e=await this.getSession();if(!e?.refreshToken)return null;try{let t=await this._refreshToken(e.refreshToken),s={...e,accessToken:t.accessToken,refreshToken:t.refreshToken||e.refreshToken,expiresAt:t.expiresAt,expiresIn:t.expiresIn};return this.currentSession=s,await this._persistSession(s),this._notifyListeners("TOKEN_REFRESHED",s),this._setupAutoRefresh(s),s}catch(t){return this._log("Failed to refresh session:",t),await this.signOut(),null}}async signUp(e){let t=await this._fetch("/auth/signup",{method:"POST",body:JSON.stringify({email:e.email,password:e.password,name:e.name,phone:e.phone,metadata:e.metadata,redirectUrl:e.redirectUrl||e.emailRedirectTo})});return u(t)||(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session)),t}async signInWithPassword(e){let t=await this._fetch("/auth/login",{method:"POST",body:JSON.stringify({email:e.email,password:e.password,mfaCode:e.mfaCode,rememberMe:e.rememberMe})});return u(t)||(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session)),t}async signInWithOAuth(e){let t=await this._fetch("/auth/oauth/authorize",{method:"POST",body:JSON.stringify({provider:e.provider,redirectUrl:e.redirectTo,scopes:e.scopes,queryParams:e.queryParams,flowType:this.config.flowType})});return n()&&(window.location.href=t.url),t}async signInWithMagicLink(e){return this._fetch("/auth/magic-link/send",{method:"POST",body:JSON.stringify({email:e.email,redirectUrl:e.redirectTo,shouldCreateUser:e.shouldCreateUser})})}async signInWithOTP(e){let t=e.phone?"/auth/phone/send":"/auth/otp/send";return this._fetch(t,{method:"POST",body:JSON.stringify({email:e.email,phone:e.phone,channel:e.channel,shouldCreateUser:e.shouldCreateUser})})}async verifyOTP(e){let t=await this._fetch("/auth/otp/verify",{method:"POST",body:JSON.stringify({email:e.email,phone:e.phone,token:e.token,type:e.type})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session),t}async signInAnonymously(e){let t=await this._fetch("/auth/anonymous",{method:"POST",body:JSON.stringify({metadata:e?.metadata})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session),t}async signInWithSSO(e){let t=await this._fetch("/auth/sso/authorize",{method:"POST",body:JSON.stringify({domain:e.domain,providerId:e.providerId,redirectUrl:e.redirectTo})});return n()&&(window.location.href=t.url),t}async signOut(){try{this.currentSession&&await this._fetch("/auth/logout",{method:"POST"});}catch{}this._clearRefreshTimer(),this.currentSession=null,await this.storage.clear(),this._notifyListeners("SIGNED_OUT",null),this._broadcastSessionUpdate(null);}async signOutAll(){try{await this._fetch("/auth/logout-all",{method:"POST"});}catch{}this._clearRefreshTimer(),this.currentSession=null,await this.storage.clear(),this._notifyListeners("SIGNED_OUT",null);}async resetPasswordForEmail(e){return this._fetch("/auth/forgot-password",{method:"POST",body:JSON.stringify({email:e.email,redirectUrl:e.redirectTo})})}async updatePassword(e){return this._fetch("/users/me/change-password",{method:"POST",body:JSON.stringify({currentPassword:e.currentPassword,newPassword:e.newPassword})})}async setPassword(e){let t=await this._fetch("/auth/reset-password",{method:"POST",body:JSON.stringify({token:e.token,password:e.password})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("PASSWORD_RECOVERY",t.session),this._setupAutoRefresh(t.session),t}async updateUser(e){let t=await this._fetch("/users/me",{method:"PATCH",body:JSON.stringify(e)});return this.currentSession&&(this.currentSession={...this.currentSession,user:t.user},await this._persistSession(this.currentSession),this._notifyListeners("USER_UPDATED",this.currentSession)),t.user}async getUserIdentities(){return (await this._fetch("/auth/oauth/providers")).identities}async linkIdentity(e,t){let s=await this._fetch("/auth/oauth/link",{method:"POST",body:JSON.stringify({provider:e,redirectUrl:t?.redirectTo})});return n()&&(window.location.href=s.url),s}async unlinkIdentity(e){return this._fetch(`/auth/oauth/unlink/${e}`,{method:"POST"})}async listMFAFactors(){return (await this._fetch("/auth/mfa/factors")).factors}async enrollMFA(e){return this._fetch("/auth/mfa/setup",{method:"POST",body:JSON.stringify({method:e.type,friendlyName:e.friendlyName})})}async verifyMFA(e){return this._fetch("/auth/mfa/enable",{method:"POST",body:JSON.stringify({factorId:e.factorId,code:e.code})})}async challengeMFA(e){return this._fetch("/auth/mfa/challenge",{method:"POST",body:JSON.stringify({factorId:e.factorId})})}async verifyMFAChallenge(e,t){let s=await this._fetch("/auth/mfa/verify",{method:"POST",body:JSON.stringify({mfaToken:e,code:t})});return this.currentSession=s.session,await this._persistSession(s.session),this._notifyListeners("MFA_CHALLENGE_VERIFIED",s.session),this._setupAutoRefresh(s.session),s}async unenrollMFA(e,t){return this._fetch("/auth/mfa/disable",{method:"POST",body:JSON.stringify({factorId:e,code:t})})}async regenerateBackupCodes(){return this._fetch("/auth/mfa/backup-codes",{method:"POST"})}async listSessions(){return (await this._fetch("/auth/sessions")).sessions}async revokeSession(e){return this._fetch(`/auth/sessions/${e}`,{method:"DELETE"})}async revokeOtherSessions(){return this._fetch("/auth/sessions/revoke-others",{method:"POST"})}async resendEmailVerification(e){return this._fetch("/auth/verify-email/send",{method:"POST",body:JSON.stringify({redirectUrl:e?.redirectTo})})}async verifyEmail(e){let t=await this._fetch("/auth/verify-email/confirm",{method:"POST",body:JSON.stringify({token:e})});return this.currentSession&&(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("USER_UPDATED",t.session)),t}onAuthStateChange(e){return this.listeners.add(e),this.initialized&&e({event:this.currentSession?"INITIAL_SESSION":"SIGNED_OUT",session:this.currentSession}),{unsubscribe:()=>{this.listeners.delete(e);}}}async _fetch(e,t={}){let s=`${this.config.url}${e}`,i={"Content-Type":"application/json",...this.config.headers};this.config.apiKey&&(i["x-vaif-key"]=this.config.apiKey),this.currentSession?.accessToken&&(i.Authorization=`Bearer ${this.currentSession.accessToken}`);let o;try{o=await fetch(s,{...t,headers:i});}catch(a){throw new h(a instanceof Error?a.message:"Network request failed","network_error")}if(!o.ok){let a=await o.json().catch(()=>({}));throw new h(a.message||"Request failed",this._mapErrorCode(o.status,a.code),o.status,a)}return o.json()}async _fetchUser(e){let t=await fetch(`${this.config.url}/auth/me`,{headers:{Authorization:`Bearer ${e}`,...this.config.headers}});if(!t.ok)throw new h("Failed to fetch user","invalid_token",t.status);return (await t.json()).user}async _refreshToken(e){let t=await fetch(`${this.config.url}/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json",...this.config.headers},body:JSON.stringify({refreshToken:e})});if(!t.ok)throw new h("Failed to refresh token","token_expired",t.status);return t.json()}async _handleUrlSession(){if(!n())return null;let e=new URLSearchParams(window.location.hash.substring(1)),t=new URLSearchParams(window.location.search),s=e.get("access_token")||t.get("access_token"),i=e.get("refresh_token")||t.get("refresh_token"),o=e.get("expires_in")||t.get("expires_in");if(!s)return null;try{let a=await this._fetchUser(s),w={accessToken:s,refreshToken:i||void 0,expiresAt:Date.now()+(o?parseInt(o,10)*1e3:36e5),expiresIn:o?parseInt(o,10):3600,tokenType:"bearer",user:a};return window.history.replaceState(null,"",window.location.pathname),w}catch(a){return this._log("Failed to handle URL session:",a),null}}async _persistSession(e){this.config.persistSession&&(await this.storage.setSession(e),e.refreshToken&&await this.storage.setRefreshToken(e.refreshToken),this._broadcastSessionUpdate(e));}_setupAutoRefresh(e){if(!this.config.autoRefreshToken||!e.refreshToken)return;this._clearRefreshTimer();let t=e.expiresAt,s=Date.now(),i=Math.max(0,t-s-R);this._log(`Setting up auto refresh in ${Math.round(i/1e3)}s`),this.refreshTimer=setTimeout(()=>{this.refreshSession();},i);}_clearRefreshTimer(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null);}_notifyListeners(e,t){let s={event:e,session:t};this.listeners.forEach(i=>{try{i(s);}catch(o){this._log("Error in auth state change listener:",o);}});}_mapErrorCode(e,t){if(t){let s={invalid_credentials:"invalid_credentials",user_not_found:"user_not_found",user_already_exists:"user_already_exists",email_not_verified:"email_not_verified",phone_not_verified:"phone_not_verified",invalid_token:"invalid_token",token_expired:"token_expired",mfa_required:"mfa_required",mfa_invalid:"mfa_invalid",rate_limited:"rate_limited",weak_password:"weak_password",invalid_email:"invalid_email",invalid_phone:"invalid_phone"};if(s[t])return s[t]}switch(e){case 401:return "invalid_credentials";case 403:return "token_expired";case 404:return "user_not_found";case 409:return "user_already_exists";case 429:return "rate_limited";default:return "unknown_error"}}_broadcastSessionUpdate(e){try{this.broadcastChannel?.postMessage({type:"SESSION_UPDATE",session:e});}catch{}}destroy(){this._clearRefreshTimer(),this.broadcastChannel?.close(),this.broadcastChannel=null,this.listeners.clear();}_log(...e){this.config.debug&&console.log("[VaifAuth]",...e);}};function C(r){return new p(r)}
|
|
2
|
+
exports.AuthError=h;exports.InvalidCredentialsError=f;exports.SessionExpiredError=g;exports.SessionStorage=c;exports.VaifAuthClient=p;exports.cookieStorage=v;exports.createAuthClient=C;exports.generateCodeChallenge=I;exports.generateCodeVerifier=P;exports.getDefaultStorage=y;exports.isBrowser=n;exports.isMFAChallenge=u;exports.localStorage=O;exports.memoryStorage=A;exports.sessionStorage=k;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{b as AuthError,d as InvalidCredentialsError,c as SessionExpiredError,g as SessionStorage,
|
|
1
|
+
export{b as AuthError,d as InvalidCredentialsError,c as SessionExpiredError,g as SessionStorage,n as VaifAuthClient,k as cookieStorage,o as createAuthClient,m as generateCodeChallenge,l as generateCodeVerifier,f as getDefaultStorage,e as isBrowser,a as isMFAChallenge,i as localStorage,h as memoryStorage,j as sessionStorage}from'./chunk-VKUCT6DW.mjs';
|
package/dist/react.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { E as AuthClientConfig, V as VaifAuthClient, a as Session, U as User, f as SignUpOptions, e as AuthResponse, M as MFAChallenge, g as SignInWithPasswordOptions, h as SignInWithOAuthOptions, i as SignInWithMagicLinkOptions, t as MFAFactor, u as MFASetupResponse, r as OAuthIdentity, O as OAuthProviderType, q as OAuthResponse, d as SessionInfo } from './client-
|
|
2
|
-
export { z as AuthChangeEvent, y as AuthEventType, D as AuthSubscription, c as createAuthClient } from './client-
|
|
1
|
+
import { E as AuthClientConfig, V as VaifAuthClient, a as Session, U as User, f as SignUpOptions, e as AuthResponse, M as MFAChallenge, g as SignInWithPasswordOptions, h as SignInWithOAuthOptions, i as SignInWithMagicLinkOptions, t as MFAFactor, u as MFASetupResponse, r as OAuthIdentity, O as OAuthProviderType, q as OAuthResponse, d as SessionInfo } from './client-DYj4LiUx.mjs';
|
|
2
|
+
export { z as AuthChangeEvent, y as AuthEventType, D as AuthSubscription, l as SignInWithSSOOptions, c as createAuthClient } from './client-DYj4LiUx.mjs';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
5
5
|
|
|
@@ -154,5 +154,17 @@ declare function useSessions(): {
|
|
|
154
154
|
}>;
|
|
155
155
|
refresh: () => Promise<void>;
|
|
156
156
|
};
|
|
157
|
+
/**
|
|
158
|
+
* SSO authentication hook
|
|
159
|
+
*/
|
|
160
|
+
declare function useSSO(): {
|
|
161
|
+
signInWithSSO: (options: {
|
|
162
|
+
domain?: string;
|
|
163
|
+
providerId?: string;
|
|
164
|
+
redirectTo?: string;
|
|
165
|
+
}) => Promise<OAuthResponse>;
|
|
166
|
+
isLoading: boolean;
|
|
167
|
+
error: Error | null;
|
|
168
|
+
};
|
|
157
169
|
|
|
158
|
-
export { AuthClientConfig, AuthProvider, type AuthProviderProps, AuthResponse, MFAChallenge, MFAFactor, Session, User, VaifAuthClient, useAuth, useAuthClient, useIdentities, useIsAuthenticated, useMFA, usePassword, useSession, useSessions, useUser };
|
|
170
|
+
export { AuthClientConfig, AuthProvider, type AuthProviderProps, AuthResponse, MFAChallenge, MFAFactor, Session, User, VaifAuthClient, useAuth, useAuthClient, useIdentities, useIsAuthenticated, useMFA, usePassword, useSSO, useSession, useSessions, useUser };
|
package/dist/react.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { E as AuthClientConfig, V as VaifAuthClient, a as Session, U as User, f as SignUpOptions, e as AuthResponse, M as MFAChallenge, g as SignInWithPasswordOptions, h as SignInWithOAuthOptions, i as SignInWithMagicLinkOptions, t as MFAFactor, u as MFASetupResponse, r as OAuthIdentity, O as OAuthProviderType, q as OAuthResponse, d as SessionInfo } from './client-
|
|
2
|
-
export { z as AuthChangeEvent, y as AuthEventType, D as AuthSubscription, c as createAuthClient } from './client-
|
|
1
|
+
import { E as AuthClientConfig, V as VaifAuthClient, a as Session, U as User, f as SignUpOptions, e as AuthResponse, M as MFAChallenge, g as SignInWithPasswordOptions, h as SignInWithOAuthOptions, i as SignInWithMagicLinkOptions, t as MFAFactor, u as MFASetupResponse, r as OAuthIdentity, O as OAuthProviderType, q as OAuthResponse, d as SessionInfo } from './client-DYj4LiUx.js';
|
|
2
|
+
export { z as AuthChangeEvent, y as AuthEventType, D as AuthSubscription, l as SignInWithSSOOptions, c as createAuthClient } from './client-DYj4LiUx.js';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
5
5
|
|
|
@@ -154,5 +154,17 @@ declare function useSessions(): {
|
|
|
154
154
|
}>;
|
|
155
155
|
refresh: () => Promise<void>;
|
|
156
156
|
};
|
|
157
|
+
/**
|
|
158
|
+
* SSO authentication hook
|
|
159
|
+
*/
|
|
160
|
+
declare function useSSO(): {
|
|
161
|
+
signInWithSSO: (options: {
|
|
162
|
+
domain?: string;
|
|
163
|
+
providerId?: string;
|
|
164
|
+
redirectTo?: string;
|
|
165
|
+
}) => Promise<OAuthResponse>;
|
|
166
|
+
isLoading: boolean;
|
|
167
|
+
error: Error | null;
|
|
168
|
+
};
|
|
157
169
|
|
|
158
|
-
export { AuthClientConfig, AuthProvider, type AuthProviderProps, AuthResponse, MFAChallenge, MFAFactor, Session, User, VaifAuthClient, useAuth, useAuthClient, useIdentities, useIsAuthenticated, useMFA, usePassword, useSession, useSessions, useUser };
|
|
170
|
+
export { AuthClientConfig, AuthProvider, type AuthProviderProps, AuthResponse, MFAChallenge, MFAFactor, Session, User, VaifAuthClient, useAuth, useAuthClient, useIdentities, useIsAuthenticated, useMFA, usePassword, useSSO, useSession, useSessions, useUser };
|
package/dist/react.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');function I(s){return "mfaRequired"in s&&s.mfaRequired===true}var m=class s extends Error{constructor(e,t,r,n){super(e),this.name="AuthError",this.code=t,this.status=r,this.details=n;}static isAuthError(e){return e instanceof s}};function f(){return typeof window<"u"&&typeof window.document<"u"}function C(){if(!f())return false;try{let s="__vaif_test__";return window.localStorage.setItem(s,s),window.localStorage.removeItem(s),!0}catch{return false}}var w=class{constructor(){this.storage=new Map;}getItem(e){return this.storage.get(e)??null}setItem(e,t){this.storage.set(e,t);}removeItem(e){this.storage.delete(e);}clear(){this.storage.clear();}},_=class{getItem(e){if(!f())return null;try{return window.localStorage.getItem(e)}catch{return null}}setItem(e,t){if(f())try{window.localStorage.setItem(e,t);}catch{}}removeItem(e){if(f())try{window.localStorage.removeItem(e);}catch{}}};function R(){return C()?new _:new w}var v=class{constructor(e,t="vaif.auth."){this.adapter=e,this.keyPrefix=t;}key(e){return `${this.keyPrefix}${e}`}async getSession(){try{let e=await this.adapter.getItem(this.key("session"));if(!e)return null;let t=JSON.parse(e);return t.expiresAt&&t.expiresAt<Date.now()?(await this.removeSession(),null):t}catch{return null}}async setSession(e){try{await this.adapter.setItem(this.key("session"),JSON.stringify(e));}catch{}}async removeSession(){try{await this.adapter.removeItem(this.key("session"));}catch{}}async getRefreshToken(){try{return await this.adapter.getItem(this.key("refresh_token"))}catch{return null}}async setRefreshToken(e){try{await this.adapter.setItem(this.key("refresh_token"),e);}catch{}}async removeRefreshToken(){try{await this.adapter.removeItem(this.key("refresh_token"));}catch{}}async clear(){await this.removeSession(),await this.removeRefreshToken();}},b=new w;C()?new _:b;var U={storageKey:"vaif.auth.",autoRefreshToken:true,persistSession:true,detectSessionInUrl:true,flowType:"implicit",debug:false},F=60*1e3,P=class{constructor(e){this.refreshTimer=null;this.listeners=new Set;this.initialized=false;this.initPromise=null;this.currentSession=null;this.config={...U,...e,headers:e.headers||{},storage:e.storage||R()},this.storage=new v(this.config.storage,this.config.storageKey);}async initialize(){return this.initPromise?this.initPromise.then(()=>this.currentSession):(this.initPromise=this._initialize(),await this.initPromise,this.currentSession)}async _initialize(){if(!this.initialized){if(this.config.detectSessionInUrl&&f()){let e=await this._handleUrlSession();if(e){this.currentSession=e,await this._persistSession(e),this._notifyListeners("SIGNED_IN",e),this._setupAutoRefresh(e),this.initialized=true;return}}if(this.config.persistSession){let e=await this.storage.getSession();e&&(this.currentSession=e,this._notifyListeners("INITIAL_SESSION",e),this._setupAutoRefresh(e));}this.initialized=true;}}async getSession(){return await this.initialize(),this.currentSession}async getUser(){return (await this.getSession())?.user??null}async setSession(e,t){let r=await this._fetchUser(e),n={accessToken:e,refreshToken:t,expiresAt:Date.now()+3600*1e3,expiresIn:3600,tokenType:"bearer",user:r};return this.currentSession=n,await this._persistSession(n),this._notifyListeners("SIGNED_IN",n),this._setupAutoRefresh(n),{session:n,user:r}}async refreshSession(){let e=await this.getSession();if(!e?.refreshToken)return null;try{let t=await this._refreshToken(e.refreshToken),r={...e,accessToken:t.accessToken,refreshToken:t.refreshToken||e.refreshToken,expiresAt:t.expiresAt,expiresIn:t.expiresIn};return this.currentSession=r,await this._persistSession(r),this._notifyListeners("TOKEN_REFRESHED",r),this._setupAutoRefresh(r),r}catch(t){return this._log("Failed to refresh session:",t),await this.signOut(),null}}async signUp(e){let t=await this._fetch("/auth/signup",{method:"POST",body:JSON.stringify({email:e.email,password:e.password,name:e.name,phone:e.phone,metadata:e.metadata,redirectUrl:e.redirectUrl||e.emailRedirectTo})});return I(t)||(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session)),t}async signInWithPassword(e){let t=await this._fetch("/auth/login",{method:"POST",body:JSON.stringify({email:e.email,password:e.password,mfaCode:e.mfaCode,rememberMe:e.rememberMe})});return I(t)||(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session)),t}async signInWithOAuth(e){let t=await this._fetch("/auth/oauth/authorize",{method:"POST",body:JSON.stringify({provider:e.provider,redirectUrl:e.redirectTo,scopes:e.scopes,queryParams:e.queryParams,flowType:this.config.flowType})});return f()&&(window.location.href=t.url),t}async signInWithMagicLink(e){return this._fetch("/auth/magic-link/send",{method:"POST",body:JSON.stringify({email:e.email,redirectUrl:e.redirectTo,shouldCreateUser:e.shouldCreateUser})})}async signInWithOTP(e){let t=e.phone?"/auth/phone/send":"/auth/otp/send";return this._fetch(t,{method:"POST",body:JSON.stringify({email:e.email,phone:e.phone,channel:e.channel,shouldCreateUser:e.shouldCreateUser})})}async verifyOTP(e){let t=await this._fetch("/auth/otp/verify",{method:"POST",body:JSON.stringify({email:e.email,phone:e.phone,token:e.token,type:e.type})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session),t}async signInAnonymously(e){let t=await this._fetch("/auth/anonymous",{method:"POST",body:JSON.stringify({metadata:e?.metadata})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session),t}async signOut(){try{this.currentSession&&await this._fetch("/auth/logout",{method:"POST"});}catch{}this._clearRefreshTimer(),this.currentSession=null,await this.storage.clear(),this._notifyListeners("SIGNED_OUT",null);}async signOutAll(){try{await this._fetch("/auth/logout-all",{method:"POST"});}catch{}this._clearRefreshTimer(),this.currentSession=null,await this.storage.clear(),this._notifyListeners("SIGNED_OUT",null);}async resetPasswordForEmail(e){return this._fetch("/auth/forgot-password",{method:"POST",body:JSON.stringify({email:e.email,redirectUrl:e.redirectTo})})}async updatePassword(e){return this._fetch("/users/me/change-password",{method:"POST",body:JSON.stringify({currentPassword:e.currentPassword,newPassword:e.newPassword})})}async setPassword(e){let t=await this._fetch("/auth/reset-password",{method:"POST",body:JSON.stringify({token:e.token,password:e.password})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("PASSWORD_RECOVERY",t.session),this._setupAutoRefresh(t.session),t}async updateUser(e){let t=await this._fetch("/users/me",{method:"PATCH",body:JSON.stringify(e)});return this.currentSession&&(this.currentSession={...this.currentSession,user:t.user},await this._persistSession(this.currentSession),this._notifyListeners("USER_UPDATED",this.currentSession)),t.user}async getUserIdentities(){return (await this._fetch("/auth/oauth/providers")).identities}async linkIdentity(e,t){let r=await this._fetch("/auth/oauth/link",{method:"POST",body:JSON.stringify({provider:e,redirectUrl:t?.redirectTo})});return f()&&(window.location.href=r.url),r}async unlinkIdentity(e){return this._fetch(`/auth/oauth/unlink/${e}`,{method:"POST"})}async listMFAFactors(){return (await this._fetch("/auth/mfa/factors")).factors}async enrollMFA(e){return this._fetch("/auth/mfa/setup",{method:"POST",body:JSON.stringify({method:e.type,friendlyName:e.friendlyName})})}async verifyMFA(e){return this._fetch("/auth/mfa/enable",{method:"POST",body:JSON.stringify({factorId:e.factorId,code:e.code})})}async challengeMFA(e){return this._fetch("/auth/mfa/challenge",{method:"POST",body:JSON.stringify({factorId:e.factorId})})}async verifyMFAChallenge(e,t){let r=await this._fetch("/auth/mfa/verify",{method:"POST",body:JSON.stringify({mfaToken:e,code:t})});return this.currentSession=r.session,await this._persistSession(r.session),this._notifyListeners("MFA_CHALLENGE_VERIFIED",r.session),this._setupAutoRefresh(r.session),r}async unenrollMFA(e,t){return this._fetch("/auth/mfa/disable",{method:"POST",body:JSON.stringify({factorId:e,code:t})})}async regenerateBackupCodes(){return this._fetch("/auth/mfa/backup-codes",{method:"POST"})}async listSessions(){return (await this._fetch("/auth/sessions")).sessions}async revokeSession(e){return this._fetch(`/auth/sessions/${e}`,{method:"DELETE"})}async revokeOtherSessions(){return this._fetch("/auth/sessions/revoke-others",{method:"POST"})}async resendEmailVerification(e){return this._fetch("/auth/verify-email/send",{method:"POST",body:JSON.stringify({redirectUrl:e?.redirectTo})})}async verifyEmail(e){let t=await this._fetch("/auth/verify-email/confirm",{method:"POST",body:JSON.stringify({token:e})});return this.currentSession&&(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("USER_UPDATED",t.session)),t}onAuthStateChange(e){return this.listeners.add(e),this.initialized&&e({event:this.currentSession?"INITIAL_SESSION":"SIGNED_OUT",session:this.currentSession}),{unsubscribe:()=>{this.listeners.delete(e);}}}async _fetch(e,t={}){let r=`${this.config.url}${e}`,n={"Content-Type":"application/json",...this.config.headers};this.config.apiKey&&(n["x-vaif-key"]=this.config.apiKey),this.currentSession?.accessToken&&(n.Authorization=`Bearer ${this.currentSession.accessToken}`);let o=await fetch(r,{...t,headers:n});if(!o.ok){let h=await o.json().catch(()=>({}));throw new m(h.message||"Request failed",this._mapErrorCode(o.status,h.code),o.status,h)}return o.json()}async _fetchUser(e){let t=await fetch(`${this.config.url}/auth/me`,{headers:{Authorization:`Bearer ${e}`,...this.config.headers}});if(!t.ok)throw new m("Failed to fetch user","invalid_token",t.status);return (await t.json()).user}async _refreshToken(e){let t=await fetch(`${this.config.url}/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json",...this.config.headers},body:JSON.stringify({refreshToken:e})});if(!t.ok)throw new m("Failed to refresh token","token_expired",t.status);return t.json()}async _handleUrlSession(){if(!f())return null;let e=new URLSearchParams(window.location.hash.substring(1)),t=new URLSearchParams(window.location.search),r=e.get("access_token")||t.get("access_token"),n=e.get("refresh_token")||t.get("refresh_token"),o=e.get("expires_in")||t.get("expires_in");if(!r)return null;try{let h=await this._fetchUser(r),i={accessToken:r,refreshToken:n||void 0,expiresAt:Date.now()+(o?parseInt(o,10)*1e3:36e5),expiresIn:o?parseInt(o,10):3600,tokenType:"bearer",user:h};return window.history.replaceState(null,"",window.location.pathname),i}catch(h){return this._log("Failed to handle URL session:",h),null}}async _persistSession(e){this.config.persistSession&&(await this.storage.setSession(e),e.refreshToken&&await this.storage.setRefreshToken(e.refreshToken));}_setupAutoRefresh(e){if(!this.config.autoRefreshToken||!e.refreshToken)return;this._clearRefreshTimer();let t=e.expiresAt,r=Date.now(),n=Math.max(0,t-r-F);this._log(`Setting up auto refresh in ${Math.round(n/1e3)}s`),this.refreshTimer=setTimeout(()=>{this.refreshSession();},n);}_clearRefreshTimer(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null);}_notifyListeners(e,t){let r={event:e,session:t};this.listeners.forEach(n=>{try{n(r);}catch(o){this._log("Error in auth state change listener:",o);}});}_mapErrorCode(e,t){if(t){let r={invalid_credentials:"invalid_credentials",user_not_found:"user_not_found",user_already_exists:"user_already_exists",email_not_verified:"email_not_verified",phone_not_verified:"phone_not_verified",invalid_token:"invalid_token",token_expired:"token_expired",mfa_required:"mfa_required",mfa_invalid:"mfa_invalid",rate_limited:"rate_limited",weak_password:"weak_password",invalid_email:"invalid_email",invalid_phone:"invalid_phone"};if(r[t])return r[t]}switch(e){case 401:return "invalid_credentials";case 403:return "token_expired";case 404:return "user_not_found";case 409:return "user_already_exists";case 429:return "rate_limited";default:return "unknown_error"}}_log(...e){this.config.debug&&console.log("[VaifAuth]",...e);}};function x(s){return new P(s)}var E=react.createContext(null);function B({children:s,config:e,client:t,initialSession:r=null}){let[n]=react.useState(()=>{if(t)return t;if(!e)throw new Error("AuthProvider requires either config or client prop");return x(e)}),[o,h]=react.useState(r),[i,g]=react.useState(!r),[c,a]=react.useState(null);react.useEffect(()=>{let d=true;n.initialize().then(S=>{d&&(h(S),g(false));}).catch(S=>{d&&(a(S),g(false));});let{unsubscribe:y}=n.onAuthStateChange(S=>{d&&(h(S.session),a(null));});return ()=>{d=false,y();}},[n]);let u=react.useMemo(()=>({client:n,session:o,user:o?.user??null,isLoading:i,isAuthenticated:!!o,error:c}),[n,o,i,c]);return jsxRuntime.jsx(E.Provider,{value:u,children:s})}function A(){let s=react.useContext(E);if(!s)throw new Error("useAuth must be used within an AuthProvider");return s}function O(){let{client:s}=A();return s}function Y(){let{client:s,session:e,user:t,isLoading:r,isAuthenticated:n,error:o}=A(),h=react.useCallback(async d=>s.signUp(d),[s]),i=react.useCallback(async d=>s.signInWithPassword(d),[s]),g=react.useCallback(async d=>{await s.signInWithOAuth(d);},[s]),c=react.useCallback(async d=>s.signInWithMagicLink(d),[s]),a=react.useCallback(async()=>s.signOut(),[s]),u=react.useCallback(async()=>s.refreshSession(),[s]);return {session:e,user:t,isLoading:r,isAuthenticated:n,error:o,signUp:h,signInWithPassword:i,signInWithOAuth:g,signInWithMagicLink:c,signOut:a,refreshSession:u,client:s}}function Q(){let{user:s}=A();return s}function X(){let{session:s}=A();return s}function Z(){let{isAuthenticated:s}=A();return s}function ee(){let s=O(),[e,t]=react.useState(false),[r,n]=react.useState(null),o=react.useCallback(async(i,g)=>{t(true),n(null);try{return await s.resetPasswordForEmail({email:i,redirectTo:g})}catch(c){throw n(c),c}finally{t(false);}},[s]),h=react.useCallback(async(i,g)=>{t(true),n(null);try{return await s.updatePassword({currentPassword:i,newPassword:g})}catch(c){throw n(c),c}finally{t(false);}},[s]);return {resetPassword:o,updatePassword:h,isLoading:e,error:r}}function te(){let s=O(),[e,t]=react.useState([]),[r,n]=react.useState(false),[o,h]=react.useState(null),i=react.useCallback(async()=>{n(true);try{let u=await s.listMFAFactors();t(u);}catch(u){h(u);}finally{n(false);}},[s]),g=react.useCallback(async u=>s.enrollMFA({type:"totp",friendlyName:u}),[s]),c=react.useCallback(async(u,d)=>{let y=await s.verifyMFA({factorId:u,code:d});return await i(),y},[s,i]),a=react.useCallback(async(u,d)=>{let y=await s.unenrollMFA(u,d);return await i(),y},[s,i]);return react.useEffect(()=>{i();},[i]),{factors:e,isLoading:r,error:o,enrollTOTP:g,verifyMFA:c,unenroll:a,refresh:i}}function se(){let s=O(),[e,t]=react.useState([]),[r,n]=react.useState(true),[o,h]=react.useState(null),i=react.useCallback(async()=>{n(true);try{let a=await s.getUserIdentities();t(a);}catch(a){h(a);}finally{n(false);}},[s]),g=react.useCallback(async(a,u)=>s.linkIdentity(a,{redirectTo:u}),[s]),c=react.useCallback(async a=>{let u=await s.unlinkIdentity(a);return await i(),u},[s,i]);return react.useEffect(()=>{i();},[i]),{identities:e,isLoading:r,error:o,linkIdentity:g,unlinkIdentity:c,refresh:i}}function re(){let s=O(),[e,t]=react.useState([]),[r,n]=react.useState(true),[o,h]=react.useState(null),i=react.useCallback(async()=>{n(true);try{let a=await s.listSessions();t(a);}catch(a){h(a);}finally{n(false);}},[s]),g=react.useCallback(async a=>{let u=await s.revokeSession(a);return await i(),u},[s,i]),c=react.useCallback(async()=>{let a=await s.revokeOtherSessions();return await i(),a},[s,i]);return react.useEffect(()=>{i();},[i]),{sessions:e,isLoading:r,error:o,revokeSession:g,revokeOtherSessions:c,refresh:i}}exports.AuthProvider=B;exports.VaifAuthClient=P;exports.createAuthClient=x;exports.useAuth=Y;exports.useAuthClient=O;exports.useIdentities=se;exports.useIsAuthenticated=Z;exports.useMFA=te;exports.usePassword=ee;exports.useSession=X;exports.useSessions=re;exports.useUser=Q;
|
|
1
|
+
'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');function k(s){return "mfaRequired"in s&&s.mfaRequired===true}var m=class s extends Error{constructor(e,t,r,n){super(e),this.name="AuthError",this.code=t,this.status=r,this.details=n;}static isAuthError(e){return e instanceof s}};function g(){return typeof window<"u"&&typeof window.document<"u"}function R(){if(!g())return false;try{let s="__vaif_test__";return window.localStorage.setItem(s,s),window.localStorage.removeItem(s),!0}catch{return false}}var _=class{constructor(){this.storage=new Map;}getItem(e){return this.storage.get(e)??null}setItem(e,t){this.storage.set(e,t);}removeItem(e){this.storage.delete(e);}clear(){this.storage.clear();}},O=class{getItem(e){if(!g())return null;try{return window.localStorage.getItem(e)}catch{return null}}setItem(e,t){if(g())try{window.localStorage.setItem(e,t);}catch{}}removeItem(e){if(g())try{window.localStorage.removeItem(e);}catch{}}};function x(){return R()?new O:new _}var v=class{constructor(e,t="vaif.auth."){this.adapter=e,this.keyPrefix=t;}key(e){return `${this.keyPrefix}${e}`}async getSession(){try{let e=await this.adapter.getItem(this.key("session"));if(!e)return null;let t=JSON.parse(e);return t.expiresAt&&t.expiresAt<Date.now()?(await this.removeSession(),null):t}catch{return null}}async setSession(e){try{await this.adapter.setItem(this.key("session"),JSON.stringify(e));}catch{}}async removeSession(){try{await this.adapter.removeItem(this.key("session"));}catch{}}async getRefreshToken(){try{return await this.adapter.getItem(this.key("refresh_token"))}catch{return null}}async setRefreshToken(e){try{await this.adapter.setItem(this.key("refresh_token"),e);}catch{}}async removeRefreshToken(){try{await this.adapter.removeItem(this.key("refresh_token"));}catch{}}async clear(){await this.removeSession(),await this.removeRefreshToken();}},b=new _;R()?new O:b;var U={storageKey:"vaif.auth.",autoRefreshToken:true,persistSession:true,detectSessionInUrl:true,flowType:"implicit",debug:false},F=60*1e3,P=class{constructor(e){this.refreshTimer=null;this.listeners=new Set;this.initialized=false;this.initPromise=null;this.currentSession=null;this.broadcastChannel=null;this.config={...U,...e,headers:e.headers||{},storage:e.storage||x()},this.storage=new v(this.config.storage,this.config.storageKey);}async initialize(){return this.initPromise?this.initPromise.then(()=>this.currentSession):(this.initPromise=this._initialize(),await this.initPromise,this.currentSession)}async _initialize(){if(!this.initialized){if(this.config.detectSessionInUrl&&g()){let e=await this._handleUrlSession();if(e){this.currentSession=e,await this._persistSession(e),this._notifyListeners("SIGNED_IN",e),this._setupAutoRefresh(e),this.initialized=true;return}}if(this.config.persistSession){let e=await this.storage.getSession();e&&(this.currentSession=e,this._notifyListeners("INITIAL_SESSION",e),this._setupAutoRefresh(e));}this.initialized=true,g()&&typeof BroadcastChannel<"u"&&(this.broadcastChannel=new BroadcastChannel(`${this.config.storageKey}sync`),this.broadcastChannel.onmessage=e=>{let{type:t,session:r}=e.data;t==="SESSION_UPDATE"&&(this.currentSession=r,this._notifyListeners(r?"TOKEN_REFRESHED":"SIGNED_OUT",r),r?this._setupAutoRefresh(r):this._clearRefreshTimer());});}}async getSession(){return await this.initialize(),this.currentSession}async getUser(){return (await this.getSession())?.user??null}async setSession(e,t){let r=await this._fetchUser(e),n={accessToken:e,refreshToken:t,expiresAt:Date.now()+3600*1e3,expiresIn:3600,tokenType:"bearer",user:r};return this.currentSession=n,await this._persistSession(n),this._notifyListeners("SIGNED_IN",n),this._setupAutoRefresh(n),{session:n,user:r}}async refreshSession(){let e=await this.getSession();if(!e?.refreshToken)return null;try{let t=await this._refreshToken(e.refreshToken),r={...e,accessToken:t.accessToken,refreshToken:t.refreshToken||e.refreshToken,expiresAt:t.expiresAt,expiresIn:t.expiresIn};return this.currentSession=r,await this._persistSession(r),this._notifyListeners("TOKEN_REFRESHED",r),this._setupAutoRefresh(r),r}catch(t){return this._log("Failed to refresh session:",t),await this.signOut(),null}}async signUp(e){let t=await this._fetch("/auth/signup",{method:"POST",body:JSON.stringify({email:e.email,password:e.password,name:e.name,phone:e.phone,metadata:e.metadata,redirectUrl:e.redirectUrl||e.emailRedirectTo})});return k(t)||(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session)),t}async signInWithPassword(e){let t=await this._fetch("/auth/login",{method:"POST",body:JSON.stringify({email:e.email,password:e.password,mfaCode:e.mfaCode,rememberMe:e.rememberMe})});return k(t)||(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session)),t}async signInWithOAuth(e){let t=await this._fetch("/auth/oauth/authorize",{method:"POST",body:JSON.stringify({provider:e.provider,redirectUrl:e.redirectTo,scopes:e.scopes,queryParams:e.queryParams,flowType:this.config.flowType})});return g()&&(window.location.href=t.url),t}async signInWithMagicLink(e){return this._fetch("/auth/magic-link/send",{method:"POST",body:JSON.stringify({email:e.email,redirectUrl:e.redirectTo,shouldCreateUser:e.shouldCreateUser})})}async signInWithOTP(e){let t=e.phone?"/auth/phone/send":"/auth/otp/send";return this._fetch(t,{method:"POST",body:JSON.stringify({email:e.email,phone:e.phone,channel:e.channel,shouldCreateUser:e.shouldCreateUser})})}async verifyOTP(e){let t=await this._fetch("/auth/otp/verify",{method:"POST",body:JSON.stringify({email:e.email,phone:e.phone,token:e.token,type:e.type})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session),t}async signInAnonymously(e){let t=await this._fetch("/auth/anonymous",{method:"POST",body:JSON.stringify({metadata:e?.metadata})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session),t}async signInWithSSO(e){let t=await this._fetch("/auth/sso/authorize",{method:"POST",body:JSON.stringify({domain:e.domain,providerId:e.providerId,redirectUrl:e.redirectTo})});return g()&&(window.location.href=t.url),t}async signOut(){try{this.currentSession&&await this._fetch("/auth/logout",{method:"POST"});}catch{}this._clearRefreshTimer(),this.currentSession=null,await this.storage.clear(),this._notifyListeners("SIGNED_OUT",null),this._broadcastSessionUpdate(null);}async signOutAll(){try{await this._fetch("/auth/logout-all",{method:"POST"});}catch{}this._clearRefreshTimer(),this.currentSession=null,await this.storage.clear(),this._notifyListeners("SIGNED_OUT",null);}async resetPasswordForEmail(e){return this._fetch("/auth/forgot-password",{method:"POST",body:JSON.stringify({email:e.email,redirectUrl:e.redirectTo})})}async updatePassword(e){return this._fetch("/users/me/change-password",{method:"POST",body:JSON.stringify({currentPassword:e.currentPassword,newPassword:e.newPassword})})}async setPassword(e){let t=await this._fetch("/auth/reset-password",{method:"POST",body:JSON.stringify({token:e.token,password:e.password})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("PASSWORD_RECOVERY",t.session),this._setupAutoRefresh(t.session),t}async updateUser(e){let t=await this._fetch("/users/me",{method:"PATCH",body:JSON.stringify(e)});return this.currentSession&&(this.currentSession={...this.currentSession,user:t.user},await this._persistSession(this.currentSession),this._notifyListeners("USER_UPDATED",this.currentSession)),t.user}async getUserIdentities(){return (await this._fetch("/auth/oauth/providers")).identities}async linkIdentity(e,t){let r=await this._fetch("/auth/oauth/link",{method:"POST",body:JSON.stringify({provider:e,redirectUrl:t?.redirectTo})});return g()&&(window.location.href=r.url),r}async unlinkIdentity(e){return this._fetch(`/auth/oauth/unlink/${e}`,{method:"POST"})}async listMFAFactors(){return (await this._fetch("/auth/mfa/factors")).factors}async enrollMFA(e){return this._fetch("/auth/mfa/setup",{method:"POST",body:JSON.stringify({method:e.type,friendlyName:e.friendlyName})})}async verifyMFA(e){return this._fetch("/auth/mfa/enable",{method:"POST",body:JSON.stringify({factorId:e.factorId,code:e.code})})}async challengeMFA(e){return this._fetch("/auth/mfa/challenge",{method:"POST",body:JSON.stringify({factorId:e.factorId})})}async verifyMFAChallenge(e,t){let r=await this._fetch("/auth/mfa/verify",{method:"POST",body:JSON.stringify({mfaToken:e,code:t})});return this.currentSession=r.session,await this._persistSession(r.session),this._notifyListeners("MFA_CHALLENGE_VERIFIED",r.session),this._setupAutoRefresh(r.session),r}async unenrollMFA(e,t){return this._fetch("/auth/mfa/disable",{method:"POST",body:JSON.stringify({factorId:e,code:t})})}async regenerateBackupCodes(){return this._fetch("/auth/mfa/backup-codes",{method:"POST"})}async listSessions(){return (await this._fetch("/auth/sessions")).sessions}async revokeSession(e){return this._fetch(`/auth/sessions/${e}`,{method:"DELETE"})}async revokeOtherSessions(){return this._fetch("/auth/sessions/revoke-others",{method:"POST"})}async resendEmailVerification(e){return this._fetch("/auth/verify-email/send",{method:"POST",body:JSON.stringify({redirectUrl:e?.redirectTo})})}async verifyEmail(e){let t=await this._fetch("/auth/verify-email/confirm",{method:"POST",body:JSON.stringify({token:e})});return this.currentSession&&(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("USER_UPDATED",t.session)),t}onAuthStateChange(e){return this.listeners.add(e),this.initialized&&e({event:this.currentSession?"INITIAL_SESSION":"SIGNED_OUT",session:this.currentSession}),{unsubscribe:()=>{this.listeners.delete(e);}}}async _fetch(e,t={}){let r=`${this.config.url}${e}`,n={"Content-Type":"application/json",...this.config.headers};this.config.apiKey&&(n["x-vaif-key"]=this.config.apiKey),this.currentSession?.accessToken&&(n.Authorization=`Bearer ${this.currentSession.accessToken}`);let o;try{o=await fetch(r,{...t,headers:n});}catch(a){throw new m(a instanceof Error?a.message:"Network request failed","network_error")}if(!o.ok){let a=await o.json().catch(()=>({}));throw new m(a.message||"Request failed",this._mapErrorCode(o.status,a.code),o.status,a)}return o.json()}async _fetchUser(e){let t=await fetch(`${this.config.url}/auth/me`,{headers:{Authorization:`Bearer ${e}`,...this.config.headers}});if(!t.ok)throw new m("Failed to fetch user","invalid_token",t.status);return (await t.json()).user}async _refreshToken(e){let t=await fetch(`${this.config.url}/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json",...this.config.headers},body:JSON.stringify({refreshToken:e})});if(!t.ok)throw new m("Failed to refresh token","token_expired",t.status);return t.json()}async _handleUrlSession(){if(!g())return null;let e=new URLSearchParams(window.location.hash.substring(1)),t=new URLSearchParams(window.location.search),r=e.get("access_token")||t.get("access_token"),n=e.get("refresh_token")||t.get("refresh_token"),o=e.get("expires_in")||t.get("expires_in");if(!r)return null;try{let a=await this._fetchUser(r),i={accessToken:r,refreshToken:n||void 0,expiresAt:Date.now()+(o?parseInt(o,10)*1e3:36e5),expiresIn:o?parseInt(o,10):3600,tokenType:"bearer",user:a};return window.history.replaceState(null,"",window.location.pathname),i}catch(a){return this._log("Failed to handle URL session:",a),null}}async _persistSession(e){this.config.persistSession&&(await this.storage.setSession(e),e.refreshToken&&await this.storage.setRefreshToken(e.refreshToken),this._broadcastSessionUpdate(e));}_setupAutoRefresh(e){if(!this.config.autoRefreshToken||!e.refreshToken)return;this._clearRefreshTimer();let t=e.expiresAt,r=Date.now(),n=Math.max(0,t-r-F);this._log(`Setting up auto refresh in ${Math.round(n/1e3)}s`),this.refreshTimer=setTimeout(()=>{this.refreshSession();},n);}_clearRefreshTimer(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null);}_notifyListeners(e,t){let r={event:e,session:t};this.listeners.forEach(n=>{try{n(r);}catch(o){this._log("Error in auth state change listener:",o);}});}_mapErrorCode(e,t){if(t){let r={invalid_credentials:"invalid_credentials",user_not_found:"user_not_found",user_already_exists:"user_already_exists",email_not_verified:"email_not_verified",phone_not_verified:"phone_not_verified",invalid_token:"invalid_token",token_expired:"token_expired",mfa_required:"mfa_required",mfa_invalid:"mfa_invalid",rate_limited:"rate_limited",weak_password:"weak_password",invalid_email:"invalid_email",invalid_phone:"invalid_phone"};if(r[t])return r[t]}switch(e){case 401:return "invalid_credentials";case 403:return "token_expired";case 404:return "user_not_found";case 409:return "user_already_exists";case 429:return "rate_limited";default:return "unknown_error"}}_broadcastSessionUpdate(e){try{this.broadcastChannel?.postMessage({type:"SESSION_UPDATE",session:e});}catch{}}destroy(){this._clearRefreshTimer(),this.broadcastChannel?.close(),this.broadcastChannel=null,this.listeners.clear();}_log(...e){this.config.debug&&console.log("[VaifAuth]",...e);}};function C(s){return new P(s)}var E=react.createContext(null);function j({children:s,config:e,client:t,initialSession:r=null}){let[n]=react.useState(()=>{if(t)return t;if(!e)throw new Error("AuthProvider requires either config or client prop");return C(e)}),[o,a]=react.useState(r),[i,f]=react.useState(!r),[l,h]=react.useState(null);react.useEffect(()=>{let p=true;n.initialize().then(y=>{p&&(a(y),f(false));}).catch(y=>{p&&(h(y),f(false));});let{unsubscribe:S}=n.onAuthStateChange(y=>{p&&(a(y.session),h(null));});return ()=>{p=false,S();}},[n]);let u=react.useMemo(()=>({client:n,session:o,user:o?.user??null,isLoading:i,isAuthenticated:!!o,error:l}),[n,o,i,l]);return jsxRuntime.jsx(E.Provider,{value:u,children:s})}function A(){let s=react.useContext(E);if(!s)throw new Error("useAuth must be used within an AuthProvider");return s}function w(){let{client:s}=A();return s}function Y(){let{client:s,session:e,user:t,isLoading:r,isAuthenticated:n,error:o}=A(),a=react.useCallback(async p=>s.signUp(p),[s]),i=react.useCallback(async p=>s.signInWithPassword(p),[s]),f=react.useCallback(async p=>{await s.signInWithOAuth(p);},[s]),l=react.useCallback(async p=>s.signInWithMagicLink(p),[s]),h=react.useCallback(async()=>s.signOut(),[s]),u=react.useCallback(async()=>s.refreshSession(),[s]);return {session:e,user:t,isLoading:r,isAuthenticated:n,error:o,signUp:a,signInWithPassword:i,signInWithOAuth:f,signInWithMagicLink:l,signOut:h,refreshSession:u,client:s}}function Q(){let{user:s}=A();return s}function X(){let{session:s}=A();return s}function Z(){let{isAuthenticated:s}=A();return s}function ee(){let s=w(),[e,t]=react.useState(false),[r,n]=react.useState(null),o=react.useCallback(async(i,f)=>{t(true),n(null);try{return await s.resetPasswordForEmail({email:i,redirectTo:f})}catch(l){throw n(l),l}finally{t(false);}},[s]),a=react.useCallback(async(i,f)=>{t(true),n(null);try{return await s.updatePassword({currentPassword:i,newPassword:f})}catch(l){throw n(l),l}finally{t(false);}},[s]);return {resetPassword:o,updatePassword:a,isLoading:e,error:r}}function te(){let s=w(),[e,t]=react.useState([]),[r,n]=react.useState(false),[o,a]=react.useState(null),i=react.useCallback(async()=>{n(true);try{let u=await s.listMFAFactors();t(u);}catch(u){a(u);}finally{n(false);}},[s]),f=react.useCallback(async u=>s.enrollMFA({type:"totp",friendlyName:u}),[s]),l=react.useCallback(async(u,p)=>{let S=await s.verifyMFA({factorId:u,code:p});return await i(),S},[s,i]),h=react.useCallback(async(u,p)=>{let S=await s.unenrollMFA(u,p);return await i(),S},[s,i]);return react.useEffect(()=>{i();},[i]),{factors:e,isLoading:r,error:o,enrollTOTP:f,verifyMFA:l,unenroll:h,refresh:i}}function se(){let s=w(),[e,t]=react.useState([]),[r,n]=react.useState(true),[o,a]=react.useState(null),i=react.useCallback(async()=>{n(true);try{let h=await s.getUserIdentities();t(h);}catch(h){a(h);}finally{n(false);}},[s]),f=react.useCallback(async(h,u)=>s.linkIdentity(h,{redirectTo:u}),[s]),l=react.useCallback(async h=>{let u=await s.unlinkIdentity(h);return await i(),u},[s,i]);return react.useEffect(()=>{i();},[i]),{identities:e,isLoading:r,error:o,linkIdentity:f,unlinkIdentity:l,refresh:i}}function re(){let s=w(),[e,t]=react.useState([]),[r,n]=react.useState(true),[o,a]=react.useState(null),i=react.useCallback(async()=>{n(true);try{let h=await s.listSessions();t(h);}catch(h){a(h);}finally{n(false);}},[s]),f=react.useCallback(async h=>{let u=await s.revokeSession(h);return await i(),u},[s,i]),l=react.useCallback(async()=>{let h=await s.revokeOtherSessions();return await i(),h},[s,i]);return react.useEffect(()=>{i();},[i]),{sessions:e,isLoading:r,error:o,revokeSession:f,revokeOtherSessions:l,refresh:i}}function ne(){let s=w(),[e,t]=react.useState(false),[r,n]=react.useState(null);return {signInWithSSO:react.useCallback(async a=>{t(true),n(null);try{return await s.signInWithSSO(a)}catch(i){throw n(i),i}finally{t(false);}},[s]),isLoading:e,error:r}}exports.AuthProvider=j;exports.VaifAuthClient=P;exports.createAuthClient=C;exports.useAuth=Y;exports.useAuthClient=w;exports.useIdentities=se;exports.useIsAuthenticated=Z;exports.useMFA=te;exports.usePassword=ee;exports.useSSO=ne;exports.useSession=X;exports.useSessions=re;exports.useUser=Q;
|
package/dist/react.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {o}from'./chunk-VKUCT6DW.mjs';export{n as VaifAuthClient,o as createAuthClient}from'./chunk-VKUCT6DW.mjs';import {createContext,useState,useEffect,useMemo,useCallback,useContext}from'react';import {jsx}from'react/jsx-runtime';var C=createContext(null);function M({children:t,config:h,client:o$1,initialSession:g=null}){let[e]=useState(()=>{if(o$1)return o$1;if(!h)throw new Error("AuthProvider requires either config or client prop");return o(h)}),[c,d]=useState(g),[n,A]=useState(!g),[u,s]=useState(null);useEffect(()=>{let l=true;e.initialize().then(p=>{l&&(d(p),A(false));}).catch(p=>{l&&(s(p),A(false));});let{unsubscribe:f}=e.onAuthStateChange(p=>{l&&(d(p.session),s(null));});return ()=>{l=false,f();}},[e]);let r=useMemo(()=>({client:e,session:c,user:c?.user??null,isLoading:n,isAuthenticated:!!c,error:u}),[e,c,n,u]);return jsx(C.Provider,{value:r,children:t})}function y(){let t=useContext(C);if(!t)throw new Error("useAuth must be used within an AuthProvider");return t}function S(){let{client:t}=y();return t}function W(){let{client:t,session:h,user:o,isLoading:g,isAuthenticated:e,error:c}=y(),d=useCallback(async l=>t.signUp(l),[t]),n=useCallback(async l=>t.signInWithPassword(l),[t]),A=useCallback(async l=>{await t.signInWithOAuth(l);},[t]),u=useCallback(async l=>t.signInWithMagicLink(l),[t]),s=useCallback(async()=>t.signOut(),[t]),r=useCallback(async()=>t.refreshSession(),[t]);return {session:h,user:o,isLoading:g,isAuthenticated:e,error:c,signUp:d,signInWithPassword:n,signInWithOAuth:A,signInWithMagicLink:u,signOut:s,refreshSession:r,client:t}}function k(){let{user:t}=y();return t}function b(){let{session:t}=y();return t}function T(){let{isAuthenticated:t}=y();return t}function U(){let t=S(),[h,o]=useState(false),[g,e]=useState(null),c=useCallback(async(n,A)=>{o(true),e(null);try{return await t.resetPasswordForEmail({email:n,redirectTo:A})}catch(u){throw e(u),u}finally{o(false);}},[t]),d=useCallback(async(n,A)=>{o(true),e(null);try{return await t.updatePassword({currentPassword:n,newPassword:A})}catch(u){throw e(u),u}finally{o(false);}},[t]);return {resetPassword:c,updatePassword:d,isLoading:h,error:g}}function R(){let t=S(),[h,o]=useState([]),[g,e]=useState(false),[c,d]=useState(null),n=useCallback(async()=>{e(true);try{let r=await t.listMFAFactors();o(r);}catch(r){d(r);}finally{e(false);}},[t]),A=useCallback(async r=>t.enrollMFA({type:"totp",friendlyName:r}),[t]),u=useCallback(async(r,l)=>{let f=await t.verifyMFA({factorId:r,code:l});return await n(),f},[t,n]),s=useCallback(async(r,l)=>{let f=await t.unenrollMFA(r,l);return await n(),f},[t,n]);return useEffect(()=>{n();},[n]),{factors:h,isLoading:g,error:c,enrollTOTP:A,verifyMFA:u,unenroll:s,refresh:n}}function V(){let t=S(),[h,o]=useState([]),[g,e]=useState(true),[c,d]=useState(null),n=useCallback(async()=>{e(true);try{let s=await t.getUserIdentities();o(s);}catch(s){d(s);}finally{e(false);}},[t]),A=useCallback(async(s,r)=>t.linkIdentity(s,{redirectTo:r}),[t]),u=useCallback(async s=>{let r=await t.unlinkIdentity(s);return await n(),r},[t,n]);return useEffect(()=>{n();},[n]),{identities:h,isLoading:g,error:c,linkIdentity:A,unlinkIdentity:u,refresh:n}}function N(){let t=S(),[h,o]=useState([]),[g,e]=useState(true),[c,d]=useState(null),n=useCallback(async()=>{e(true);try{let s=await t.listSessions();o(s);}catch(s){d(s);}finally{e(false);}},[t]),A=useCallback(async s=>{let r=await t.revokeSession(s);return await n(),r},[t,n]),u=useCallback(async()=>{let s=await t.revokeOtherSessions();return await n(),s},[t,n]);return useEffect(()=>{n();},[n]),{sessions:h,isLoading:g,error:c,revokeSession:A,revokeOtherSessions:u,refresh:n}}function q(){let t=S(),[h,o]=useState(false),[g,e]=useState(null);return {signInWithSSO:useCallback(async d=>{o(true),e(null);try{return await t.signInWithSSO(d)}catch(n){throw e(n),n}finally{o(false);}},[t]),isLoading:h,error:g}}export{M as AuthProvider,W as useAuth,S as useAuthClient,V as useIdentities,T as useIsAuthenticated,R as useMFA,U as usePassword,q as useSSO,b as useSession,N as useSessions,k as useUser};
|
package/package.json
CHANGED
package/dist/chunk-JF55RF72.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function l(i){return "mfaRequired"in i&&i.mfaRequired===true}var a=class i extends Error{constructor(e,t,s,r){super(e),this.name="AuthError",this.code=t,this.status=s,this.details=r;}static isAuthError(e){return e instanceof i}},m=class extends a{constructor(e="Session has expired"){super(e,"session_expired",401),this.name="SessionExpiredError";}},S=class extends a{constructor(e="Invalid email or password"){super(e,"invalid_credentials",401),this.name="InvalidCredentialsError";}};function n(){return typeof window<"u"&&typeof window.document<"u"}function y(){if(!n())return false;try{let i="__vaif_test__";return window.localStorage.setItem(i,i),window.localStorage.removeItem(i),!0}catch{return false}}var u=class{constructor(){this.storage=new Map;}getItem(e){return this.storage.get(e)??null}setItem(e,t){this.storage.set(e,t);}removeItem(e){this.storage.delete(e);}clear(){this.storage.clear();}},c=class{getItem(e){if(!n())return null;try{return window.localStorage.getItem(e)}catch{return null}}setItem(e,t){if(n())try{window.localStorage.setItem(e,t);}catch{}}removeItem(e){if(n())try{window.localStorage.removeItem(e);}catch{}}},p=class{getItem(e){if(!n())return null;try{return window.sessionStorage.getItem(e)}catch{return null}}setItem(e,t){if(n())try{window.sessionStorage.setItem(e,t);}catch{}}removeItem(e){if(n())try{window.sessionStorage.removeItem(e);}catch{}}},g=class{constructor(e){this.options={secure:n()&&window.location.protocol==="https:",sameSite:"lax",path:"/",...e};}getItem(e){if(!n())return null;try{let t=document.cookie.split(";");for(let s of t){let[r,o]=s.trim().split("=");if(r===e)return decodeURIComponent(o)}return null}catch{return null}}setItem(e,t){if(n())try{let s=`${e}=${encodeURIComponent(t)}`;s+=`; path=${this.options.path}`,s+=`; samesite=${this.options.sameSite}`,this.options.secure&&(s+="; secure"),this.options.domain&&(s+=`; domain=${this.options.domain}`),this.options.maxAge&&(s+=`; max-age=${this.options.maxAge}`),document.cookie=s;}catch{}}removeItem(e){if(n())try{document.cookie=`${e}=; path=${this.options.path}; expires=Thu, 01 Jan 1970 00:00:00 GMT`;}catch{}}};function _(){return y()?new c:new u}var d=class{constructor(e,t="vaif.auth."){this.adapter=e,this.keyPrefix=t;}key(e){return `${this.keyPrefix}${e}`}async getSession(){try{let e=await this.adapter.getItem(this.key("session"));if(!e)return null;let t=JSON.parse(e);return t.expiresAt&&t.expiresAt<Date.now()?(await this.removeSession(),null):t}catch{return null}}async setSession(e){try{await this.adapter.setItem(this.key("session"),JSON.stringify(e));}catch{}}async removeSession(){try{await this.adapter.removeItem(this.key("session"));}catch{}}async getRefreshToken(){try{return await this.adapter.getItem(this.key("refresh_token"))}catch{return null}}async setRefreshToken(e){try{await this.adapter.setItem(this.key("refresh_token"),e);}catch{}}async removeRefreshToken(){try{await this.adapter.removeItem(this.key("refresh_token"));}catch{}}async clear(){await this.removeSession(),await this.removeRefreshToken();}},A=new u,P=y()?new c:A,T=n()?new p:A,I=i=>new g(i);var k={storageKey:"vaif.auth.",autoRefreshToken:true,persistSession:true,detectSessionInUrl:true,flowType:"implicit",debug:false},v=60*1e3,f=class{constructor(e){this.refreshTimer=null;this.listeners=new Set;this.initialized=false;this.initPromise=null;this.currentSession=null;this.config={...k,...e,headers:e.headers||{},storage:e.storage||_()},this.storage=new d(this.config.storage,this.config.storageKey);}async initialize(){return this.initPromise?this.initPromise.then(()=>this.currentSession):(this.initPromise=this._initialize(),await this.initPromise,this.currentSession)}async _initialize(){if(!this.initialized){if(this.config.detectSessionInUrl&&n()){let e=await this._handleUrlSession();if(e){this.currentSession=e,await this._persistSession(e),this._notifyListeners("SIGNED_IN",e),this._setupAutoRefresh(e),this.initialized=true;return}}if(this.config.persistSession){let e=await this.storage.getSession();e&&(this.currentSession=e,this._notifyListeners("INITIAL_SESSION",e),this._setupAutoRefresh(e));}this.initialized=true;}}async getSession(){return await this.initialize(),this.currentSession}async getUser(){return (await this.getSession())?.user??null}async setSession(e,t){let s=await this._fetchUser(e),r={accessToken:e,refreshToken:t,expiresAt:Date.now()+3600*1e3,expiresIn:3600,tokenType:"bearer",user:s};return this.currentSession=r,await this._persistSession(r),this._notifyListeners("SIGNED_IN",r),this._setupAutoRefresh(r),{session:r,user:s}}async refreshSession(){let e=await this.getSession();if(!e?.refreshToken)return null;try{let t=await this._refreshToken(e.refreshToken),s={...e,accessToken:t.accessToken,refreshToken:t.refreshToken||e.refreshToken,expiresAt:t.expiresAt,expiresIn:t.expiresIn};return this.currentSession=s,await this._persistSession(s),this._notifyListeners("TOKEN_REFRESHED",s),this._setupAutoRefresh(s),s}catch(t){return this._log("Failed to refresh session:",t),await this.signOut(),null}}async signUp(e){let t=await this._fetch("/auth/signup",{method:"POST",body:JSON.stringify({email:e.email,password:e.password,name:e.name,phone:e.phone,metadata:e.metadata,redirectUrl:e.redirectUrl||e.emailRedirectTo})});return l(t)||(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session)),t}async signInWithPassword(e){let t=await this._fetch("/auth/login",{method:"POST",body:JSON.stringify({email:e.email,password:e.password,mfaCode:e.mfaCode,rememberMe:e.rememberMe})});return l(t)||(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session)),t}async signInWithOAuth(e){let t=await this._fetch("/auth/oauth/authorize",{method:"POST",body:JSON.stringify({provider:e.provider,redirectUrl:e.redirectTo,scopes:e.scopes,queryParams:e.queryParams,flowType:this.config.flowType})});return n()&&(window.location.href=t.url),t}async signInWithMagicLink(e){return this._fetch("/auth/magic-link/send",{method:"POST",body:JSON.stringify({email:e.email,redirectUrl:e.redirectTo,shouldCreateUser:e.shouldCreateUser})})}async signInWithOTP(e){let t=e.phone?"/auth/phone/send":"/auth/otp/send";return this._fetch(t,{method:"POST",body:JSON.stringify({email:e.email,phone:e.phone,channel:e.channel,shouldCreateUser:e.shouldCreateUser})})}async verifyOTP(e){let t=await this._fetch("/auth/otp/verify",{method:"POST",body:JSON.stringify({email:e.email,phone:e.phone,token:e.token,type:e.type})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session),t}async signInAnonymously(e){let t=await this._fetch("/auth/anonymous",{method:"POST",body:JSON.stringify({metadata:e?.metadata})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("SIGNED_IN",t.session),this._setupAutoRefresh(t.session),t}async signOut(){try{this.currentSession&&await this._fetch("/auth/logout",{method:"POST"});}catch{}this._clearRefreshTimer(),this.currentSession=null,await this.storage.clear(),this._notifyListeners("SIGNED_OUT",null);}async signOutAll(){try{await this._fetch("/auth/logout-all",{method:"POST"});}catch{}this._clearRefreshTimer(),this.currentSession=null,await this.storage.clear(),this._notifyListeners("SIGNED_OUT",null);}async resetPasswordForEmail(e){return this._fetch("/auth/forgot-password",{method:"POST",body:JSON.stringify({email:e.email,redirectUrl:e.redirectTo})})}async updatePassword(e){return this._fetch("/users/me/change-password",{method:"POST",body:JSON.stringify({currentPassword:e.currentPassword,newPassword:e.newPassword})})}async setPassword(e){let t=await this._fetch("/auth/reset-password",{method:"POST",body:JSON.stringify({token:e.token,password:e.password})});return this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("PASSWORD_RECOVERY",t.session),this._setupAutoRefresh(t.session),t}async updateUser(e){let t=await this._fetch("/users/me",{method:"PATCH",body:JSON.stringify(e)});return this.currentSession&&(this.currentSession={...this.currentSession,user:t.user},await this._persistSession(this.currentSession),this._notifyListeners("USER_UPDATED",this.currentSession)),t.user}async getUserIdentities(){return (await this._fetch("/auth/oauth/providers")).identities}async linkIdentity(e,t){let s=await this._fetch("/auth/oauth/link",{method:"POST",body:JSON.stringify({provider:e,redirectUrl:t?.redirectTo})});return n()&&(window.location.href=s.url),s}async unlinkIdentity(e){return this._fetch(`/auth/oauth/unlink/${e}`,{method:"POST"})}async listMFAFactors(){return (await this._fetch("/auth/mfa/factors")).factors}async enrollMFA(e){return this._fetch("/auth/mfa/setup",{method:"POST",body:JSON.stringify({method:e.type,friendlyName:e.friendlyName})})}async verifyMFA(e){return this._fetch("/auth/mfa/enable",{method:"POST",body:JSON.stringify({factorId:e.factorId,code:e.code})})}async challengeMFA(e){return this._fetch("/auth/mfa/challenge",{method:"POST",body:JSON.stringify({factorId:e.factorId})})}async verifyMFAChallenge(e,t){let s=await this._fetch("/auth/mfa/verify",{method:"POST",body:JSON.stringify({mfaToken:e,code:t})});return this.currentSession=s.session,await this._persistSession(s.session),this._notifyListeners("MFA_CHALLENGE_VERIFIED",s.session),this._setupAutoRefresh(s.session),s}async unenrollMFA(e,t){return this._fetch("/auth/mfa/disable",{method:"POST",body:JSON.stringify({factorId:e,code:t})})}async regenerateBackupCodes(){return this._fetch("/auth/mfa/backup-codes",{method:"POST"})}async listSessions(){return (await this._fetch("/auth/sessions")).sessions}async revokeSession(e){return this._fetch(`/auth/sessions/${e}`,{method:"DELETE"})}async revokeOtherSessions(){return this._fetch("/auth/sessions/revoke-others",{method:"POST"})}async resendEmailVerification(e){return this._fetch("/auth/verify-email/send",{method:"POST",body:JSON.stringify({redirectUrl:e?.redirectTo})})}async verifyEmail(e){let t=await this._fetch("/auth/verify-email/confirm",{method:"POST",body:JSON.stringify({token:e})});return this.currentSession&&(this.currentSession=t.session,await this._persistSession(t.session),this._notifyListeners("USER_UPDATED",t.session)),t}onAuthStateChange(e){return this.listeners.add(e),this.initialized&&e({event:this.currentSession?"INITIAL_SESSION":"SIGNED_OUT",session:this.currentSession}),{unsubscribe:()=>{this.listeners.delete(e);}}}async _fetch(e,t={}){let s=`${this.config.url}${e}`,r={"Content-Type":"application/json",...this.config.headers};this.config.apiKey&&(r["x-vaif-key"]=this.config.apiKey),this.currentSession?.accessToken&&(r.Authorization=`Bearer ${this.currentSession.accessToken}`);let o=await fetch(s,{...t,headers:r});if(!o.ok){let h=await o.json().catch(()=>({}));throw new a(h.message||"Request failed",this._mapErrorCode(o.status,h.code),o.status,h)}return o.json()}async _fetchUser(e){let t=await fetch(`${this.config.url}/auth/me`,{headers:{Authorization:`Bearer ${e}`,...this.config.headers}});if(!t.ok)throw new a("Failed to fetch user","invalid_token",t.status);return (await t.json()).user}async _refreshToken(e){let t=await fetch(`${this.config.url}/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json",...this.config.headers},body:JSON.stringify({refreshToken:e})});if(!t.ok)throw new a("Failed to refresh token","token_expired",t.status);return t.json()}async _handleUrlSession(){if(!n())return null;let e=new URLSearchParams(window.location.hash.substring(1)),t=new URLSearchParams(window.location.search),s=e.get("access_token")||t.get("access_token"),r=e.get("refresh_token")||t.get("refresh_token"),o=e.get("expires_in")||t.get("expires_in");if(!s)return null;try{let h=await this._fetchUser(s),w={accessToken:s,refreshToken:r||void 0,expiresAt:Date.now()+(o?parseInt(o,10)*1e3:36e5),expiresIn:o?parseInt(o,10):3600,tokenType:"bearer",user:h};return window.history.replaceState(null,"",window.location.pathname),w}catch(h){return this._log("Failed to handle URL session:",h),null}}async _persistSession(e){this.config.persistSession&&(await this.storage.setSession(e),e.refreshToken&&await this.storage.setRefreshToken(e.refreshToken));}_setupAutoRefresh(e){if(!this.config.autoRefreshToken||!e.refreshToken)return;this._clearRefreshTimer();let t=e.expiresAt,s=Date.now(),r=Math.max(0,t-s-v);this._log(`Setting up auto refresh in ${Math.round(r/1e3)}s`),this.refreshTimer=setTimeout(()=>{this.refreshSession();},r);}_clearRefreshTimer(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null);}_notifyListeners(e,t){let s={event:e,session:t};this.listeners.forEach(r=>{try{r(s);}catch(o){this._log("Error in auth state change listener:",o);}});}_mapErrorCode(e,t){if(t){let s={invalid_credentials:"invalid_credentials",user_not_found:"user_not_found",user_already_exists:"user_already_exists",email_not_verified:"email_not_verified",phone_not_verified:"phone_not_verified",invalid_token:"invalid_token",token_expired:"token_expired",mfa_required:"mfa_required",mfa_invalid:"mfa_invalid",rate_limited:"rate_limited",weak_password:"weak_password",invalid_email:"invalid_email",invalid_phone:"invalid_phone"};if(s[t])return s[t]}switch(e){case 401:return "invalid_credentials";case 403:return "token_expired";case 404:return "user_not_found";case 409:return "user_already_exists";case 429:return "rate_limited";default:return "unknown_error"}}_log(...e){this.config.debug&&console.log("[VaifAuth]",...e);}};function C(i){return new f(i)}export{l as a,a as b,m as c,S as d,n as e,_ as f,d as g,A as h,P as i,T as j,I as k,f as l,C as m};
|