@authsome/ui-core 0.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 +164 -0
- package/dist/adapters/index.d.mts +57 -0
- package/dist/adapters/index.d.ts +57 -0
- package/dist/adapters/index.js +94 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/index.mjs +92 -0
- package/dist/adapters/index.mjs.map +1 -0
- package/dist/index.d.mts +540 -0
- package/dist/index.d.ts +540 -0
- package/dist/index.js +1453 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1415 -0
- package/dist/index.mjs.map +1 -0
- package/dist/provider-DXf_a2WT.d.mts +457 -0
- package/dist/provider-DXf_a2WT.d.ts +457 -0
- package/dist/types/index.d.mts +98 -0
- package/dist/types/index.d.ts +98 -0
- package/dist/types/index.js +180 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/index.mjs +170 -0
- package/dist/types/index.mjs.map +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# @authsome/ui-core
|
|
2
|
+
|
|
3
|
+
Framework-agnostic authentication core for AuthSome UI.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @authsome/ui-core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Provider Adapters**: Built-in support for AuthSome, Clerk, Supabase, and custom backends
|
|
14
|
+
- **Observable State**: Framework-agnostic state management
|
|
15
|
+
- **Complete Auth Flows**: Email/password, OAuth, magic links, 2FA, passkeys, phone auth
|
|
16
|
+
- **Type Safe**: Full TypeScript support
|
|
17
|
+
- **Zero Dependencies**: Minimal footprint
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Basic Setup with AuthSome
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { AuthClient, AuthSomeAdapter } from '@authsome/ui-core';
|
|
25
|
+
|
|
26
|
+
// Create adapter
|
|
27
|
+
const adapter = new AuthSomeAdapter();
|
|
28
|
+
await adapter.initialize({
|
|
29
|
+
apiUrl: 'https://your-api.com/auth',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Create client
|
|
33
|
+
const authClient = new AuthClient({
|
|
34
|
+
provider: adapter,
|
|
35
|
+
autoRefresh: true,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Initialize
|
|
39
|
+
await authClient.initialize();
|
|
40
|
+
|
|
41
|
+
// Subscribe to auth state
|
|
42
|
+
const unsubscribe = authClient.subscribe((state) => {
|
|
43
|
+
console.log('Auth state:', state);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Sign in
|
|
47
|
+
await authClient.signIn({
|
|
48
|
+
email: 'user@example.com',
|
|
49
|
+
password: 'password',
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Using with Clerk
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { AuthClient, ClerkAdapter } from '@authsome/ui-core';
|
|
57
|
+
|
|
58
|
+
const adapter = new ClerkAdapter();
|
|
59
|
+
await adapter.initialize({
|
|
60
|
+
publishableKey: 'pk_test_...',
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const authClient = new AuthClient({ provider: adapter });
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Using with Supabase
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { AuthClient, SupabaseAdapter } from '@authsome/ui-core';
|
|
70
|
+
|
|
71
|
+
const adapter = new SupabaseAdapter();
|
|
72
|
+
await adapter.initialize({
|
|
73
|
+
url: 'https://your-project.supabase.co',
|
|
74
|
+
anonKey: 'your-anon-key',
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const authClient = new AuthClient({ provider: adapter });
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Custom Backend
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { AuthClient, GenericAdapter } from '@authsome/ui-core';
|
|
84
|
+
|
|
85
|
+
const adapter = new GenericAdapter();
|
|
86
|
+
await adapter.initialize({
|
|
87
|
+
baseUrl: 'https://your-api.com',
|
|
88
|
+
endpoints: {
|
|
89
|
+
signIn: '/auth/login',
|
|
90
|
+
signUp: '/auth/register',
|
|
91
|
+
signOut: '/auth/logout',
|
|
92
|
+
getCurrentUser: '/auth/me',
|
|
93
|
+
// ... other endpoints
|
|
94
|
+
},
|
|
95
|
+
transforms: {
|
|
96
|
+
transformAuthResponse: (res) => ({
|
|
97
|
+
user: res.user,
|
|
98
|
+
session: res.session,
|
|
99
|
+
}),
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const authClient = new AuthClient({ provider: adapter });
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## API Reference
|
|
107
|
+
|
|
108
|
+
### AuthClient
|
|
109
|
+
|
|
110
|
+
The main authentication client.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
const client = new AuthClient({
|
|
114
|
+
provider: adapter,
|
|
115
|
+
autoRefresh: true, // Auto-refresh sessions
|
|
116
|
+
refreshInterval: 300000, // 5 minutes
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Methods
|
|
121
|
+
|
|
122
|
+
- `initialize()`: Initialize the client and restore session
|
|
123
|
+
- `signIn(request)`: Sign in with credentials
|
|
124
|
+
- `signUp(request)`: Register a new user
|
|
125
|
+
- `signOut()`: Sign out current user
|
|
126
|
+
- `updateUser(request)`: Update user profile
|
|
127
|
+
- `changePassword(request)`: Change user password
|
|
128
|
+
- `requestPasswordReset(request)`: Request password reset email
|
|
129
|
+
- `confirmPasswordReset(request)`: Confirm password reset with token
|
|
130
|
+
- `getOAuthUrl(request)`: Get OAuth authorization URL
|
|
131
|
+
- `handleOAuthCallback(request)`: Handle OAuth callback
|
|
132
|
+
- `sendMagicLink(request)`: Send magic link email
|
|
133
|
+
- `verifyMagicLink(request)`: Verify magic link token
|
|
134
|
+
- `sendPhoneCode(request)`: Send phone verification code
|
|
135
|
+
- `verifyPhoneCode(request)`: Verify phone code
|
|
136
|
+
- `setupTwoFactor(request)`: Setup 2FA
|
|
137
|
+
- `verifyTwoFactor(request)`: Verify 2FA code
|
|
138
|
+
- `disableTwoFactor()`: Disable 2FA
|
|
139
|
+
- `getTwoFactorStatus()`: Get enabled 2FA methods
|
|
140
|
+
- `registerPasskey(request)`: Register a passkey
|
|
141
|
+
- `authenticatePasskey(request)`: Authenticate with passkey
|
|
142
|
+
- `listPasskeys()`: List user's passkeys
|
|
143
|
+
- `deletePasskey(id)`: Delete a passkey
|
|
144
|
+
- `refreshSession()`: Manually refresh session
|
|
145
|
+
- `subscribe(listener)`: Subscribe to auth state changes
|
|
146
|
+
- `destroy()`: Cleanup resources
|
|
147
|
+
|
|
148
|
+
### Auth State
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
interface AuthContext {
|
|
152
|
+
state: AuthState; // AUTHENTICATED | UNAUTHENTICATED | LOADING | ERROR
|
|
153
|
+
user: User | null;
|
|
154
|
+
session: Session | null;
|
|
155
|
+
error: AuthError | null;
|
|
156
|
+
isAuthenticated: boolean;
|
|
157
|
+
isLoading: boolean;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT
|
|
164
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { c as AuthProvider, z as ProviderConfig, S as SignInRequest, y as AuthResponse, d as SignUpRequest, t as User, u as Session, U as UpdateUserRequest, P as PasswordChangeRequest, e as PasswordResetRequest, f as PasswordResetConfirmRequest, O as OAuthSignInRequest, g as OAuthCallbackRequest, h as OAuthProvider, M as MagicLinkRequest, i as MagicLinkVerifyRequest, j as PhoneAuthRequest, k as PhoneVerifyRequest, T as TwoFactorSetupRequest, l as TwoFactorSetupResponse, m as TwoFactorVerifyRequest, n as TwoFactorMethod, o as PasskeyRegisterRequest, p as PasskeyCredential, q as PasskeyAuthRequest, a as AuthError } from '../provider-DXf_a2WT.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base auth provider implementation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Base provider class with common functionality
|
|
9
|
+
*/
|
|
10
|
+
declare abstract class BaseAuthProvider implements AuthProvider {
|
|
11
|
+
abstract readonly name: string;
|
|
12
|
+
protected config: ProviderConfig;
|
|
13
|
+
protected initialized: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Initialize the provider
|
|
16
|
+
*/
|
|
17
|
+
initialize(config: ProviderConfig): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Ensure provider is initialized
|
|
20
|
+
*/
|
|
21
|
+
protected ensureInitialized(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Make HTTP request
|
|
24
|
+
*/
|
|
25
|
+
protected request<T>(url: string, options?: RequestInit): Promise<T>;
|
|
26
|
+
abstract signIn(request: SignInRequest): Promise<AuthResponse>;
|
|
27
|
+
abstract signUp(request: SignUpRequest): Promise<AuthResponse>;
|
|
28
|
+
abstract signOut(): Promise<void>;
|
|
29
|
+
abstract getCurrentUser(): Promise<User | null>;
|
|
30
|
+
abstract getCurrentSession(): Promise<Session | null>;
|
|
31
|
+
abstract refreshSession(): Promise<Session>;
|
|
32
|
+
abstract updateUser(request: UpdateUserRequest): Promise<User>;
|
|
33
|
+
abstract changePassword(request: PasswordChangeRequest): Promise<void>;
|
|
34
|
+
abstract requestPasswordReset(request: PasswordResetRequest): Promise<void>;
|
|
35
|
+
abstract confirmPasswordReset(request: PasswordResetConfirmRequest): Promise<void>;
|
|
36
|
+
abstract oauthSignIn(request: OAuthSignInRequest): Promise<string>;
|
|
37
|
+
abstract oauthCallback(request: OAuthCallbackRequest): Promise<AuthResponse>;
|
|
38
|
+
abstract getOAuthProviders(): Promise<OAuthProvider[]>;
|
|
39
|
+
abstract sendMagicLink(request: MagicLinkRequest): Promise<void>;
|
|
40
|
+
abstract verifyMagicLink(request: MagicLinkVerifyRequest): Promise<AuthResponse>;
|
|
41
|
+
abstract sendPhoneCode(request: PhoneAuthRequest): Promise<void>;
|
|
42
|
+
abstract verifyPhoneCode(request: PhoneVerifyRequest): Promise<AuthResponse>;
|
|
43
|
+
abstract setupTwoFactor(request: TwoFactorSetupRequest): Promise<TwoFactorSetupResponse>;
|
|
44
|
+
abstract verifyTwoFactor(request: TwoFactorVerifyRequest): Promise<AuthResponse>;
|
|
45
|
+
abstract disableTwoFactor(): Promise<void>;
|
|
46
|
+
abstract getTwoFactorStatus(): Promise<TwoFactorMethod[]>;
|
|
47
|
+
abstract registerPasskey(request: PasskeyRegisterRequest): Promise<PasskeyCredential>;
|
|
48
|
+
abstract authenticatePasskey(request: PasskeyAuthRequest): Promise<AuthResponse>;
|
|
49
|
+
abstract listPasskeys(): Promise<PasskeyCredential[]>;
|
|
50
|
+
abstract deletePasskey(credentialId: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Normalize error to AuthError
|
|
53
|
+
*/
|
|
54
|
+
normalizeError(error: unknown): AuthError;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { BaseAuthProvider };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { c as AuthProvider, z as ProviderConfig, S as SignInRequest, y as AuthResponse, d as SignUpRequest, t as User, u as Session, U as UpdateUserRequest, P as PasswordChangeRequest, e as PasswordResetRequest, f as PasswordResetConfirmRequest, O as OAuthSignInRequest, g as OAuthCallbackRequest, h as OAuthProvider, M as MagicLinkRequest, i as MagicLinkVerifyRequest, j as PhoneAuthRequest, k as PhoneVerifyRequest, T as TwoFactorSetupRequest, l as TwoFactorSetupResponse, m as TwoFactorVerifyRequest, n as TwoFactorMethod, o as PasskeyRegisterRequest, p as PasskeyCredential, q as PasskeyAuthRequest, a as AuthError } from '../provider-DXf_a2WT.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base auth provider implementation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Base provider class with common functionality
|
|
9
|
+
*/
|
|
10
|
+
declare abstract class BaseAuthProvider implements AuthProvider {
|
|
11
|
+
abstract readonly name: string;
|
|
12
|
+
protected config: ProviderConfig;
|
|
13
|
+
protected initialized: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Initialize the provider
|
|
16
|
+
*/
|
|
17
|
+
initialize(config: ProviderConfig): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Ensure provider is initialized
|
|
20
|
+
*/
|
|
21
|
+
protected ensureInitialized(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Make HTTP request
|
|
24
|
+
*/
|
|
25
|
+
protected request<T>(url: string, options?: RequestInit): Promise<T>;
|
|
26
|
+
abstract signIn(request: SignInRequest): Promise<AuthResponse>;
|
|
27
|
+
abstract signUp(request: SignUpRequest): Promise<AuthResponse>;
|
|
28
|
+
abstract signOut(): Promise<void>;
|
|
29
|
+
abstract getCurrentUser(): Promise<User | null>;
|
|
30
|
+
abstract getCurrentSession(): Promise<Session | null>;
|
|
31
|
+
abstract refreshSession(): Promise<Session>;
|
|
32
|
+
abstract updateUser(request: UpdateUserRequest): Promise<User>;
|
|
33
|
+
abstract changePassword(request: PasswordChangeRequest): Promise<void>;
|
|
34
|
+
abstract requestPasswordReset(request: PasswordResetRequest): Promise<void>;
|
|
35
|
+
abstract confirmPasswordReset(request: PasswordResetConfirmRequest): Promise<void>;
|
|
36
|
+
abstract oauthSignIn(request: OAuthSignInRequest): Promise<string>;
|
|
37
|
+
abstract oauthCallback(request: OAuthCallbackRequest): Promise<AuthResponse>;
|
|
38
|
+
abstract getOAuthProviders(): Promise<OAuthProvider[]>;
|
|
39
|
+
abstract sendMagicLink(request: MagicLinkRequest): Promise<void>;
|
|
40
|
+
abstract verifyMagicLink(request: MagicLinkVerifyRequest): Promise<AuthResponse>;
|
|
41
|
+
abstract sendPhoneCode(request: PhoneAuthRequest): Promise<void>;
|
|
42
|
+
abstract verifyPhoneCode(request: PhoneVerifyRequest): Promise<AuthResponse>;
|
|
43
|
+
abstract setupTwoFactor(request: TwoFactorSetupRequest): Promise<TwoFactorSetupResponse>;
|
|
44
|
+
abstract verifyTwoFactor(request: TwoFactorVerifyRequest): Promise<AuthResponse>;
|
|
45
|
+
abstract disableTwoFactor(): Promise<void>;
|
|
46
|
+
abstract getTwoFactorStatus(): Promise<TwoFactorMethod[]>;
|
|
47
|
+
abstract registerPasskey(request: PasskeyRegisterRequest): Promise<PasskeyCredential>;
|
|
48
|
+
abstract authenticatePasskey(request: PasskeyAuthRequest): Promise<AuthResponse>;
|
|
49
|
+
abstract listPasskeys(): Promise<PasskeyCredential[]>;
|
|
50
|
+
abstract deletePasskey(credentialId: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Normalize error to AuthError
|
|
53
|
+
*/
|
|
54
|
+
normalizeError(error: unknown): AuthError;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { BaseAuthProvider };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/types/auth.ts
|
|
4
|
+
var AuthError = class _AuthError extends Error {
|
|
5
|
+
constructor(message, type = "unknown_error" /* UNKNOWN_ERROR */, options) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "AuthError";
|
|
8
|
+
this.type = type;
|
|
9
|
+
this.details = options?.details;
|
|
10
|
+
this.code = options?.code;
|
|
11
|
+
this.originalError = options?.originalError;
|
|
12
|
+
if (Error.captureStackTrace) {
|
|
13
|
+
Error.captureStackTrace(this, _AuthError);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// src/utils/errors.ts
|
|
19
|
+
function isAuthError(error) {
|
|
20
|
+
return error instanceof AuthError;
|
|
21
|
+
}
|
|
22
|
+
function toAuthError(error) {
|
|
23
|
+
if (isAuthError(error)) {
|
|
24
|
+
return error;
|
|
25
|
+
}
|
|
26
|
+
if (error instanceof Error) {
|
|
27
|
+
return new AuthError(error.message, "unknown_error" /* UNKNOWN_ERROR */, {
|
|
28
|
+
details: {
|
|
29
|
+
originalError: error.name,
|
|
30
|
+
stack: error.stack
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (typeof error === "string") {
|
|
35
|
+
return new AuthError(error, "unknown_error" /* UNKNOWN_ERROR */);
|
|
36
|
+
}
|
|
37
|
+
return new AuthError(
|
|
38
|
+
"An unknown error occurred",
|
|
39
|
+
"unknown_error" /* UNKNOWN_ERROR */,
|
|
40
|
+
{ details: { error } }
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/adapters/base-provider.ts
|
|
45
|
+
var BaseAuthProvider = class {
|
|
46
|
+
constructor() {
|
|
47
|
+
this.config = {};
|
|
48
|
+
this.initialized = false;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Initialize the provider
|
|
52
|
+
*/
|
|
53
|
+
async initialize(config) {
|
|
54
|
+
this.config = config;
|
|
55
|
+
this.initialized = true;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Ensure provider is initialized
|
|
59
|
+
*/
|
|
60
|
+
ensureInitialized() {
|
|
61
|
+
if (!this.initialized) {
|
|
62
|
+
throw new Error(`Provider ${this.name} is not initialized`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Make HTTP request
|
|
67
|
+
*/
|
|
68
|
+
async request(url, options = {}) {
|
|
69
|
+
const response = await fetch(url, {
|
|
70
|
+
...options,
|
|
71
|
+
headers: {
|
|
72
|
+
"Content-Type": "application/json",
|
|
73
|
+
...options.headers
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
const error = await response.json().catch(() => ({
|
|
78
|
+
message: response.statusText
|
|
79
|
+
}));
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
return response.json();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Normalize error to AuthError
|
|
86
|
+
*/
|
|
87
|
+
normalizeError(error) {
|
|
88
|
+
return toAuthError(error);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
exports.BaseAuthProvider = BaseAuthProvider;
|
|
93
|
+
//# sourceMappingURL=index.js.map
|
|
94
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types/auth.ts","../../src/utils/errors.ts","../../src/adapters/base-provider.ts"],"names":[],"mappings":";;;AAyEO,IAAM,SAAA,GAAN,MAAM,UAAA,SAAkB,KAAA,CAAM;AAAA,EAMnC,WAAA,CACE,OAAA,EACA,IAAA,GAAsB,eAAA,sBACtB,OAAA,EAKA;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,WAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,UAAU,OAAA,EAAS,OAAA;AACxB,IAAA,IAAA,CAAK,OAAO,OAAA,EAAS,IAAA;AACrB,IAAA,IAAA,CAAK,gBAAgB,OAAA,EAAS,aAAA;AAG9B,IAAA,IAAI,MAAM,iBAAA,EAAmB;AAC3B,MAAA,KAAA,CAAM,iBAAA,CAAkB,MAAM,UAAS,CAAA;AAAA,IACzC;AAAA,EACF;AACF,CAAA;;;AC7EO,SAAS,YAAY,KAAA,EAAoC;AAC9D,EAAA,OAAO,KAAA,YAAiB,SAAA;AAC1B;AAKO,SAAS,YAAY,KAAA,EAA2B;AACrD,EAAA,IAAI,WAAA,CAAY,KAAK,CAAA,EAAG;AACtB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,iBAAiB,KAAA,EAAO;AAC1B,IAAA,OAAO,IAAI,SAAA,CAAU,KAAA,CAAM,OAAA,EAAA,eAAA,sBAAsC;AAAA,MAC/D,OAAA,EAAS;AAAA,QACP,eAAe,KAAA,CAAM,IAAA;AAAA,QACrB,OAAO,KAAA,CAAM;AAAA;AACf,KACD,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,IAAI,UAAU,KAAA,EAAA,eAAA,qBAAkC;AAAA,EACzD;AAEA,EAAA,OAAO,IAAI,SAAA;AAAA,IACT,2BAAA;AAAA,IAAA,eAAA;AAAA,IAEA,EAAE,OAAA,EAAS,EAAE,KAAA,EAAM;AAAE,GACvB;AACF;;;AChBO,IAAe,mBAAf,MAAwD;AAAA,EAAxD,WAAA,GAAA;AAEL,IAAA,IAAA,CAAU,SAAyB,EAAC;AACpC,IAAA,IAAA,CAAU,WAAA,GAAc,KAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKxB,MAAM,WAAW,MAAA,EAAuC;AACtD,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKU,iBAAA,GAA0B;AAClC,IAAA,IAAI,CAAC,KAAK,WAAA,EAAa;AACrB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,SAAA,EAAY,IAAA,CAAK,IAAI,CAAA,mBAAA,CAAqB,CAAA;AAAA,IAC5D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAgB,OAAA,CACd,GAAA,EACA,OAAA,GAAuB,EAAC,EACZ;AACZ,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAChC,GAAG,OAAA;AAAA,MACH,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,GAAG,OAAA,CAAQ;AAAA;AACb,KACD,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,QAAQ,MAAM,QAAA,CAAS,IAAA,EAAK,CAAE,MAAM,OAAO;AAAA,QAC/C,SAAS,QAAA,CAAS;AAAA,OACpB,CAAE,CAAA;AACF,MAAA,MAAM,KAAA;AAAA,IACR;AAEA,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAgCA,eAAe,KAAA,EAA2B;AACxC,IAAA,OAAO,YAAY,KAAK,CAAA;AAAA,EAC1B;AACF","file":"index.js","sourcesContent":["/**\n * Core authentication types and interfaces\n */\n\n/**\n * Authentication state enum\n */\nexport enum AuthState {\n AUTHENTICATED = 'authenticated',\n UNAUTHENTICATED = 'unauthenticated',\n LOADING = 'loading',\n ERROR = 'error',\n}\n\n/**\n * User profile interface\n */\nexport interface User {\n id: string;\n email?: string;\n username?: string;\n phone?: string;\n emailVerified?: boolean;\n phoneVerified?: boolean;\n name?: string;\n firstName?: string;\n lastName?: string;\n avatar?: string;\n metadata?: Record<string, unknown>;\n createdAt?: Date;\n updatedAt?: Date;\n \n // Organization fields\n organizationId?: string;\n organizationRole?: string;\n organizationMemberships?: OrganizationMembership[];\n}\n\n/**\n * Session interface\n */\nexport interface Session {\n id: string;\n userId: string;\n token: string;\n expiresAt?: Date;\n createdAt?: Date;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Auth error types\n */\nexport enum AuthErrorType {\n INVALID_CREDENTIALS = 'invalid_credentials',\n USER_NOT_FOUND = 'user_not_found',\n USER_ALREADY_EXISTS = 'user_already_exists',\n INVALID_TOKEN = 'invalid_token',\n TOKEN_EXPIRED = 'token_expired',\n NETWORK_ERROR = 'network_error',\n VALIDATION_ERROR = 'validation_error',\n MFA_REQUIRED = 'mfa_required',\n EMAIL_NOT_VERIFIED = 'email_not_verified',\n PHONE_NOT_VERIFIED = 'phone_not_verified',\n RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded',\n UNKNOWN_ERROR = 'unknown_error',\n}\n\n/**\n * Auth error class\n * \n * Extends Error to provide proper error handling with auth-specific context\n */\nexport class AuthError extends Error {\n public readonly type: AuthErrorType;\n public readonly details?: Record<string, unknown>;\n public readonly code?: string | number;\n public readonly originalError?: unknown;\n\n constructor(\n message: string,\n type: AuthErrorType = AuthErrorType.UNKNOWN_ERROR,\n options?: {\n details?: Record<string, unknown>;\n code?: string | number;\n originalError?: unknown;\n }\n ) {\n super(message);\n this.name = 'AuthError';\n this.type = type;\n this.details = options?.details;\n this.code = options?.code;\n this.originalError = options?.originalError;\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, AuthError);\n }\n }\n}\n\n/**\n * Auth context state\n */\nexport interface AuthContext {\n state: AuthState;\n user: User | null;\n session: Session | null;\n error: AuthError | null;\n isAuthenticated: boolean;\n isLoading: boolean;\n}\n\n/**\n * OAuth provider types\n */\nexport enum OAuthProvider {\n GOOGLE = 'google',\n GITHUB = 'github',\n FACEBOOK = 'facebook',\n TWITTER = 'twitter',\n MICROSOFT = 'microsoft',\n APPLE = 'apple',\n LINKEDIN = 'linkedin',\n DISCORD = 'discord',\n}\n\n/**\n * OAuth configuration\n */\nexport interface OAuthConfig {\n provider: OAuthProvider;\n clientId: string;\n redirectUri: string;\n scope?: string[];\n state?: string;\n}\n\n/**\n * 2FA method types\n */\nexport enum TwoFactorMethod {\n TOTP = 'totp',\n SMS = 'sms',\n EMAIL = 'email',\n BACKUP_CODE = 'backup_code',\n}\n\n/**\n * 2FA configuration\n */\nexport interface TwoFactorConfig {\n method: TwoFactorMethod;\n enabled: boolean;\n verified?: boolean;\n}\n\n/**\n * Passkey/WebAuthn types\n */\nexport interface PasskeyCredential {\n id: string;\n name?: string;\n createdAt?: Date;\n lastUsedAt?: Date;\n}\n\n/**\n * Validation error\n */\nexport interface ValidationError {\n field: string;\n message: string;\n code?: string;\n}\n\n/**\n * Organization interface\n */\nexport interface Organization {\n id: string;\n name: string;\n slug: string;\n logoUrl?: string;\n createdAt?: Date;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Organization membership interface\n */\nexport interface OrganizationMembership {\n organization: Organization;\n role: 'owner' | 'admin' | 'member';\n permissions?: string[];\n}\n\n","/**\n * Error handling utilities\n */\n\nimport { AuthError, AuthErrorType } from '../types';\n\n/**\n * Create an auth error\n * \n * @deprecated Use `new AuthError()` directly instead\n */\nexport function createAuthError(\n type: AuthErrorType,\n message: string,\n details?: Record<string, unknown>,\n code?: string | number\n): AuthError {\n return new AuthError(message, type, { details, code });\n}\n\n/**\n * Check if an error is an auth error\n */\nexport function isAuthError(error: unknown): error is AuthError {\n return error instanceof AuthError;\n}\n\n/**\n * Convert unknown error to auth error\n */\nexport function toAuthError(error: unknown): AuthError {\n if (isAuthError(error)) {\n return error;\n }\n\n if (error instanceof Error) {\n return new AuthError(error.message, AuthErrorType.UNKNOWN_ERROR, {\n details: {\n originalError: error.name,\n stack: error.stack,\n },\n });\n }\n\n if (typeof error === 'string') {\n return new AuthError(error, AuthErrorType.UNKNOWN_ERROR);\n }\n\n return new AuthError(\n 'An unknown error occurred',\n AuthErrorType.UNKNOWN_ERROR,\n { details: { error } }\n );\n}\n\n/**\n * Check if error is a network error\n */\nexport function isNetworkError(error: unknown): boolean {\n if (error instanceof Error) {\n return (\n error.name === 'NetworkError' ||\n error.message.includes('network') ||\n error.message.includes('fetch')\n );\n }\n return false;\n}\n\n/**\n * Check if error indicates authentication is required\n */\nexport function isUnauthenticatedError(error: unknown): boolean {\n if (isAuthError(error)) {\n return (\n error.type === AuthErrorType.INVALID_TOKEN ||\n error.type === AuthErrorType.TOKEN_EXPIRED\n );\n }\n return false;\n}\n\n/**\n * Check if error requires MFA\n */\nexport function isMFARequiredError(error: unknown): boolean {\n if (isAuthError(error)) {\n return error.type === AuthErrorType.MFA_REQUIRED;\n }\n return false;\n}\n","/**\n * Base auth provider implementation\n */\n\nimport type {\n AuthProvider,\n AuthResponse,\n SignInRequest,\n SignUpRequest,\n UpdateUserRequest,\n PasswordChangeRequest,\n PasswordResetRequest,\n PasswordResetConfirmRequest,\n OAuthSignInRequest,\n OAuthCallbackRequest,\n MagicLinkRequest,\n MagicLinkVerifyRequest,\n PhoneAuthRequest,\n PhoneVerifyRequest,\n TwoFactorSetupRequest,\n TwoFactorSetupResponse,\n TwoFactorVerifyRequest,\n PasskeyRegisterRequest,\n PasskeyAuthRequest,\n User,\n Session,\n OAuthProvider,\n TwoFactorMethod,\n PasskeyCredential,\n AuthError,\n ProviderConfig,\n} from '../types';\nimport { toAuthError } from '../utils';\n\n/**\n * Base provider class with common functionality\n */\nexport abstract class BaseAuthProvider implements AuthProvider {\n abstract readonly name: string;\n protected config: ProviderConfig = {};\n protected initialized = false;\n\n /**\n * Initialize the provider\n */\n async initialize(config: ProviderConfig): Promise<void> {\n this.config = config;\n this.initialized = true;\n }\n\n /**\n * Ensure provider is initialized\n */\n protected ensureInitialized(): void {\n if (!this.initialized) {\n throw new Error(`Provider ${this.name} is not initialized`);\n }\n }\n\n /**\n * Make HTTP request\n */\n protected async request<T>(\n url: string,\n options: RequestInit = {}\n ): Promise<T> {\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({\n message: response.statusText,\n }));\n throw error;\n }\n\n return response.json();\n }\n\n // Abstract methods that must be implemented by subclasses\n abstract signIn(request: SignInRequest): Promise<AuthResponse>;\n abstract signUp(request: SignUpRequest): Promise<AuthResponse>;\n abstract signOut(): Promise<void>;\n abstract getCurrentUser(): Promise<User | null>;\n abstract getCurrentSession(): Promise<Session | null>;\n abstract refreshSession(): Promise<Session>;\n abstract updateUser(request: UpdateUserRequest): Promise<User>;\n abstract changePassword(request: PasswordChangeRequest): Promise<void>;\n abstract requestPasswordReset(request: PasswordResetRequest): Promise<void>;\n abstract confirmPasswordReset(request: PasswordResetConfirmRequest): Promise<void>;\n abstract oauthSignIn(request: OAuthSignInRequest): Promise<string>;\n abstract oauthCallback(request: OAuthCallbackRequest): Promise<AuthResponse>;\n abstract getOAuthProviders(): Promise<OAuthProvider[]>;\n abstract sendMagicLink(request: MagicLinkRequest): Promise<void>;\n abstract verifyMagicLink(request: MagicLinkVerifyRequest): Promise<AuthResponse>;\n abstract sendPhoneCode(request: PhoneAuthRequest): Promise<void>;\n abstract verifyPhoneCode(request: PhoneVerifyRequest): Promise<AuthResponse>;\n abstract setupTwoFactor(request: TwoFactorSetupRequest): Promise<TwoFactorSetupResponse>;\n abstract verifyTwoFactor(request: TwoFactorVerifyRequest): Promise<AuthResponse>;\n abstract disableTwoFactor(): Promise<void>;\n abstract getTwoFactorStatus(): Promise<TwoFactorMethod[]>;\n abstract registerPasskey(request: PasskeyRegisterRequest): Promise<PasskeyCredential>;\n abstract authenticatePasskey(request: PasskeyAuthRequest): Promise<AuthResponse>;\n abstract listPasskeys(): Promise<PasskeyCredential[]>;\n abstract deletePasskey(credentialId: string): Promise<void>;\n\n /**\n * Normalize error to AuthError\n */\n normalizeError(error: unknown): AuthError {\n return toAuthError(error);\n }\n}\n\n"]}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// src/types/auth.ts
|
|
2
|
+
var AuthError = class _AuthError extends Error {
|
|
3
|
+
constructor(message, type = "unknown_error" /* UNKNOWN_ERROR */, options) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "AuthError";
|
|
6
|
+
this.type = type;
|
|
7
|
+
this.details = options?.details;
|
|
8
|
+
this.code = options?.code;
|
|
9
|
+
this.originalError = options?.originalError;
|
|
10
|
+
if (Error.captureStackTrace) {
|
|
11
|
+
Error.captureStackTrace(this, _AuthError);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/utils/errors.ts
|
|
17
|
+
function isAuthError(error) {
|
|
18
|
+
return error instanceof AuthError;
|
|
19
|
+
}
|
|
20
|
+
function toAuthError(error) {
|
|
21
|
+
if (isAuthError(error)) {
|
|
22
|
+
return error;
|
|
23
|
+
}
|
|
24
|
+
if (error instanceof Error) {
|
|
25
|
+
return new AuthError(error.message, "unknown_error" /* UNKNOWN_ERROR */, {
|
|
26
|
+
details: {
|
|
27
|
+
originalError: error.name,
|
|
28
|
+
stack: error.stack
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
if (typeof error === "string") {
|
|
33
|
+
return new AuthError(error, "unknown_error" /* UNKNOWN_ERROR */);
|
|
34
|
+
}
|
|
35
|
+
return new AuthError(
|
|
36
|
+
"An unknown error occurred",
|
|
37
|
+
"unknown_error" /* UNKNOWN_ERROR */,
|
|
38
|
+
{ details: { error } }
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/adapters/base-provider.ts
|
|
43
|
+
var BaseAuthProvider = class {
|
|
44
|
+
constructor() {
|
|
45
|
+
this.config = {};
|
|
46
|
+
this.initialized = false;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Initialize the provider
|
|
50
|
+
*/
|
|
51
|
+
async initialize(config) {
|
|
52
|
+
this.config = config;
|
|
53
|
+
this.initialized = true;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Ensure provider is initialized
|
|
57
|
+
*/
|
|
58
|
+
ensureInitialized() {
|
|
59
|
+
if (!this.initialized) {
|
|
60
|
+
throw new Error(`Provider ${this.name} is not initialized`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Make HTTP request
|
|
65
|
+
*/
|
|
66
|
+
async request(url, options = {}) {
|
|
67
|
+
const response = await fetch(url, {
|
|
68
|
+
...options,
|
|
69
|
+
headers: {
|
|
70
|
+
"Content-Type": "application/json",
|
|
71
|
+
...options.headers
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
const error = await response.json().catch(() => ({
|
|
76
|
+
message: response.statusText
|
|
77
|
+
}));
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
return response.json();
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Normalize error to AuthError
|
|
84
|
+
*/
|
|
85
|
+
normalizeError(error) {
|
|
86
|
+
return toAuthError(error);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export { BaseAuthProvider };
|
|
91
|
+
//# sourceMappingURL=index.mjs.map
|
|
92
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types/auth.ts","../../src/utils/errors.ts","../../src/adapters/base-provider.ts"],"names":[],"mappings":";AAyEO,IAAM,SAAA,GAAN,MAAM,UAAA,SAAkB,KAAA,CAAM;AAAA,EAMnC,WAAA,CACE,OAAA,EACA,IAAA,GAAsB,eAAA,sBACtB,OAAA,EAKA;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,WAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,UAAU,OAAA,EAAS,OAAA;AACxB,IAAA,IAAA,CAAK,OAAO,OAAA,EAAS,IAAA;AACrB,IAAA,IAAA,CAAK,gBAAgB,OAAA,EAAS,aAAA;AAG9B,IAAA,IAAI,MAAM,iBAAA,EAAmB;AAC3B,MAAA,KAAA,CAAM,iBAAA,CAAkB,MAAM,UAAS,CAAA;AAAA,IACzC;AAAA,EACF;AACF,CAAA;;;AC7EO,SAAS,YAAY,KAAA,EAAoC;AAC9D,EAAA,OAAO,KAAA,YAAiB,SAAA;AAC1B;AAKO,SAAS,YAAY,KAAA,EAA2B;AACrD,EAAA,IAAI,WAAA,CAAY,KAAK,CAAA,EAAG;AACtB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,iBAAiB,KAAA,EAAO;AAC1B,IAAA,OAAO,IAAI,SAAA,CAAU,KAAA,CAAM,OAAA,EAAA,eAAA,sBAAsC;AAAA,MAC/D,OAAA,EAAS;AAAA,QACP,eAAe,KAAA,CAAM,IAAA;AAAA,QACrB,OAAO,KAAA,CAAM;AAAA;AACf,KACD,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,IAAI,UAAU,KAAA,EAAA,eAAA,qBAAkC;AAAA,EACzD;AAEA,EAAA,OAAO,IAAI,SAAA;AAAA,IACT,2BAAA;AAAA,IAAA,eAAA;AAAA,IAEA,EAAE,OAAA,EAAS,EAAE,KAAA,EAAM;AAAE,GACvB;AACF;;;AChBO,IAAe,mBAAf,MAAwD;AAAA,EAAxD,WAAA,GAAA;AAEL,IAAA,IAAA,CAAU,SAAyB,EAAC;AACpC,IAAA,IAAA,CAAU,WAAA,GAAc,KAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKxB,MAAM,WAAW,MAAA,EAAuC;AACtD,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKU,iBAAA,GAA0B;AAClC,IAAA,IAAI,CAAC,KAAK,WAAA,EAAa;AACrB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,SAAA,EAAY,IAAA,CAAK,IAAI,CAAA,mBAAA,CAAqB,CAAA;AAAA,IAC5D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAgB,OAAA,CACd,GAAA,EACA,OAAA,GAAuB,EAAC,EACZ;AACZ,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAChC,GAAG,OAAA;AAAA,MACH,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,GAAG,OAAA,CAAQ;AAAA;AACb,KACD,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,QAAQ,MAAM,QAAA,CAAS,IAAA,EAAK,CAAE,MAAM,OAAO;AAAA,QAC/C,SAAS,QAAA,CAAS;AAAA,OACpB,CAAE,CAAA;AACF,MAAA,MAAM,KAAA;AAAA,IACR;AAEA,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAgCA,eAAe,KAAA,EAA2B;AACxC,IAAA,OAAO,YAAY,KAAK,CAAA;AAAA,EAC1B;AACF","file":"index.mjs","sourcesContent":["/**\n * Core authentication types and interfaces\n */\n\n/**\n * Authentication state enum\n */\nexport enum AuthState {\n AUTHENTICATED = 'authenticated',\n UNAUTHENTICATED = 'unauthenticated',\n LOADING = 'loading',\n ERROR = 'error',\n}\n\n/**\n * User profile interface\n */\nexport interface User {\n id: string;\n email?: string;\n username?: string;\n phone?: string;\n emailVerified?: boolean;\n phoneVerified?: boolean;\n name?: string;\n firstName?: string;\n lastName?: string;\n avatar?: string;\n metadata?: Record<string, unknown>;\n createdAt?: Date;\n updatedAt?: Date;\n \n // Organization fields\n organizationId?: string;\n organizationRole?: string;\n organizationMemberships?: OrganizationMembership[];\n}\n\n/**\n * Session interface\n */\nexport interface Session {\n id: string;\n userId: string;\n token: string;\n expiresAt?: Date;\n createdAt?: Date;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Auth error types\n */\nexport enum AuthErrorType {\n INVALID_CREDENTIALS = 'invalid_credentials',\n USER_NOT_FOUND = 'user_not_found',\n USER_ALREADY_EXISTS = 'user_already_exists',\n INVALID_TOKEN = 'invalid_token',\n TOKEN_EXPIRED = 'token_expired',\n NETWORK_ERROR = 'network_error',\n VALIDATION_ERROR = 'validation_error',\n MFA_REQUIRED = 'mfa_required',\n EMAIL_NOT_VERIFIED = 'email_not_verified',\n PHONE_NOT_VERIFIED = 'phone_not_verified',\n RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded',\n UNKNOWN_ERROR = 'unknown_error',\n}\n\n/**\n * Auth error class\n * \n * Extends Error to provide proper error handling with auth-specific context\n */\nexport class AuthError extends Error {\n public readonly type: AuthErrorType;\n public readonly details?: Record<string, unknown>;\n public readonly code?: string | number;\n public readonly originalError?: unknown;\n\n constructor(\n message: string,\n type: AuthErrorType = AuthErrorType.UNKNOWN_ERROR,\n options?: {\n details?: Record<string, unknown>;\n code?: string | number;\n originalError?: unknown;\n }\n ) {\n super(message);\n this.name = 'AuthError';\n this.type = type;\n this.details = options?.details;\n this.code = options?.code;\n this.originalError = options?.originalError;\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, AuthError);\n }\n }\n}\n\n/**\n * Auth context state\n */\nexport interface AuthContext {\n state: AuthState;\n user: User | null;\n session: Session | null;\n error: AuthError | null;\n isAuthenticated: boolean;\n isLoading: boolean;\n}\n\n/**\n * OAuth provider types\n */\nexport enum OAuthProvider {\n GOOGLE = 'google',\n GITHUB = 'github',\n FACEBOOK = 'facebook',\n TWITTER = 'twitter',\n MICROSOFT = 'microsoft',\n APPLE = 'apple',\n LINKEDIN = 'linkedin',\n DISCORD = 'discord',\n}\n\n/**\n * OAuth configuration\n */\nexport interface OAuthConfig {\n provider: OAuthProvider;\n clientId: string;\n redirectUri: string;\n scope?: string[];\n state?: string;\n}\n\n/**\n * 2FA method types\n */\nexport enum TwoFactorMethod {\n TOTP = 'totp',\n SMS = 'sms',\n EMAIL = 'email',\n BACKUP_CODE = 'backup_code',\n}\n\n/**\n * 2FA configuration\n */\nexport interface TwoFactorConfig {\n method: TwoFactorMethod;\n enabled: boolean;\n verified?: boolean;\n}\n\n/**\n * Passkey/WebAuthn types\n */\nexport interface PasskeyCredential {\n id: string;\n name?: string;\n createdAt?: Date;\n lastUsedAt?: Date;\n}\n\n/**\n * Validation error\n */\nexport interface ValidationError {\n field: string;\n message: string;\n code?: string;\n}\n\n/**\n * Organization interface\n */\nexport interface Organization {\n id: string;\n name: string;\n slug: string;\n logoUrl?: string;\n createdAt?: Date;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Organization membership interface\n */\nexport interface OrganizationMembership {\n organization: Organization;\n role: 'owner' | 'admin' | 'member';\n permissions?: string[];\n}\n\n","/**\n * Error handling utilities\n */\n\nimport { AuthError, AuthErrorType } from '../types';\n\n/**\n * Create an auth error\n * \n * @deprecated Use `new AuthError()` directly instead\n */\nexport function createAuthError(\n type: AuthErrorType,\n message: string,\n details?: Record<string, unknown>,\n code?: string | number\n): AuthError {\n return new AuthError(message, type, { details, code });\n}\n\n/**\n * Check if an error is an auth error\n */\nexport function isAuthError(error: unknown): error is AuthError {\n return error instanceof AuthError;\n}\n\n/**\n * Convert unknown error to auth error\n */\nexport function toAuthError(error: unknown): AuthError {\n if (isAuthError(error)) {\n return error;\n }\n\n if (error instanceof Error) {\n return new AuthError(error.message, AuthErrorType.UNKNOWN_ERROR, {\n details: {\n originalError: error.name,\n stack: error.stack,\n },\n });\n }\n\n if (typeof error === 'string') {\n return new AuthError(error, AuthErrorType.UNKNOWN_ERROR);\n }\n\n return new AuthError(\n 'An unknown error occurred',\n AuthErrorType.UNKNOWN_ERROR,\n { details: { error } }\n );\n}\n\n/**\n * Check if error is a network error\n */\nexport function isNetworkError(error: unknown): boolean {\n if (error instanceof Error) {\n return (\n error.name === 'NetworkError' ||\n error.message.includes('network') ||\n error.message.includes('fetch')\n );\n }\n return false;\n}\n\n/**\n * Check if error indicates authentication is required\n */\nexport function isUnauthenticatedError(error: unknown): boolean {\n if (isAuthError(error)) {\n return (\n error.type === AuthErrorType.INVALID_TOKEN ||\n error.type === AuthErrorType.TOKEN_EXPIRED\n );\n }\n return false;\n}\n\n/**\n * Check if error requires MFA\n */\nexport function isMFARequiredError(error: unknown): boolean {\n if (isAuthError(error)) {\n return error.type === AuthErrorType.MFA_REQUIRED;\n }\n return false;\n}\n","/**\n * Base auth provider implementation\n */\n\nimport type {\n AuthProvider,\n AuthResponse,\n SignInRequest,\n SignUpRequest,\n UpdateUserRequest,\n PasswordChangeRequest,\n PasswordResetRequest,\n PasswordResetConfirmRequest,\n OAuthSignInRequest,\n OAuthCallbackRequest,\n MagicLinkRequest,\n MagicLinkVerifyRequest,\n PhoneAuthRequest,\n PhoneVerifyRequest,\n TwoFactorSetupRequest,\n TwoFactorSetupResponse,\n TwoFactorVerifyRequest,\n PasskeyRegisterRequest,\n PasskeyAuthRequest,\n User,\n Session,\n OAuthProvider,\n TwoFactorMethod,\n PasskeyCredential,\n AuthError,\n ProviderConfig,\n} from '../types';\nimport { toAuthError } from '../utils';\n\n/**\n * Base provider class with common functionality\n */\nexport abstract class BaseAuthProvider implements AuthProvider {\n abstract readonly name: string;\n protected config: ProviderConfig = {};\n protected initialized = false;\n\n /**\n * Initialize the provider\n */\n async initialize(config: ProviderConfig): Promise<void> {\n this.config = config;\n this.initialized = true;\n }\n\n /**\n * Ensure provider is initialized\n */\n protected ensureInitialized(): void {\n if (!this.initialized) {\n throw new Error(`Provider ${this.name} is not initialized`);\n }\n }\n\n /**\n * Make HTTP request\n */\n protected async request<T>(\n url: string,\n options: RequestInit = {}\n ): Promise<T> {\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({\n message: response.statusText,\n }));\n throw error;\n }\n\n return response.json();\n }\n\n // Abstract methods that must be implemented by subclasses\n abstract signIn(request: SignInRequest): Promise<AuthResponse>;\n abstract signUp(request: SignUpRequest): Promise<AuthResponse>;\n abstract signOut(): Promise<void>;\n abstract getCurrentUser(): Promise<User | null>;\n abstract getCurrentSession(): Promise<Session | null>;\n abstract refreshSession(): Promise<Session>;\n abstract updateUser(request: UpdateUserRequest): Promise<User>;\n abstract changePassword(request: PasswordChangeRequest): Promise<void>;\n abstract requestPasswordReset(request: PasswordResetRequest): Promise<void>;\n abstract confirmPasswordReset(request: PasswordResetConfirmRequest): Promise<void>;\n abstract oauthSignIn(request: OAuthSignInRequest): Promise<string>;\n abstract oauthCallback(request: OAuthCallbackRequest): Promise<AuthResponse>;\n abstract getOAuthProviders(): Promise<OAuthProvider[]>;\n abstract sendMagicLink(request: MagicLinkRequest): Promise<void>;\n abstract verifyMagicLink(request: MagicLinkVerifyRequest): Promise<AuthResponse>;\n abstract sendPhoneCode(request: PhoneAuthRequest): Promise<void>;\n abstract verifyPhoneCode(request: PhoneVerifyRequest): Promise<AuthResponse>;\n abstract setupTwoFactor(request: TwoFactorSetupRequest): Promise<TwoFactorSetupResponse>;\n abstract verifyTwoFactor(request: TwoFactorVerifyRequest): Promise<AuthResponse>;\n abstract disableTwoFactor(): Promise<void>;\n abstract getTwoFactorStatus(): Promise<TwoFactorMethod[]>;\n abstract registerPasskey(request: PasskeyRegisterRequest): Promise<PasskeyCredential>;\n abstract authenticatePasskey(request: PasskeyAuthRequest): Promise<AuthResponse>;\n abstract listPasskeys(): Promise<PasskeyCredential[]>;\n abstract deletePasskey(credentialId: string): Promise<void>;\n\n /**\n * Normalize error to AuthError\n */\n normalizeError(error: unknown): AuthError {\n return toAuthError(error);\n }\n}\n\n"]}
|