@micha.bigler/ui-core-micha 1.3.2 → 1.3.5

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.
@@ -373,30 +373,33 @@ export async function authenticateWithMFA({ code, credential }) {
373
373
  // Authentication: password (MODIFIZIERT)
374
374
  // -----------------------------
375
375
  export async function loginWithPassword(email, password) {
376
- var _a;
376
+ var _a, _b, _c;
377
377
  try {
378
378
  await axios.post(`${HEADLESS_BASE}/auth/login`, { email, password }, { withCredentials: true });
379
379
  }
380
380
  catch (error) {
381
- // SKEPTISCHER CHECK: Ist es der MFA-Flow?
382
- if (error.response &&
383
- error.response.status === 401 &&
384
- ((_a = error.response.data) === null || _a === void 0 ? void 0 : _a.flow) === 'mfa_authenticate') {
385
- // KEIN FEHLER! Wir geben zurück, dass MFA nötig ist.
381
+ const status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status;
382
+ const data = (_b = error.response) === null || _b === void 0 ? void 0 : _b.data;
383
+ console.log('Login Error Debug:', { status, data });
384
+ // --- SKEPTISCHER CHECK (KORRIGIERT) ---
385
+ // Wir suchen in der Liste 'flows' nach einem Eintrag mit id='mfa_authenticate'
386
+ // und prüfen, ob er 'is_pending' ist.
387
+ const mfaFlow = (_c = data === null || data === void 0 ? void 0 : data.flows) === null || _c === void 0 ? void 0 : _c.find(f => f.id === 'mfa_authenticate');
388
+ if (status === 401 && mfaFlow && mfaFlow.is_pending) {
386
389
  return {
387
390
  needsMfa: true,
388
- availableTypes: error.response.data.types || [], // z.B. ["webauthn", "totp"]
391
+ availableTypes: mfaFlow.types || [], // ["recovery_codes", "webauthn"]
389
392
  };
390
393
  }
391
- // Bestehende Logik für "Already logged in"
392
- if (error.response && error.response.status === 409) {
393
- // continue to fetch user
394
+ // --- Already Logged In ---
395
+ if (status === 409) {
396
+ // user ist schon eingeloggt
394
397
  }
395
398
  else {
396
399
  throw new Error(extractErrorMessage(error));
397
400
  }
398
401
  }
399
- // Wenn wir hier landen, war kein MFA nötig oder wir waren schon eingeloggt
402
+ // Erfolg ohne MFA
400
403
  const user = await fetchCurrentUser();
401
404
  return { user, needsMfa: false };
402
405
  }
@@ -76,7 +76,25 @@ export function LoginPage() {
76
76
  };
77
77
  // ... (Social & Sign Up Handler bleiben gleich) ...
78
78
  const handleSocialLogin = (provider) => authApi.startSocialLogin(provider);
79
- const handlePasskeyLoginInitial = async () => { };
79
+ const handlePasskeyLoginInitial = async () => {
80
+ var _a, _b;
81
+ setError('');
82
+ setSubmitting(true);
83
+ try {
84
+ // Wir rufen die existierende Passkey-Login Funktion auf
85
+ const { user } = await authApi.loginWithPasskey();
86
+ login(user);
87
+ navigate('/');
88
+ }
89
+ catch (err) {
90
+ setError(((_b = (_a = err === null || err === void 0 ? void 0 : err.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.detail) ||
91
+ (err === null || err === void 0 ? void 0 : err.message) ||
92
+ 'Passkey login failed.');
93
+ }
94
+ finally {
95
+ setSubmitting(false);
96
+ }
97
+ };
80
98
  const handleSignUp = () => navigate('/signup');
81
99
  const handleForgotPassword = () => navigate('/reset-request-password');
82
100
  return (_jsxs(NarrowPage, { title: "Login", children: [_jsx(Helmet, { children: _jsx("title", { children: "Login" }) }), error && _jsx(Alert, { severity: "error", sx: { mb: 2 }, children: error }), step === 'credentials' && (_jsx(LoginForm, { onSubmit: handleSubmitCredentials, onForgotPassword: handleForgotPassword, onSocialLogin: handleSocialLogin, onPasskeyLogin: handlePasskeyLoginInitial, onSignUp: handleSignUp, disabled: submitting })), step === 'mfa' && (_jsxs(Box, { children: [_jsx(Typography, { variant: "body1", gutterBottom: true, children: "Two-Factor Authentication required." }), _jsxs(Stack, { spacing: 2, sx: { mt: 2 }, children: [mfaTypes.includes('webauthn') && (_jsx(Button, { variant: "outlined", onClick: handleMfaPasskey, fullWidth: true, children: "Use Passkey / Security Key" })), (mfaTypes.includes('totp') || mfaTypes.includes('recovery_codes')) && (_jsxs("form", { onSubmit: handleMfaTotpSubmit, children: [_jsx(TextField, { label: "Authenticator Code (or Recovery Code)", value: totpCode, onChange: (e) => setTotpCode(e.target.value), fullWidth: true, autoFocus: true, disabled: submitting, sx: { mb: 2 } }), _jsx(Button, { type: "submit", variant: "contained", fullWidth: true, disabled: submitting, children: "Verify" })] })), _jsx(Button, { size: "small", onClick: () => setStep('credentials'), children: "Back to Login" })] })] }))] }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@micha.bigler/ui-core-micha",
3
- "version": "1.3.2",
3
+ "version": "1.3.5",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "private": false,
@@ -489,31 +489,35 @@ export async function loginWithPassword(email, password) {
489
489
  await axios.post(
490
490
  `${HEADLESS_BASE}/auth/login`,
491
491
  { email, password },
492
- { withCredentials: true }
492
+ { withCredentials: true },
493
493
  );
494
494
  } catch (error) {
495
- // SKEPTISCHER CHECK: Ist es der MFA-Flow?
496
- if (
497
- error.response &&
498
- error.response.status === 401 &&
499
- error.response.data?.flow === 'mfa_authenticate'
500
- ) {
501
- // KEIN FEHLER! Wir geben zurück, dass MFA nötig ist.
495
+ const status = error.response?.status;
496
+ const data = error.response?.data;
497
+
498
+ console.log('Login Error Debug:', { status, data });
499
+
500
+ // --- SKEPTISCHER CHECK (KORRIGIERT) ---
501
+ // Wir suchen in der Liste 'flows' nach einem Eintrag mit id='mfa_authenticate'
502
+ // und prüfen, ob er 'is_pending' ist.
503
+ const mfaFlow = data?.flows?.find(f => f.id === 'mfa_authenticate');
504
+
505
+ if (status === 401 && mfaFlow && mfaFlow.is_pending) {
502
506
  return {
503
507
  needsMfa: true,
504
- availableTypes: error.response.data.types || [], // z.B. ["webauthn", "totp"]
508
+ availableTypes: mfaFlow.types || [], // ["recovery_codes", "webauthn"]
505
509
  };
506
510
  }
507
-
508
- // Bestehende Logik für "Already logged in"
509
- if (error.response && error.response.status === 409) {
510
- // continue to fetch user
511
+
512
+ // --- Already Logged In ---
513
+ if (status === 409) {
514
+ // user ist schon eingeloggt
511
515
  } else {
512
- throw new Error(extractErrorMessage(error));
516
+ throw new Error(extractErrorMessage(error));
513
517
  }
514
518
  }
515
519
 
516
- // Wenn wir hier landen, war kein MFA nötig oder wir waren schon eingeloggt
520
+ // Erfolg ohne MFA
517
521
  const user = await fetchCurrentUser();
518
522
  return { user, needsMfa: false };
519
523
  }
@@ -77,7 +77,24 @@ export function LoginPage() {
77
77
 
78
78
  // ... (Social & Sign Up Handler bleiben gleich) ...
79
79
  const handleSocialLogin = (provider) => authApi.startSocialLogin(provider);
80
- const handlePasskeyLoginInitial = async () => { /* wie gehabt für Step 1 */ };
80
+ const handlePasskeyLoginInitial = async () => {
81
+ setError('');
82
+ setSubmitting(true);
83
+ try {
84
+ // Wir rufen die existierende Passkey-Login Funktion auf
85
+ const { user } = await authApi.loginWithPasskey();
86
+ login(user);
87
+ navigate('/');
88
+ } catch (err) {
89
+ setError(
90
+ err?.response?.data?.detail ||
91
+ err?.message ||
92
+ 'Passkey login failed.',
93
+ );
94
+ } finally {
95
+ setSubmitting(false);
96
+ }
97
+ };
81
98
  const handleSignUp = () => navigate('/signup');
82
99
  const handleForgotPassword = () => navigate('/reset-request-password');
83
100