@proveanything/smartlinks-auth-ui 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 +323 -0
- package/dist/api.d.ts +44 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +105 -0
- package/dist/components/AuthContainer.d.ts +12 -0
- package/dist/components/AuthContainer.d.ts.map +1 -0
- package/dist/components/AuthContainer.js +46 -0
- package/dist/components/AuthUIPreview.d.ts +11 -0
- package/dist/components/AuthUIPreview.d.ts.map +1 -0
- package/dist/components/AuthUIPreview.js +10 -0
- package/dist/components/EmailAuthForm.d.ts +14 -0
- package/dist/components/EmailAuthForm.d.ts.map +1 -0
- package/dist/components/EmailAuthForm.js +20 -0
- package/dist/components/PasswordResetForm.d.ts +13 -0
- package/dist/components/PasswordResetForm.d.ts.map +1 -0
- package/dist/components/PasswordResetForm.js +37 -0
- package/dist/components/PhoneAuthForm.d.ts +11 -0
- package/dist/components/PhoneAuthForm.d.ts.map +1 -0
- package/dist/components/PhoneAuthForm.js +20 -0
- package/dist/components/ProtectedRoute.d.ts +9 -0
- package/dist/components/ProtectedRoute.d.ts.map +1 -0
- package/dist/components/ProtectedRoute.js +20 -0
- package/dist/components/ProviderButtons.d.ts +12 -0
- package/dist/components/ProviderButtons.d.ts.map +1 -0
- package/dist/components/ProviderButtons.js +8 -0
- package/dist/context/AuthContext.d.ts +20 -0
- package/dist/context/AuthContext.d.ts.map +1 -0
- package/dist/context/AuthContext.js +113 -0
- package/dist/index.css +2 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.css +2 -0
- package/dist/index.esm.css.map +1 -0
- package/dist/index.esm.js +840 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +867 -0
- package/dist/index.js.map +1 -0
- package/dist/smartlinks.d.ts +65 -0
- package/dist/smartlinks.d.ts.map +1 -0
- package/dist/smartlinks.js +141 -0
- package/dist/types.d.ts +101 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/utils/tokenStorage.d.ts +14 -0
- package/dist/utils/tokenStorage.d.ts.map +1 -0
- package/dist/utils/tokenStorage.js +71 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
# @smartlinks/auth-ui
|
|
2
|
+
|
|
3
|
+
A lightweight, drop-in React authentication UI component library with bearer token support, session management, and multi-tenant account data. Provides a complete authentication solution without exposing backend implementation details to the frontend.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔐 **Multiple Auth Methods**: Email/Password, Google OAuth, SMS (Phone)
|
|
8
|
+
- 🎨 **Beautiful Pre-built UI**: Professional, responsive authentication flows
|
|
9
|
+
- 🪙 **Bearer Token Based**: Returns JWT tokens for seamless API authentication
|
|
10
|
+
- 🗂️ **Session Management**: Built-in AuthProvider, useAuth hook, and ProtectedRoute
|
|
11
|
+
- 🏢 **Multi-Tenant Support**: Client ID for identifying different systems/tenants
|
|
12
|
+
- 📊 **Account Data**: Store custom metadata per user account
|
|
13
|
+
- 🔗 **URL Flow Handling**: Email verification, password reset links
|
|
14
|
+
- ⚡ **Lightweight**: Minimal dependencies, no backend SDK required in consuming apps
|
|
15
|
+
- 📱 **Fully Responsive**: Works seamlessly on mobile and desktop
|
|
16
|
+
- ♿ **Accessible**: WCAG compliant authentication forms
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @smartlinks/auth-ui
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
### Basic Usage with Session Management
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { SmartlinksAuthUI, AuthProvider, useAuth } from '@smartlinks/auth-ui';
|
|
30
|
+
|
|
31
|
+
function App() {
|
|
32
|
+
return (
|
|
33
|
+
<AuthProvider apiEndpoint="https://your-api.smartlinks.com" clientId="your-client-123">
|
|
34
|
+
<YourApp />
|
|
35
|
+
</AuthProvider>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function YourApp() {
|
|
40
|
+
const { user, token, accountData, isAuthenticated, logout } = useAuth();
|
|
41
|
+
|
|
42
|
+
if (isAuthenticated) {
|
|
43
|
+
return (
|
|
44
|
+
<div>
|
|
45
|
+
<h1>Welcome, {user.displayName}!</h1>
|
|
46
|
+
<p>Account: {accountData?.companyName}</p>
|
|
47
|
+
<button onClick={logout}>Logout</button>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<SmartlinksAuthUI
|
|
54
|
+
apiEndpoint="https://your-api.smartlinks.com"
|
|
55
|
+
clientId="your-client-123" // REQUIRED - identifies your application
|
|
56
|
+
clientName="Acme Corp"
|
|
57
|
+
accountData={{
|
|
58
|
+
companyName: "Acme Corp",
|
|
59
|
+
plan: "pro"
|
|
60
|
+
}}
|
|
61
|
+
onAuthSuccess={(token, user, accountData) => {
|
|
62
|
+
console.log('Authenticated!', { token, user, accountData });
|
|
63
|
+
}}
|
|
64
|
+
enabledProviders={['email', 'google', 'phone']}
|
|
65
|
+
/>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Props
|
|
71
|
+
|
|
72
|
+
### SmartlinksAuthUI
|
|
73
|
+
|
|
74
|
+
| Prop | Type | Required | Description |
|
|
75
|
+
|------|------|----------|-------------|
|
|
76
|
+
| `apiEndpoint` | string | Yes | Your Smartlinks API endpoint (e.g., `https://api.smartlinks.com`) |
|
|
77
|
+
| `clientId` | string | **Yes** | **REQUIRED** - Client identifier used in all API calls |
|
|
78
|
+
| `clientName` | string | No | Client name for branded emails |
|
|
79
|
+
| `accountData` | Record<string, any> | No | Custom metadata to store on registration |
|
|
80
|
+
| `onAuthSuccess` | (token: string, user: AuthUser, accountData?: Record<string, any>) => void | Yes | Callback when authentication succeeds |
|
|
81
|
+
| `onAuthError` | (error: Error) => void | No | Callback when authentication fails |
|
|
82
|
+
| `enabledProviders` | Array<'email' \| 'google' \| 'phone'> | No | Auth providers to enable (default: all) |
|
|
83
|
+
| `redirectUrl` | string | No | URL to redirect after auth (default: current page) |
|
|
84
|
+
| `theme` | 'light' \| 'dark' | No | UI theme (default: 'light') |
|
|
85
|
+
|
|
86
|
+
## Session Management
|
|
87
|
+
|
|
88
|
+
### AuthProvider
|
|
89
|
+
|
|
90
|
+
Wrap your app with AuthProvider to enable session management:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
import { AuthProvider } from '@smartlinks/auth-ui';
|
|
94
|
+
|
|
95
|
+
<AuthProvider apiEndpoint="https://your-api.smartlinks.com/api/v1/authkit">
|
|
96
|
+
<App />
|
|
97
|
+
</AuthProvider>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### useAuth Hook
|
|
101
|
+
|
|
102
|
+
Access authentication state anywhere in your app:
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
import { useAuth } from '@smartlinks/auth-ui';
|
|
106
|
+
|
|
107
|
+
function MyComponent() {
|
|
108
|
+
const {
|
|
109
|
+
user, // Current user object
|
|
110
|
+
token, // Bearer token
|
|
111
|
+
accountData, // Custom account metadata
|
|
112
|
+
isAuthenticated, // Boolean auth status
|
|
113
|
+
isLoading, // Loading state
|
|
114
|
+
login, // Login function
|
|
115
|
+
logout, // Logout function
|
|
116
|
+
getToken, // Get current token
|
|
117
|
+
} = useAuth();
|
|
118
|
+
|
|
119
|
+
// Your component logic
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### ProtectedRoute
|
|
124
|
+
|
|
125
|
+
Protect routes that require authentication:
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
import { ProtectedRoute } from '@smartlinks/auth-ui';
|
|
129
|
+
|
|
130
|
+
<ProtectedRoute fallback={<LoginPage />}>
|
|
131
|
+
<DashboardPage />
|
|
132
|
+
</ProtectedRoute>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Multi-Tenant & Account Data
|
|
136
|
+
|
|
137
|
+
### Client ID
|
|
138
|
+
|
|
139
|
+
Use `clientId` to identify which system/tenant is using the auth:
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
<SmartlinksAuthUI
|
|
143
|
+
apiEndpoint="https://api.smartlinks.com/api/v1/authkit"
|
|
144
|
+
clientId="acme-corp-production"
|
|
145
|
+
onAuthSuccess={(token, user, accountData) => {
|
|
146
|
+
console.log('Client:', accountData.clientId);
|
|
147
|
+
}}
|
|
148
|
+
/>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Account Data
|
|
152
|
+
|
|
153
|
+
Store custom metadata per user account on registration:
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
<SmartlinksAuthUI
|
|
157
|
+
apiEndpoint="https://api.smartlinks.com/api/v1/authkit"
|
|
158
|
+
clientId="your-client-123"
|
|
159
|
+
clientName="Acme Corporation"
|
|
160
|
+
accountData={{
|
|
161
|
+
companyName: "Acme Corporation",
|
|
162
|
+
plan: "enterprise",
|
|
163
|
+
seats: 50,
|
|
164
|
+
customField: "value"
|
|
165
|
+
}}
|
|
166
|
+
onAuthSuccess={(token, user, accountData) => {
|
|
167
|
+
// accountData now includes all custom fields
|
|
168
|
+
console.log('Company:', accountData.companyName);
|
|
169
|
+
console.log('Plan:', accountData.plan);
|
|
170
|
+
}}
|
|
171
|
+
/>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
On login, the account data is automatically retrieved and returned.
|
|
175
|
+
|
|
176
|
+
## Authentication Flows
|
|
177
|
+
|
|
178
|
+
### Email/Password Login
|
|
179
|
+
```tsx
|
|
180
|
+
<SmartlinksAuthUI
|
|
181
|
+
apiEndpoint="https://api.smartlinks.com/api/v1/authkit"
|
|
182
|
+
onAuthSuccess={(token) => console.log('Token:', token)}
|
|
183
|
+
enabledProviders={['email']}
|
|
184
|
+
/>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Google OAuth
|
|
188
|
+
```tsx
|
|
189
|
+
<SmartlinksAuthUI
|
|
190
|
+
apiEndpoint="https://api.smartlinks.com/api/v1/authkit"
|
|
191
|
+
onAuthSuccess={(token) => console.log('Token:', token)}
|
|
192
|
+
enabledProviders={['google']}
|
|
193
|
+
/>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Phone/SMS Authentication
|
|
197
|
+
```tsx
|
|
198
|
+
<SmartlinksAuthUI
|
|
199
|
+
apiEndpoint="https://api.smartlinks.com/api/v1/authkit"
|
|
200
|
+
onAuthSuccess={(token) => console.log('Token:', token)}
|
|
201
|
+
enabledProviders={['phone']}
|
|
202
|
+
/>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## URL-Based Flows
|
|
206
|
+
|
|
207
|
+
The component automatically handles URL parameters for:
|
|
208
|
+
|
|
209
|
+
- **Email Verification**: `?mode=verifyEmail&token=xxx`
|
|
210
|
+
- **Password Reset**: `?mode=resetPassword&token=xxx`
|
|
211
|
+
|
|
212
|
+
## API Integration
|
|
213
|
+
|
|
214
|
+
Your Smartlinks API should implement these endpoints with clientId in the URL path:
|
|
215
|
+
|
|
216
|
+
### POST /api/v1/authkit/:clientId/auth/login
|
|
217
|
+
```json
|
|
218
|
+
{
|
|
219
|
+
"email": "user@example.com",
|
|
220
|
+
"password": "password123"
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
Response: `{ "token": "bearer_token", "user": {...} }`
|
|
224
|
+
|
|
225
|
+
### POST /api/v1/authkit/:clientId/auth/register
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"email": "user@example.com",
|
|
229
|
+
"password": "password123",
|
|
230
|
+
"displayName": "John Doe"
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
Response: `{ "token": "bearer_token", "user": {...} }`
|
|
234
|
+
|
|
235
|
+
### POST /api/v1/authkit/:clientId/auth/google
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"idToken": "google_id_token"
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
Response: `{ "token": "bearer_token", "user": {...} }`
|
|
242
|
+
|
|
243
|
+
### POST /api/v1/authkit/:clientId/auth/phone/send-code
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"phoneNumber": "+1234567890"
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
Response: `{ "verificationId": "xxx" }`
|
|
250
|
+
|
|
251
|
+
### POST /api/v1/authkit/:clientId/auth/phone/verify
|
|
252
|
+
```json
|
|
253
|
+
{
|
|
254
|
+
"verificationId": "xxx",
|
|
255
|
+
"code": "123456"
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
Response: `{ "token": "bearer_token", "user": {...} }`
|
|
259
|
+
|
|
260
|
+
### POST /api/v1/authkit/:clientId/auth/reset-password
|
|
261
|
+
```json
|
|
262
|
+
{
|
|
263
|
+
"email": "user@example.com"
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
Response: `{ "success": true }`
|
|
267
|
+
|
|
268
|
+
### POST /api/v1/authkit/:clientId/auth/verify-reset-token
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"oobCode": "reset_code_from_url"
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
Response: `{ "valid": true, "email": "user@example.com" }`
|
|
275
|
+
|
|
276
|
+
### POST /api/v1/authkit/:clientId/auth/complete-reset
|
|
277
|
+
```json
|
|
278
|
+
{
|
|
279
|
+
"token": "reset_token_from_email",
|
|
280
|
+
"newPassword": "newpass123"
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
Response: `{ "success": true }`
|
|
284
|
+
|
|
285
|
+
### GET /api/v1/authkit/:clientId/config
|
|
286
|
+
Get UI configuration for the client (public, cached)
|
|
287
|
+
|
|
288
|
+
Response:
|
|
289
|
+
```json
|
|
290
|
+
{
|
|
291
|
+
"title": "Welcome to Acme",
|
|
292
|
+
"subtitle": "Sign in to your account",
|
|
293
|
+
"primaryColor": "#3B82F6",
|
|
294
|
+
"buttonStyle": "rounded",
|
|
295
|
+
"enabledProviders": ["email", "google"]
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Styling
|
|
300
|
+
|
|
301
|
+
The component uses CSS modules and can be customized:
|
|
302
|
+
|
|
303
|
+
```tsx
|
|
304
|
+
<SmartlinksAuthUI
|
|
305
|
+
apiEndpoint="https://api.smartlinks.com"
|
|
306
|
+
clientId="your-client-123"
|
|
307
|
+
onAuthSuccess={handleAuth}
|
|
308
|
+
className="custom-auth-container"
|
|
309
|
+
theme="dark"
|
|
310
|
+
/>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## TypeScript Support
|
|
314
|
+
|
|
315
|
+
Full TypeScript definitions included:
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
import type { AuthUser, AuthToken, AuthProvider } from '@smartlinks/auth-ui';
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## License
|
|
322
|
+
|
|
323
|
+
MIT © Smartlinks
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { AuthResponse, AuthFormData, AuthUIConfig } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* AuthAPI - Thin wrapper around Smartlinks SDK authKit namespace
|
|
4
|
+
* All authentication operations now use the global Smartlinks SDK
|
|
5
|
+
*/
|
|
6
|
+
export declare class AuthAPI {
|
|
7
|
+
private clientId;
|
|
8
|
+
private clientName?;
|
|
9
|
+
constructor(_apiEndpoint: string, clientId: string, clientName?: string);
|
|
10
|
+
login(email: string, password: string): Promise<AuthResponse>;
|
|
11
|
+
register(data: AuthFormData): Promise<AuthResponse>;
|
|
12
|
+
loginWithGoogle(idToken: string): Promise<AuthResponse>;
|
|
13
|
+
sendPhoneCode(phoneNumber: string): Promise<{
|
|
14
|
+
verificationId: string;
|
|
15
|
+
}>;
|
|
16
|
+
verifyPhoneCode(verificationId: string, code: string): Promise<AuthResponse>;
|
|
17
|
+
requestPasswordReset(email: string, redirectUrl: string): Promise<{
|
|
18
|
+
success: boolean;
|
|
19
|
+
message: string;
|
|
20
|
+
}>;
|
|
21
|
+
verifyResetToken(token: string): Promise<{
|
|
22
|
+
valid: boolean;
|
|
23
|
+
email?: string;
|
|
24
|
+
expiresAt?: number;
|
|
25
|
+
message?: string;
|
|
26
|
+
}>;
|
|
27
|
+
completePasswordReset(token: string, newPassword: string): Promise<{
|
|
28
|
+
success: boolean;
|
|
29
|
+
message: string;
|
|
30
|
+
}>;
|
|
31
|
+
sendEmailVerification(userId: string, email: string, redirectUrl: string): Promise<{
|
|
32
|
+
success: boolean;
|
|
33
|
+
message: string;
|
|
34
|
+
}>;
|
|
35
|
+
verifyEmailWithToken(token: string): Promise<AuthResponse & {
|
|
36
|
+
message: string;
|
|
37
|
+
}>;
|
|
38
|
+
resendVerification(userId: string, email: string, redirectUrl: string): Promise<{
|
|
39
|
+
success: boolean;
|
|
40
|
+
message: string;
|
|
41
|
+
}>;
|
|
42
|
+
fetchConfig(): Promise<AuthUIConfig>;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAExE;;;GAGG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAC,CAAS;gBAEhB,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;IAOjE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAI7D,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IASnD,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAIvD,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAIvE,eAAe,CACnB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC;IAIlB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAQxG,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAIlH,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAIzG,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IASzH,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAIhF,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAStH,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC;CAkB3C"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export class AuthAPI {
|
|
2
|
+
constructor(apiEndpoint, clientId, clientName) {
|
|
3
|
+
this.baseUrl = apiEndpoint.replace(/\/$/, '');
|
|
4
|
+
this.clientId = clientId;
|
|
5
|
+
this.clientName = clientName;
|
|
6
|
+
}
|
|
7
|
+
buildUrl(path) {
|
|
8
|
+
return `${this.baseUrl}/api/v1/authkit/${this.clientId}${path}`;
|
|
9
|
+
}
|
|
10
|
+
async request(path, method = 'GET', body) {
|
|
11
|
+
const url = this.buildUrl(path);
|
|
12
|
+
const response = await fetch(url, {
|
|
13
|
+
method,
|
|
14
|
+
headers: {
|
|
15
|
+
'Content-Type': 'application/json',
|
|
16
|
+
'ngrok-skip-browser-warning': 'true',
|
|
17
|
+
},
|
|
18
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
19
|
+
});
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
const error = await response.json().catch(() => ({ message: 'Request failed' }));
|
|
22
|
+
throw new Error(error.message || `HTTP ${response.status}`);
|
|
23
|
+
}
|
|
24
|
+
return response.json();
|
|
25
|
+
}
|
|
26
|
+
async login(email, password) {
|
|
27
|
+
return this.request('/auth/login', 'POST', { email, password });
|
|
28
|
+
}
|
|
29
|
+
async register(data) {
|
|
30
|
+
// Include clientId, redirectUrl, and clientName in registration
|
|
31
|
+
return this.request('/auth/register', 'POST', {
|
|
32
|
+
...data,
|
|
33
|
+
clientId: this.clientId,
|
|
34
|
+
clientName: this.clientName
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
async loginWithGoogle(idToken) {
|
|
38
|
+
return this.request('/auth/google', 'POST', { idToken });
|
|
39
|
+
}
|
|
40
|
+
async sendPhoneCode(phoneNumber) {
|
|
41
|
+
return this.request('/auth/phone/send-code', 'POST', { phoneNumber });
|
|
42
|
+
}
|
|
43
|
+
async verifyPhoneCode(verificationId, code) {
|
|
44
|
+
return this.request('/auth/phone/verify', 'POST', {
|
|
45
|
+
verificationId,
|
|
46
|
+
code,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// Custom Email Flow Methods (using Resend)
|
|
50
|
+
async requestPasswordReset(email, redirectUrl) {
|
|
51
|
+
return this.request('/auth/reset-password', 'POST', {
|
|
52
|
+
email,
|
|
53
|
+
redirectUrl,
|
|
54
|
+
clientName: this.clientName
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async verifyResetToken(token) {
|
|
58
|
+
return this.request('/auth/verify-reset-token', 'POST', { token });
|
|
59
|
+
}
|
|
60
|
+
async completePasswordReset(token, newPassword) {
|
|
61
|
+
return this.request('/auth/complete-reset', 'POST', {
|
|
62
|
+
token,
|
|
63
|
+
newPassword
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async sendEmailVerification(userId, email, redirectUrl) {
|
|
67
|
+
return this.request('/auth/send-verification', 'POST', {
|
|
68
|
+
userId,
|
|
69
|
+
email,
|
|
70
|
+
redirectUrl,
|
|
71
|
+
clientName: this.clientName
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async verifyEmailWithToken(token) {
|
|
75
|
+
return this.request('/auth/verify-email', 'POST', { token });
|
|
76
|
+
}
|
|
77
|
+
async resendVerification(userId, email, redirectUrl) {
|
|
78
|
+
return this.request('/auth/resend-verification', 'POST', {
|
|
79
|
+
userId,
|
|
80
|
+
email,
|
|
81
|
+
redirectUrl,
|
|
82
|
+
clientName: this.clientName
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
// UI Configuration
|
|
86
|
+
async fetchConfig() {
|
|
87
|
+
try {
|
|
88
|
+
return await this.request('/config', 'GET');
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.warn('Failed to fetch UI config, using defaults:', error);
|
|
92
|
+
return {
|
|
93
|
+
branding: {
|
|
94
|
+
title: 'Smartlinks Auth',
|
|
95
|
+
subtitle: 'Sign in to your account',
|
|
96
|
+
primaryColor: '#3B82F6',
|
|
97
|
+
secondaryColor: '#1D4ED8',
|
|
98
|
+
backgroundColor: '#e0f2fe',
|
|
99
|
+
buttonStyle: 'rounded',
|
|
100
|
+
fontFamily: 'Inter, sans-serif'
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import './AuthContainer.css';
|
|
3
|
+
import type { AuthUIConfig } from '../types';
|
|
4
|
+
interface AuthContainerProps {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
theme?: 'light' | 'dark';
|
|
7
|
+
className?: string;
|
|
8
|
+
config?: AuthUIConfig;
|
|
9
|
+
}
|
|
10
|
+
export declare const AuthContainer: React.FC<AuthContainerProps>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=AuthContainer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthContainer.d.ts","sourceRoot":"","sources":["../../src/components/AuthContainer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AACzC,OAAO,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA4GtD,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useEffect } from 'react';
|
|
3
|
+
import './AuthContainer.css';
|
|
4
|
+
export const AuthContainer = ({ children, theme = 'light', className = '', config, }) => {
|
|
5
|
+
// Apply CSS variables for customization
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
if (!config?.branding)
|
|
8
|
+
return;
|
|
9
|
+
const root = document.documentElement;
|
|
10
|
+
const { branding } = config;
|
|
11
|
+
if (branding.primaryColor) {
|
|
12
|
+
root.style.setProperty('--auth-primary-color', branding.primaryColor);
|
|
13
|
+
}
|
|
14
|
+
if (branding.secondaryColor) {
|
|
15
|
+
root.style.setProperty('--auth-secondary-color', branding.secondaryColor);
|
|
16
|
+
}
|
|
17
|
+
if (branding.backgroundColor) {
|
|
18
|
+
root.style.setProperty('--auth-bg-color', branding.backgroundColor);
|
|
19
|
+
}
|
|
20
|
+
if (branding.fontFamily) {
|
|
21
|
+
root.style.setProperty('--auth-font-family', branding.fontFamily);
|
|
22
|
+
}
|
|
23
|
+
// Inject custom CSS if provided
|
|
24
|
+
if (branding.customCss) {
|
|
25
|
+
const styleId = 'auth-custom-styles';
|
|
26
|
+
let styleEl = document.getElementById(styleId);
|
|
27
|
+
if (!styleEl) {
|
|
28
|
+
styleEl = document.createElement('style');
|
|
29
|
+
styleEl.id = styleId;
|
|
30
|
+
document.head.appendChild(styleEl);
|
|
31
|
+
}
|
|
32
|
+
styleEl.textContent = branding.customCss;
|
|
33
|
+
}
|
|
34
|
+
return () => {
|
|
35
|
+
// Cleanup on unmount
|
|
36
|
+
root.style.removeProperty('--auth-primary-color');
|
|
37
|
+
root.style.removeProperty('--auth-secondary-color');
|
|
38
|
+
root.style.removeProperty('--auth-bg-color');
|
|
39
|
+
root.style.removeProperty('--auth-font-family');
|
|
40
|
+
};
|
|
41
|
+
}, [config]);
|
|
42
|
+
const title = config?.branding?.title || 'Smartlinks Auth';
|
|
43
|
+
const subtitle = config?.branding?.subtitle || 'Sign in to your account';
|
|
44
|
+
const logoUrl = config?.branding?.logoUrl;
|
|
45
|
+
return (_jsx("div", { className: `auth-container auth-theme-${theme} ${className}`, children: _jsxs("div", { className: "auth-card", style: { borderRadius: config?.branding?.buttonStyle === 'square' ? '4px' : '12px' }, children: [_jsxs("div", { className: "auth-header", children: [_jsx("div", { className: "auth-logo", children: logoUrl ? (_jsx("img", { src: logoUrl, alt: "Logo", style: { width: 40, height: 40, objectFit: 'contain' } })) : (_jsxs("svg", { width: "40", height: "40", viewBox: "0 0 40 40", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("rect", { width: "40", height: "40", rx: "8", fill: "url(#gradient)" }), _jsx("path", { d: "M20 10L12 18L20 26L28 18L20 10Z", fill: "white", fillOpacity: "0.9" }), _jsx("path", { d: "M20 18L16 22L20 26L24 22L20 18Z", fill: "white" }), _jsx("defs", { children: _jsxs("linearGradient", { id: "gradient", x1: "0", y1: "0", x2: "40", y2: "40", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "var(--auth-primary-color, #3B82F6)" }), _jsx("stop", { offset: "1", stopColor: "var(--auth-secondary-color, #1D4ED8)" })] }) })] })) }), _jsx("h1", { className: "auth-title", children: title }), subtitle && _jsx("p", { className: "auth-subtitle", children: subtitle })] }), _jsx("div", { className: "auth-content", children: children }), (config?.branding?.termsUrl || config?.branding?.privacyUrl) && (_jsxs("div", { className: "auth-footer", children: [config.branding.termsUrl && _jsx("a", { href: config.branding.termsUrl, target: "_blank", rel: "noopener noreferrer", children: "Terms" }), config.branding.termsUrl && config.branding.privacyUrl && _jsx("span", { children: "\u2022" }), config.branding.privacyUrl && _jsx("a", { href: config.branding.privacyUrl, target: "_blank", rel: "noopener noreferrer", children: "Privacy" })] }))] }) }));
|
|
46
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AuthProvider, AuthUIConfig } from '../types';
|
|
3
|
+
interface AuthUIPreviewProps {
|
|
4
|
+
customization?: Partial<AuthUIConfig>;
|
|
5
|
+
enabledProviders?: AuthProvider[];
|
|
6
|
+
theme?: 'light' | 'dark';
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const AuthUIPreview: React.FC<AuthUIPreviewProps>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=AuthUIPreview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthUIPreview.d.ts","sourceRoot":"","sources":["../../src/components/AuthUIPreview.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE3D,UAAU,kBAAkB;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACtC,gBAAgB,CAAC,EAAE,YAAY,EAAE,CAAC;IAClC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA8FtD,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { AuthContainer } from './AuthContainer';
|
|
4
|
+
export const AuthUIPreview = ({ customization, enabledProviders = ['email', 'google', 'phone'], theme = 'light', className, }) => {
|
|
5
|
+
const showEmail = enabledProviders.includes('email');
|
|
6
|
+
const showGoogle = enabledProviders.includes('google');
|
|
7
|
+
const showPhone = enabledProviders.includes('phone');
|
|
8
|
+
const hasProviders = showGoogle || showPhone;
|
|
9
|
+
return (_jsxs(AuthContainer, { theme: theme, className: className, config: customization, children: [showEmail && (_jsxs("div", { className: "auth-form", children: [_jsxs("div", { className: "auth-form-group", children: [_jsx("label", { className: "auth-label", children: "Email" }), _jsx("input", { type: "email", className: "auth-input", placeholder: "Enter your email", disabled: true })] }), _jsxs("div", { className: "auth-form-group", children: [_jsx("label", { className: "auth-label", children: "Password" }), _jsx("input", { type: "password", className: "auth-input", placeholder: "Enter your password", disabled: true })] }), _jsx("button", { className: "auth-button auth-button-primary", disabled: true, children: "Sign In" }), _jsx("div", { style: { textAlign: 'center', marginTop: '1rem' }, children: _jsx("button", { className: "auth-link", disabled: true, children: "Forgot password?" }) }), _jsxs("div", { style: { textAlign: 'center', marginTop: '0.5rem', fontSize: '0.875rem', color: 'var(--auth-text-muted, #6B7280)' }, children: ["Don't have an account?", ' ', _jsx("button", { className: "auth-link", disabled: true, children: "Sign up" })] })] })), hasProviders && (_jsxs(_Fragment, { children: [showEmail && (_jsx("div", { className: "auth-or-divider", children: _jsx("span", { children: "or continue with" }) })), _jsxs("div", { className: "auth-provider-buttons", children: [showGoogle && (_jsxs("button", { className: "auth-provider-button", disabled: true, children: [_jsxs("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", children: [_jsx("path", { d: "M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z", fill: "#4285F4" }), _jsx("path", { d: "M9 18c2.43 0 4.467-.806 5.956-2.183l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332C2.438 15.983 5.482 18 9 18z", fill: "#34A853" }), _jsx("path", { d: "M3.964 10.707c-.18-.54-.282-1.117-.282-1.707 0-.593.102-1.167.282-1.707V4.961H.957C.347 6.175 0 7.548 0 9s.348 2.825.957 4.039l3.007-2.332z", fill: "#FBBC05" }), _jsx("path", { d: "M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0 5.482 0 2.438 2.017.957 4.958L3.964 7.29C4.672 5.163 6.656 3.58 9 3.58z", fill: "#EA4335" })] }), _jsx("span", { children: "Google" })] })), showPhone && (_jsxs("button", { className: "auth-provider-button", disabled: true, children: [_jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" }) }), _jsx("span", { children: "Phone" })] }))] })] }))] }));
|
|
10
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AuthFormData } from '../types';
|
|
3
|
+
import './AuthForm.css';
|
|
4
|
+
interface EmailAuthFormProps {
|
|
5
|
+
mode: 'login' | 'register';
|
|
6
|
+
onSubmit: (data: AuthFormData) => Promise<void>;
|
|
7
|
+
onModeSwitch: () => void;
|
|
8
|
+
onForgotPassword: () => void;
|
|
9
|
+
loading: boolean;
|
|
10
|
+
error?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const EmailAuthForm: React.FC<EmailAuthFormProps>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=EmailAuthForm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailAuthForm.d.ts","sourceRoot":"","sources":["../../src/components/EmailAuthForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,gBAAgB,CAAC;AAExB,UAAU,kBAAkB;IAC1B,IAAI,EAAE,OAAO,GAAG,UAAU,CAAC;IAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA4ItD,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import './AuthForm.css';
|
|
4
|
+
export const EmailAuthForm = ({ mode, onSubmit, onModeSwitch, onForgotPassword, loading, error, }) => {
|
|
5
|
+
const [formData, setFormData] = useState({
|
|
6
|
+
email: '',
|
|
7
|
+
password: '',
|
|
8
|
+
displayName: '',
|
|
9
|
+
});
|
|
10
|
+
const handleSubmit = async (e) => {
|
|
11
|
+
e.preventDefault();
|
|
12
|
+
await onSubmit(formData);
|
|
13
|
+
};
|
|
14
|
+
const handleChange = (field, value) => {
|
|
15
|
+
setFormData(prev => ({ ...prev, [field]: value }));
|
|
16
|
+
};
|
|
17
|
+
return (_jsxs("form", { className: "auth-form", onSubmit: handleSubmit, children: [_jsxs("div", { className: "auth-form-header", children: [_jsx("h2", { className: "auth-form-title", children: mode === 'login' ? 'Sign in' : 'Create account' }), _jsx("p", { className: "auth-form-subtitle", children: mode === 'login'
|
|
18
|
+
? 'Welcome back! Please enter your credentials.'
|
|
19
|
+
: 'Get started by creating your account.' })] }), error && (_jsxs("div", { className: "auth-error", role: "alert", children: [_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: _jsx("path", { d: "M8 0C3.58 0 0 3.58 0 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm1 13H7v-2h2v2zm0-3H7V4h2v6z" }) }), error] })), mode === 'register' && (_jsxs("div", { className: "auth-form-group", children: [_jsx("label", { htmlFor: "displayName", className: "auth-label", children: "Full Name" }), _jsx("input", { type: "text", id: "displayName", className: "auth-input", value: formData.displayName || '', onChange: (e) => handleChange('displayName', e.target.value), required: mode === 'register', disabled: loading, placeholder: "John Doe" })] })), _jsxs("div", { className: "auth-form-group", children: [_jsx("label", { htmlFor: "email", className: "auth-label", children: "Email address" }), _jsx("input", { type: "email", id: "email", className: "auth-input", value: formData.email || '', onChange: (e) => handleChange('email', e.target.value), required: true, disabled: loading, placeholder: "you@example.com", autoComplete: "email" })] }), _jsxs("div", { className: "auth-form-group", children: [_jsx("label", { htmlFor: "password", className: "auth-label", children: "Password" }), _jsx("input", { type: "password", id: "password", className: "auth-input", value: formData.password || '', onChange: (e) => handleChange('password', e.target.value), required: true, disabled: loading, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", autoComplete: mode === 'login' ? 'current-password' : 'new-password', minLength: 6 })] }), mode === 'login' && (_jsx("div", { className: "auth-form-footer", children: _jsx("button", { type: "button", className: "auth-link", onClick: onForgotPassword, disabled: loading, children: "Forgot password?" }) })), _jsx("button", { type: "submit", className: "auth-button auth-button-primary", disabled: loading, children: loading ? (_jsx("span", { className: "auth-spinner" })) : mode === 'login' ? ('Sign in') : ('Create account') }), _jsxs("div", { className: "auth-divider", children: [_jsx("span", { children: mode === 'login' ? "Don't have an account?" : 'Already have an account?' }), _jsx("button", { type: "button", className: "auth-link auth-link-bold", onClick: onModeSwitch, disabled: loading, children: mode === 'login' ? 'Sign up' : 'Sign in' })] })] }));
|
|
20
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import './AuthForm.css';
|
|
3
|
+
interface PasswordResetFormProps {
|
|
4
|
+
onSubmit: (emailOrPassword: string, confirmPassword?: string) => Promise<void>;
|
|
5
|
+
onBack: () => void;
|
|
6
|
+
loading: boolean;
|
|
7
|
+
error?: string;
|
|
8
|
+
success?: boolean;
|
|
9
|
+
token?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare const PasswordResetForm: React.FC<PasswordResetFormProps>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=PasswordResetForm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PasswordResetForm.d.ts","sourceRoot":"","sources":["../../src/components/PasswordResetForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AACxC,OAAO,gBAAgB,CAAC;AAExB,UAAU,sBAAsB;IAC9B,QAAQ,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAwL9D,CAAC"}
|