@authagonal/login 0.1.97
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 +348 -0
- package/dist/App.d.ts +1 -0
- package/dist/api.d.ts +35 -0
- package/dist/branding.d.ts +22 -0
- package/dist/branding.json +8 -0
- package/dist/components/AuthLayout.d.ts +7 -0
- package/dist/components/ui/alert.d.ts +9 -0
- package/dist/components/ui/button.d.ts +11 -0
- package/dist/components/ui/card.d.ts +8 -0
- package/dist/components/ui/input.d.ts +3 -0
- package/dist/components/ui/label.d.ts +3 -0
- package/dist/components/ui/separator.d.ts +6 -0
- package/dist/favicon.svg +1 -0
- package/dist/hooks/useDarkMode.d.ts +6 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/icons.svg +24 -0
- package/dist/index.css +3 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +6332 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/main.d.ts +2 -0
- package/dist/pages/ConsentPage.d.ts +1 -0
- package/dist/pages/DevicePage.d.ts +1 -0
- package/dist/pages/ForgotPasswordPage.d.ts +1 -0
- package/dist/pages/GrantsPage.d.ts +1 -0
- package/dist/pages/LoginPage.d.ts +1 -0
- package/dist/pages/MfaChallengePage.d.ts +1 -0
- package/dist/pages/MfaSetupPage.d.ts +1 -0
- package/dist/pages/RegisterPage.d.ts +1 -0
- package/dist/pages/ResetPasswordPage.d.ts +1 -0
- package/dist/types.d.ts +91 -0
- package/index.html +13 -0
- package/package.json +65 -0
- package/public/branding.json +8 -0
- package/public/favicon.svg +1 -0
- package/public/icons.svg +24 -0
- package/src/App.tsx +32 -0
- package/src/api.ts +156 -0
- package/src/branding.ts +55 -0
- package/src/components/AuthLayout.tsx +107 -0
- package/src/components/ui/alert.tsx +31 -0
- package/src/components/ui/button.tsx +51 -0
- package/src/components/ui/card.tsx +50 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/label.tsx +17 -0
- package/src/components/ui/separator.tsx +16 -0
- package/src/hooks/useDarkMode.ts +39 -0
- package/src/i18n/de.json +111 -0
- package/src/i18n/en.json +136 -0
- package/src/i18n/es.json +111 -0
- package/src/i18n/fr.json +111 -0
- package/src/i18n/index.ts +39 -0
- package/src/i18n/pt.json +111 -0
- package/src/i18n/tlh.json +111 -0
- package/src/i18n/vi.json +111 -0
- package/src/i18n/zh-Hans.json +111 -0
- package/src/index.ts +44 -0
- package/src/lib/utils.ts +6 -0
- package/src/main.tsx +19 -0
- package/src/pages/ConsentPage.tsx +144 -0
- package/src/pages/DevicePage.tsx +145 -0
- package/src/pages/ForgotPasswordPage.tsx +90 -0
- package/src/pages/GrantsPage.tsx +87 -0
- package/src/pages/LoginPage.tsx +423 -0
- package/src/pages/MfaChallengePage.tsx +246 -0
- package/src/pages/MfaSetupPage.tsx +366 -0
- package/src/pages/RegisterPage.tsx +161 -0
- package/src/pages/ResetPasswordPage.tsx +219 -0
- package/src/styles.css +33 -0
- package/src/types.ts +112 -0
- package/tsconfig.app.json +37 -0
- package/tsconfig.json +7 -0
- package/vite.config.ts +54 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useSearchParams, Link } from 'react-router-dom';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { resetPassword, ApiRequestError } from '../api';
|
|
5
|
+
import { Button } from '@/components/ui/button';
|
|
6
|
+
import { Input } from '@/components/ui/input';
|
|
7
|
+
import { Label } from '@/components/ui/label';
|
|
8
|
+
import { Alert } from '@/components/ui/alert';
|
|
9
|
+
import { CardTitle, CardFooter } from '@/components/ui/card';
|
|
10
|
+
import { Check, X } from 'lucide-react';
|
|
11
|
+
|
|
12
|
+
interface PasswordRule {
|
|
13
|
+
rule: string;
|
|
14
|
+
value: number | null;
|
|
15
|
+
label: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface PasswordRequirement {
|
|
19
|
+
label: string;
|
|
20
|
+
met: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const API_URL = import.meta.env.VITE_API_URL || '';
|
|
24
|
+
|
|
25
|
+
const defaultRules: PasswordRule[] = [
|
|
26
|
+
{ rule: 'minLength', value: 8, label: 'At least 8 characters' },
|
|
27
|
+
{ rule: 'uppercase', value: null, label: 'Uppercase letter' },
|
|
28
|
+
{ rule: 'lowercase', value: null, label: 'Lowercase letter' },
|
|
29
|
+
{ rule: 'digit', value: null, label: 'Number' },
|
|
30
|
+
{ rule: 'specialChar', value: null, label: 'Special character' },
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
function evaluateRequirements(password: string, rules: PasswordRule[]): PasswordRequirement[] {
|
|
34
|
+
return rules.map((r) => {
|
|
35
|
+
let met = false;
|
|
36
|
+
switch (r.rule) {
|
|
37
|
+
case 'minLength': met = password.length >= (r.value ?? 8); break;
|
|
38
|
+
case 'uppercase': met = /[A-Z]/.test(password); break;
|
|
39
|
+
case 'lowercase': met = /[a-z]/.test(password); break;
|
|
40
|
+
case 'digit': met = /[0-9]/.test(password); break;
|
|
41
|
+
case 'specialChar': met = /[^A-Za-z0-9]/.test(password); break;
|
|
42
|
+
default: met = true;
|
|
43
|
+
}
|
|
44
|
+
return { label: r.label, met };
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default function ResetPasswordPage() {
|
|
49
|
+
const { t } = useTranslation();
|
|
50
|
+
const [searchParams] = useSearchParams();
|
|
51
|
+
const token = searchParams.get('p') || '';
|
|
52
|
+
|
|
53
|
+
const [newPassword, setNewPassword] = useState('');
|
|
54
|
+
const [confirmPassword, setConfirmPassword] = useState('');
|
|
55
|
+
const [loading, setLoading] = useState(false);
|
|
56
|
+
const [error, setError] = useState('');
|
|
57
|
+
const [success, setSuccess] = useState(false);
|
|
58
|
+
const [validationError, setValidationError] = useState('');
|
|
59
|
+
const [rules, setRules] = useState<PasswordRule[]>(defaultRules);
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
fetch(`${API_URL}/api/auth/password-policy`)
|
|
63
|
+
.then((r) => r.ok ? r.json() : null)
|
|
64
|
+
.then((data) => { if (data?.rules) setRules(data.rules); })
|
|
65
|
+
.catch(() => { /* use defaults */ });
|
|
66
|
+
}, []);
|
|
67
|
+
|
|
68
|
+
function getRuleLabel(rule: PasswordRule): string {
|
|
69
|
+
switch (rule.rule) {
|
|
70
|
+
case 'minLength': return t('ruleMinLength', { count: rule.value ?? 8 });
|
|
71
|
+
case 'uppercase': return t('ruleUppercase');
|
|
72
|
+
case 'lowercase': return t('ruleLowercase');
|
|
73
|
+
case 'digit': return t('ruleDigit');
|
|
74
|
+
case 'specialChar': return t('ruleSpecialChar');
|
|
75
|
+
default: return rule.label;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const localizedRules: PasswordRule[] = rules.map(r => ({
|
|
80
|
+
...r,
|
|
81
|
+
label: getRuleLabel(r),
|
|
82
|
+
}));
|
|
83
|
+
|
|
84
|
+
const requirements = evaluateRequirements(newPassword, localizedRules);
|
|
85
|
+
const allRequirementsMet = requirements.every((r) => r.met);
|
|
86
|
+
|
|
87
|
+
async function handleSubmit(e: React.FormEvent) {
|
|
88
|
+
e.preventDefault();
|
|
89
|
+
setError('');
|
|
90
|
+
setValidationError('');
|
|
91
|
+
|
|
92
|
+
if (!allRequirementsMet) {
|
|
93
|
+
setValidationError(t('passwordNotMeetRequirements'));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (newPassword !== confirmPassword) {
|
|
98
|
+
setValidationError(t('passwordsDoNotMatch'));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
setLoading(true);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
await resetPassword(token, newPassword);
|
|
106
|
+
setSuccess(true);
|
|
107
|
+
} catch (err) {
|
|
108
|
+
if (err instanceof ApiRequestError) {
|
|
109
|
+
switch (err.error) {
|
|
110
|
+
case 'weak_password':
|
|
111
|
+
setError(err.message || t('passwordWeakError'));
|
|
112
|
+
break;
|
|
113
|
+
case 'invalid_token':
|
|
114
|
+
case 'token_expired':
|
|
115
|
+
setError(t('invalidOrExpiredLink'));
|
|
116
|
+
break;
|
|
117
|
+
case 'password_required':
|
|
118
|
+
setError(t('errorPasswordRequired'));
|
|
119
|
+
break;
|
|
120
|
+
default:
|
|
121
|
+
setError(err.message || t('errorUnexpected'));
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
setError(t('errorUnexpected'));
|
|
125
|
+
}
|
|
126
|
+
} finally {
|
|
127
|
+
setLoading(false);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (success) {
|
|
132
|
+
return (
|
|
133
|
+
<div>
|
|
134
|
+
<CardTitle>{t('passwordResetSuccess')}</CardTitle>
|
|
135
|
+
<Alert variant="success">{t('passwordResetSuccessMessage')}</Alert>
|
|
136
|
+
<CardFooter>
|
|
137
|
+
<Link to="/login" className="text-sm font-medium text-primary hover:underline no-underline">
|
|
138
|
+
{t('signIn')}
|
|
139
|
+
</Link>
|
|
140
|
+
</CardFooter>
|
|
141
|
+
</div>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!token) {
|
|
146
|
+
return (
|
|
147
|
+
<div>
|
|
148
|
+
<CardTitle>{t('invalidLink')}</CardTitle>
|
|
149
|
+
<Alert variant="error">{t('invalidOrExpiredLink')}</Alert>
|
|
150
|
+
<CardFooter>
|
|
151
|
+
<Link to="/forgot-password" className="text-sm font-medium text-primary hover:underline no-underline">
|
|
152
|
+
{t('requestNewResetLink')}
|
|
153
|
+
</Link>
|
|
154
|
+
</CardFooter>
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<div>
|
|
161
|
+
<CardTitle>{t('setNewPassword')}</CardTitle>
|
|
162
|
+
|
|
163
|
+
{error && <Alert variant="error">{error}</Alert>}
|
|
164
|
+
{validationError && <Alert variant="error">{validationError}</Alert>}
|
|
165
|
+
|
|
166
|
+
<form onSubmit={handleSubmit}>
|
|
167
|
+
<div className="mb-4">
|
|
168
|
+
<Label htmlFor="newPassword">{t('newPassword')}</Label>
|
|
169
|
+
<Input
|
|
170
|
+
id="newPassword"
|
|
171
|
+
type="password"
|
|
172
|
+
value={newPassword}
|
|
173
|
+
onChange={(e) => setNewPassword(e.target.value)}
|
|
174
|
+
placeholder={t('newPasswordPlaceholder')}
|
|
175
|
+
autoComplete="new-password"
|
|
176
|
+
autoFocus
|
|
177
|
+
maxLength={256}
|
|
178
|
+
required
|
|
179
|
+
/>
|
|
180
|
+
</div>
|
|
181
|
+
|
|
182
|
+
{newPassword.length > 0 && (
|
|
183
|
+
<ul className="list-none mb-4 p-3 bg-gray-50 dark:bg-gray-800/60 rounded-md">
|
|
184
|
+
{requirements.map((req) => (
|
|
185
|
+
<li key={req.label} className={`text-[13px] py-0.5 flex items-center gap-1.5 ${req.met ? 'text-green-800 dark:text-green-400' : 'text-red-800 dark:text-red-400'}`}>
|
|
186
|
+
{req.met ? <Check className="h-3.5 w-3.5 shrink-0" /> : <X className="h-3.5 w-3.5 shrink-0" />}
|
|
187
|
+
{req.label}
|
|
188
|
+
</li>
|
|
189
|
+
))}
|
|
190
|
+
</ul>
|
|
191
|
+
)}
|
|
192
|
+
|
|
193
|
+
<div className="mb-4">
|
|
194
|
+
<Label htmlFor="confirmPassword">{t('confirmPassword')}</Label>
|
|
195
|
+
<Input
|
|
196
|
+
id="confirmPassword"
|
|
197
|
+
type="password"
|
|
198
|
+
value={confirmPassword}
|
|
199
|
+
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
200
|
+
placeholder={t('confirmPasswordPlaceholder')}
|
|
201
|
+
autoComplete="new-password"
|
|
202
|
+
maxLength={256}
|
|
203
|
+
required
|
|
204
|
+
/>
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
<Button type="submit" loading={loading} disabled={!allRequirementsMet}>
|
|
208
|
+
{loading ? t('resetting') : t('resetPassword')}
|
|
209
|
+
</Button>
|
|
210
|
+
|
|
211
|
+
<CardFooter>
|
|
212
|
+
<Link to="/login" className="text-sm font-medium text-primary hover:underline no-underline">
|
|
213
|
+
{t('backToSignIn')}
|
|
214
|
+
</Link>
|
|
215
|
+
</CardFooter>
|
|
216
|
+
</form>
|
|
217
|
+
</div>
|
|
218
|
+
);
|
|
219
|
+
}
|
package/src/styles.css
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
@import 'tailwindcss';
|
|
2
|
+
|
|
3
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
4
|
+
|
|
5
|
+
@theme {
|
|
6
|
+
--color-primary: var(--brand-primary, #2563eb);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* Default auth surface vars. Tenants can override any of these via
|
|
11
|
+
* branding.customCssUrl. Light values are declared at :root; dark-mode
|
|
12
|
+
* overrides are scoped to .dark so tenant CSS still wins when provided.
|
|
13
|
+
*/
|
|
14
|
+
:root {
|
|
15
|
+
--brand-primary: #2563eb;
|
|
16
|
+
--auth-bg: #f3f4f6;
|
|
17
|
+
--auth-card-bg: #ffffff;
|
|
18
|
+
--auth-heading: #111827;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.dark {
|
|
22
|
+
color-scheme: dark;
|
|
23
|
+
--auth-bg: #030712;
|
|
24
|
+
--auth-card-bg: #111827;
|
|
25
|
+
--auth-heading: #f9fafb;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
body {
|
|
29
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
|
30
|
+
'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
|
|
31
|
+
-webkit-font-smoothing: antialiased;
|
|
32
|
+
-moz-osx-font-smoothing: grayscale;
|
|
33
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
export interface LoginResponse {
|
|
2
|
+
userId: string;
|
|
3
|
+
email: string;
|
|
4
|
+
name: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface ApiError {
|
|
8
|
+
error: string;
|
|
9
|
+
message?: string;
|
|
10
|
+
retryAfter?: number;
|
|
11
|
+
redirectUrl?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface SessionResponse {
|
|
15
|
+
authenticated: boolean;
|
|
16
|
+
userId: string;
|
|
17
|
+
email: string;
|
|
18
|
+
name: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface SsoCheckResponse {
|
|
22
|
+
ssoRequired: boolean;
|
|
23
|
+
providerType?: string;
|
|
24
|
+
connectionId?: string;
|
|
25
|
+
redirectUrl?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ExternalProvider {
|
|
29
|
+
connectionId: string;
|
|
30
|
+
name: string;
|
|
31
|
+
loginUrl: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ProvidersResponse {
|
|
35
|
+
providers: ExternalProvider[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface PasswordPolicyRule {
|
|
39
|
+
rule: string;
|
|
40
|
+
value: number | null;
|
|
41
|
+
label: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface PasswordPolicyResponse {
|
|
45
|
+
rules: PasswordPolicyRule[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// MFA types
|
|
49
|
+
export interface MfaLoginResponse {
|
|
50
|
+
mfaRequired?: boolean;
|
|
51
|
+
mfaSetupRequired?: boolean;
|
|
52
|
+
mfaAvailable?: boolean;
|
|
53
|
+
clientId?: string;
|
|
54
|
+
challengeId?: string;
|
|
55
|
+
setupToken?: string;
|
|
56
|
+
methods?: string[];
|
|
57
|
+
webAuthn?: PublicKeyCredentialRequestOptionsJSON;
|
|
58
|
+
userId?: string;
|
|
59
|
+
email?: string;
|
|
60
|
+
name?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// WebAuthn types (simplified from WebAuthn L2 spec)
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
|
+
export type PublicKeyCredentialRequestOptionsJSON = any;
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
67
|
+
export type PublicKeyCredentialCreationOptionsJSON = any;
|
|
68
|
+
|
|
69
|
+
export interface MfaVerifyResponse {
|
|
70
|
+
userId: string;
|
|
71
|
+
email: string;
|
|
72
|
+
name: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface MfaStatusResponse {
|
|
76
|
+
enabled: boolean;
|
|
77
|
+
methods: MfaMethod[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface MfaMethod {
|
|
81
|
+
id: string;
|
|
82
|
+
type: string;
|
|
83
|
+
name: string;
|
|
84
|
+
createdAt: string;
|
|
85
|
+
lastUsedAt: string | null;
|
|
86
|
+
isConsumed?: boolean | null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface MfaTotpSetupResponse {
|
|
90
|
+
setupToken: string;
|
|
91
|
+
qrCodeDataUri: string;
|
|
92
|
+
manualKey: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface MfaRecoveryGenerateResponse {
|
|
96
|
+
codes: string[];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface MfaWebAuthnSetupResponse {
|
|
100
|
+
setupToken: string;
|
|
101
|
+
options: PublicKeyCredentialCreationOptionsJSON;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface MfaWebAuthnConfirmResponse {
|
|
105
|
+
success: boolean;
|
|
106
|
+
credentialId: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface RegisterResponse {
|
|
110
|
+
success: boolean;
|
|
111
|
+
userId: string;
|
|
112
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
+
"target": "ES2023",
|
|
5
|
+
"useDefineForClassFields": true,
|
|
6
|
+
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"types": ["vite/client"],
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
|
|
11
|
+
/* Bundler mode */
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"moduleDetection": "force",
|
|
16
|
+
"declaration": true,
|
|
17
|
+
"emitDeclarationOnly": true,
|
|
18
|
+
"declarationDir": "./dist",
|
|
19
|
+
"noEmit": false,
|
|
20
|
+
"jsx": "react-jsx",
|
|
21
|
+
|
|
22
|
+
/* Linting */
|
|
23
|
+
"strict": true,
|
|
24
|
+
"noUnusedLocals": true,
|
|
25
|
+
"noUnusedParameters": true,
|
|
26
|
+
"erasableSyntaxOnly": true,
|
|
27
|
+
"noFallthroughCasesInSwitch": true,
|
|
28
|
+
"noUncheckedSideEffectImports": true,
|
|
29
|
+
|
|
30
|
+
/* Path aliases */
|
|
31
|
+
"baseUrl": ".",
|
|
32
|
+
"paths": {
|
|
33
|
+
"@/*": ["./src/*"]
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"include": ["src"]
|
|
37
|
+
}
|
package/tsconfig.json
ADDED
package/vite.config.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import react from '@vitejs/plugin-react'
|
|
3
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
4
|
+
import path from 'path'
|
|
5
|
+
import { fileURLToPath } from 'url'
|
|
6
|
+
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
8
|
+
|
|
9
|
+
// https://vite.dev/config/
|
|
10
|
+
export default defineConfig({
|
|
11
|
+
plugins: [react(), tailwindcss()],
|
|
12
|
+
resolve: {
|
|
13
|
+
alias: {
|
|
14
|
+
'@': path.resolve(__dirname, './src'),
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
build: {
|
|
18
|
+
lib: {
|
|
19
|
+
entry: path.resolve(__dirname, 'src/index.ts'),
|
|
20
|
+
formats: ['es'],
|
|
21
|
+
fileName: 'index',
|
|
22
|
+
},
|
|
23
|
+
rollupOptions: {
|
|
24
|
+
external: ['react', 'react-dom', 'react/jsx-runtime', 'react-router-dom'],
|
|
25
|
+
output: {
|
|
26
|
+
globals: {
|
|
27
|
+
react: 'React',
|
|
28
|
+
'react-dom': 'ReactDOM',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
cssCodeSplit: false,
|
|
33
|
+
},
|
|
34
|
+
server: {
|
|
35
|
+
proxy: {
|
|
36
|
+
'/api': {
|
|
37
|
+
target: 'http://localhost:5000',
|
|
38
|
+
changeOrigin: true,
|
|
39
|
+
},
|
|
40
|
+
'/saml': {
|
|
41
|
+
target: 'http://localhost:5000',
|
|
42
|
+
changeOrigin: true,
|
|
43
|
+
},
|
|
44
|
+
'/oidc': {
|
|
45
|
+
target: 'http://localhost:5000',
|
|
46
|
+
changeOrigin: true,
|
|
47
|
+
},
|
|
48
|
+
'/connect': {
|
|
49
|
+
target: 'http://localhost:5000',
|
|
50
|
+
changeOrigin: true,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
})
|