@micha.bigler/ui-core-micha 1.4.14 → 1.4.16

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.
@@ -1,12 +1,8 @@
1
- import axios from 'axios';
1
+ import apiClient from './apiClient';
2
2
  import { HEADLESS_BASE, USERS_BASE, ACCESS_CODES_BASE } from './authConfig';
3
3
  // -----------------------------
4
4
  // WebAuthn Serialization Helpers
5
5
  // -----------------------------
6
- /**
7
- * Converts an ArrayBuffer to a Base64URL encoded string.
8
- * Required for manual credential serialization when .toJSON() is missing.
9
- */
10
6
  function bufferToBase64URL(buffer) {
11
7
  const bytes = new Uint8Array(buffer);
12
8
  let str = '';
@@ -16,15 +12,10 @@ function bufferToBase64URL(buffer) {
16
12
  const base64 = btoa(str);
17
13
  return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
18
14
  }
19
- /**
20
- * Serializes a PublicKeyCredential into a JSON-compatible object.
21
- * Acts as a polyfill for environments where credential.toJSON() is missing (e.g., Proton Pass).
22
- */
23
15
  function serializeCredential(credential) {
24
16
  if (typeof credential.toJSON === 'function') {
25
17
  return credential.toJSON();
26
18
  }
27
- // Manual serialization for extensions that return incomplete objects
28
19
  const p = {
29
20
  id: credential.id,
30
21
  rawId: bufferToBase64URL(credential.rawId),
@@ -34,22 +25,17 @@ function serializeCredential(credential) {
34
25
  },
35
26
  };
36
27
  if (credential.response.attestationObject) {
37
- // Registration specific
38
28
  p.response.attestationObject = bufferToBase64URL(credential.response.attestationObject);
39
29
  }
40
30
  if (credential.response.authenticatorData) {
41
- // Login specific
42
31
  p.response.authenticatorData = bufferToBase64URL(credential.response.authenticatorData);
43
32
  }
44
33
  if (credential.response.signature) {
45
- // Login specific
46
34
  p.response.signature = bufferToBase64URL(credential.response.signature);
47
35
  }
48
36
  if (credential.response.userHandle) {
49
- // Login specific
50
37
  p.response.userHandle = bufferToBase64URL(credential.response.userHandle);
51
38
  }
52
- // Include clientExtensionResults if present
53
39
  if (typeof credential.getClientExtensionResults === 'function') {
54
40
  p.clientExtensionResults = credential.getClientExtensionResults();
55
41
  }
@@ -68,10 +54,6 @@ function normaliseApiError(error, defaultCode = 'Auth.GENERIC_ERROR') {
68
54
  function mapAllauthDetailToCode(detail) {
69
55
  if (!detail || typeof detail !== 'string')
70
56
  return null;
71
- // Optional: bekannte allauth-Texte auf eigene Codes mappen
72
- // if (detail.includes('Unable to log in with provided credentials')) {
73
- // return 'Auth.INVALID_CREDENTIALS';
74
- // }
75
57
  return null;
76
58
  }
77
59
  function extractErrorInfo(error) {
@@ -79,47 +61,21 @@ function extractErrorInfo(error) {
79
61
  const status = (_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status) !== null && _b !== void 0 ? _b : null;
80
62
  const data = (_d = (_c = error.response) === null || _c === void 0 ? void 0 : _c.data) !== null && _d !== void 0 ? _d : null;
81
63
  if (!data) {
82
- return {
83
- status,
84
- code: null,
85
- message: error.message || null,
86
- raw: null,
87
- };
64
+ return { status, code: null, message: error.message || null, raw: null };
88
65
  }
89
66
  if (typeof data.code === 'string') {
90
- return {
91
- status,
92
- code: data.code,
93
- message: null,
94
- raw: data,
95
- };
67
+ return { status, code: data.code, message: null, raw: data };
96
68
  }
97
69
  if (typeof data.detail === 'string') {
98
70
  const mapped = mapAllauthDetailToCode(data.detail);
99
- return {
100
- status,
101
- code: mapped,
102
- message: data.detail,
103
- raw: data,
104
- };
71
+ return { status, code: mapped, message: data.detail, raw: data };
105
72
  }
106
- if (Array.isArray(data.non_field_errors) &&
107
- data.non_field_errors.length > 0) {
73
+ if (Array.isArray(data.non_field_errors) && data.non_field_errors.length > 0) {
108
74
  const msg = data.non_field_errors[0];
109
75
  const mapped = mapAllauthDetailToCode(msg);
110
- return {
111
- status,
112
- code: mapped,
113
- message: msg,
114
- raw: data,
115
- };
76
+ return { status, code: mapped, message: msg, raw: data };
116
77
  }
117
- return {
118
- status,
119
- code: null,
120
- message: null,
121
- raw: data,
122
- };
78
+ return { status, code: null, message: null, raw: data };
123
79
  }
124
80
  // -----------------------------
125
81
  // CSRF helper
@@ -128,7 +84,8 @@ function getCsrfToken() {
128
84
  if (typeof document === 'undefined' || !document.cookie) {
129
85
  return null;
130
86
  }
131
- const match = document.cookie.match(/csrftoken=([^;]+)/);
87
+ // Robust regex for CSRF token
88
+ const match = document.cookie.match(/(?:^|; )csrftoken=([^;]+)/);
132
89
  return match ? match[1] : null;
133
90
  }
134
91
  // -----------------------------
@@ -150,16 +107,13 @@ function ensureWebAuthnSupport() {
150
107
  // User-related helpers
151
108
  // -----------------------------
152
109
  export async function fetchCurrentUser() {
153
- const res = await axios.get(`${USERS_BASE}/current/`, {
154
- withCredentials: true,
155
- });
110
+ const res = await apiClient.get(`${USERS_BASE}/current/`);
156
111
  return res.data;
157
112
  }
158
113
  export async function updateUserProfile(data) {
159
114
  try {
160
- const res = await axios.patch(`${USERS_BASE}/current/`, data, {
161
- withCredentials: true,
162
- });
115
+ // CHANGED: axios -> apiClient
116
+ const res = await apiClient.patch(`${USERS_BASE}/current/`, data);
163
117
  return res.data;
164
118
  }
165
119
  catch (error) {
@@ -169,38 +123,17 @@ export async function updateUserProfile(data) {
169
123
  // -----------------------------
170
124
  // Authentication: password
171
125
  // -----------------------------
172
- /*
173
- export async function loginWithPassword(email, password) {
174
- try {
175
- await axios.post(
176
- `${HEADLESS_BASE}/auth/login`,
177
- { email, password },
178
- { withCredentials: true },
179
- );
180
- } catch (error) {
181
- if (error.response && error.response.status === 409) {
182
- // Already logged in: continue and fetch current user
183
- } else {
184
- throw new Error(extractErrorMessage(error));
185
- }
186
- }
187
-
188
- const user = await fetchCurrentUser();
189
- return { user };
190
- }
191
- */
192
126
  export async function requestPasswordReset(email) {
193
127
  try {
194
- await axios.post(`${USERS_BASE}/reset-request/`, { email }, { withCredentials: true });
128
+ await apiClient.post(`${USERS_BASE}/reset-request/`, { email });
195
129
  }
196
130
  catch (error) {
197
131
  throw normaliseApiError(error, 'Auth.RESET_REQUEST_FAILED');
198
132
  }
199
133
  }
200
- // (Falls du es noch brauchst: klassischer allauth-Key-Flow)
201
134
  export async function resetPasswordWithKey(key, newPassword) {
202
135
  try {
203
- await axios.post(`${HEADLESS_BASE}/auth/password/reset/key`, { key, password: newPassword }, { withCredentials: true });
136
+ await apiClient.post(`${HEADLESS_BASE}/auth/password/reset/key`, { key, password: newPassword });
204
137
  }
205
138
  catch (error) {
206
139
  throw normaliseApiError(error, 'Auth.RESET_WITH_KEY_FAILED');
@@ -208,10 +141,10 @@ export async function resetPasswordWithKey(key, newPassword) {
208
141
  }
209
142
  export async function changePassword(currentPassword, newPassword) {
210
143
  try {
211
- await axios.post(`${HEADLESS_BASE}/account/password/change`, {
144
+ await apiClient.post(`${HEADLESS_BASE}/account/password/change`, {
212
145
  current_password: currentPassword,
213
146
  new_password: newPassword,
214
- }, { withCredentials: true });
147
+ });
215
148
  }
216
149
  catch (error) {
217
150
  throw normaliseApiError(error, 'Auth.PASSWORD_CHANGE_FAILED');
@@ -227,14 +160,11 @@ export async function logoutSession() {
227
160
  if (csrfToken) {
228
161
  headers['X-CSRFToken'] = csrfToken;
229
162
  }
230
- await axios.delete(`${HEADLESS_BASE}/auth/session`, {
231
- withCredentials: true,
232
- headers,
233
- });
163
+ // CHANGED: axios -> apiClient
164
+ await apiClient.delete(`${HEADLESS_BASE}/auth/session`, { headers });
234
165
  }
235
166
  catch (error) {
236
167
  if (error.response && [401, 404, 410].includes(error.response.status)) {
237
- // Session already gone, nothing to do
238
168
  return;
239
169
  }
240
170
  // eslint-disable-next-line no-console
@@ -242,9 +172,7 @@ export async function logoutSession() {
242
172
  }
243
173
  }
244
174
  export async function fetchHeadlessSession() {
245
- const res = await axios.get(`${HEADLESS_BASE}/auth/session`, {
246
- withCredentials: true,
247
- });
175
+ const res = await apiClient.get(`${HEADLESS_BASE}/auth/session`);
248
176
  return res.data;
249
177
  }
250
178
  // -----------------------------
@@ -254,7 +182,6 @@ export function startSocialLogin(provider) {
254
182
  if (typeof window === 'undefined') {
255
183
  throw normaliseApiError(new Error('Auth.SOCIAL_LOGIN_NOT_IN_BROWSER'), 'Auth.SOCIAL_LOGIN_NOT_IN_BROWSER');
256
184
  }
257
- // Classic allauth HTML flow
258
185
  window.location.href = `/accounts/${provider}/login/?process=login`;
259
186
  }
260
187
  // -----------------------------
@@ -262,11 +189,10 @@ export function startSocialLogin(provider) {
262
189
  // -----------------------------
263
190
  export async function validateAccessCode(code) {
264
191
  try {
265
- const res = await axios.post(`${ACCESS_CODES_BASE}/validate/`, { code }, { withCredentials: true });
192
+ const res = await apiClient.post(`${ACCESS_CODES_BASE}/validate/`, { code });
266
193
  return res.data;
267
194
  }
268
195
  catch (error) {
269
- // Default für "irgendwas ist mit dem Code schief"
270
196
  throw normaliseApiError(error, 'Auth.ACCESS_CODE_INVALID_OR_INACTIVE');
271
197
  }
272
198
  }
@@ -276,11 +202,10 @@ export async function requestInviteWithCode(email, accessCode) {
276
202
  payload.access_code = accessCode;
277
203
  }
278
204
  try {
279
- const res = await axios.post(`${USERS_BASE}/invite/`, payload, { withCredentials: true });
205
+ const res = await apiClient.post(`${USERS_BASE}/invite/`, payload);
280
206
  return res.data;
281
207
  }
282
208
  catch (error) {
283
- // z.B. bei Netzwerkfehlern oder wenn Backend ausnahmsweise keinen code liefert
284
209
  throw normaliseApiError(error, 'Auth.INVITE_FAILED');
285
210
  }
286
211
  }
@@ -289,17 +214,16 @@ export async function requestInviteWithCode(email, accessCode) {
289
214
  // -----------------------------
290
215
  export async function verifyResetToken(uid, token) {
291
216
  try {
292
- const res = await axios.get(`${USERS_BASE}/password-reset/${uid}/${token}/`, { withCredentials: true });
217
+ const res = await apiClient.get(`${USERS_BASE}/password-reset/${uid}/${token}/`);
293
218
  return res.data;
294
219
  }
295
220
  catch (error) {
296
- // Wenn der Link nicht passt oder Netzwerkfehler: generisch als "Link invalid"
297
221
  throw normaliseApiError(error, 'Auth.RESET_LINK_INVALID');
298
222
  }
299
223
  }
300
224
  export async function setNewPassword(uid, token, newPassword) {
301
225
  try {
302
- const res = await axios.post(`${USERS_BASE}/password-reset/${uid}/${token}/`, { new_password: newPassword }, { withCredentials: true });
226
+ const res = await apiClient.post(`${USERS_BASE}/password-reset/${uid}/${token}/`, { new_password: newPassword });
303
227
  return res.data;
304
228
  }
305
229
  catch (error) {
@@ -307,28 +231,22 @@ export async function setNewPassword(uid, token, newPassword) {
307
231
  }
308
232
  }
309
233
  // -----------------------------
310
- // WebAuthn / Passkeys: register
234
+ // WebAuthn / Passkeys
311
235
  // -----------------------------
312
236
  async function registerPasskeyStart({ passwordless = true } = {}) {
313
237
  ensureWebAuthnSupport();
314
- const res = await axios.get(`${HEADLESS_BASE}/account/authenticators/webauthn`, {
238
+ const res = await apiClient.get(`${HEADLESS_BASE}/account/authenticators/webauthn`, {
315
239
  params: passwordless ? { passwordless: true } : {},
316
- withCredentials: true,
317
240
  });
318
241
  const responseBody = res.data || {};
319
- // Handle nested 'data' wrapper if present, otherwise use body directly
320
242
  const payload = responseBody.data || responseBody;
321
- // Extract the inner publicKey structure required by the browser API
322
243
  const publicKeyJson = (payload.creation_options && payload.creation_options.publicKey) ||
323
244
  payload.publicKey ||
324
245
  payload;
325
246
  return publicKeyJson;
326
247
  }
327
248
  async function registerPasskeyComplete(credentialJson, name = 'Passkey') {
328
- const res = await axios.post(`${HEADLESS_BASE}/account/authenticators/webauthn`, {
329
- credential: credentialJson,
330
- name,
331
- }, { withCredentials: true });
249
+ const res = await apiClient.post(`${HEADLESS_BASE}/account/authenticators/webauthn`, { credential: credentialJson, name });
332
250
  return res.data;
333
251
  }
334
252
  export async function registerPasskey(name = 'Passkey') {
@@ -336,17 +254,13 @@ export async function registerPasskey(name = 'Passkey') {
336
254
  if (!hasJsonWebAuthn) {
337
255
  throw normaliseApiError(new Error('Auth.PASSKEY_JSON_HELPERS_UNAVAILABLE'), 'Auth.PASSKEY_JSON_HELPERS_UNAVAILABLE');
338
256
  }
339
- // ... (previous logic for registerPasskeyStart) ...
340
257
  const publicKeyJson = await registerPasskeyStart({ passwordless: true });
341
258
  let credential;
342
259
  try {
343
260
  const publicKeyOptions = window.PublicKeyCredential.parseCreationOptionsFromJSON(publicKeyJson);
344
- credential = await navigator.credentials.create({
345
- publicKey: publicKeyOptions,
346
- });
261
+ credential = await navigator.credentials.create({ publicKey: publicKeyOptions });
347
262
  }
348
263
  catch (err) {
349
- // ... (error handling) ...
350
264
  if (err && err.name === 'NotAllowedError') {
351
265
  throw normaliseApiError(err, 'Auth.PASSKEY_CREATION_CANCELLED');
352
266
  }
@@ -355,27 +269,21 @@ export async function registerPasskey(name = 'Passkey') {
355
269
  if (!credential) {
356
270
  throw normaliseApiError(new Error('Auth.PASSKEY_CREATION_CANCELLED'), 'Auth.PASSKEY_CREATION_CANCELLED');
357
271
  }
358
- // CHANGED: Use helper instead of direct .toJSON()
359
272
  const credentialJson = serializeCredential(credential);
360
273
  return registerPasskeyComplete(credentialJson, name);
361
274
  }
362
- // -----------------------------
363
- // WebAuthn / Passkeys: login
364
- // -----------------------------
365
275
  async function loginWithPasskeyStart() {
366
276
  ensureWebAuthnSupport();
367
- const res = await axios.get(`${HEADLESS_BASE}/auth/webauthn/login`, { withCredentials: true });
277
+ const res = await apiClient.get(`${HEADLESS_BASE}/auth/webauthn/login`);
368
278
  const responseBody = res.data || {};
369
- // Handle nested 'data' wrapper if present
370
279
  const payload = responseBody.data || responseBody;
371
- // Extract request options for authentication
372
280
  const requestOptionsJson = (payload.request_options && payload.request_options.publicKey) ||
373
281
  payload.request_options ||
374
282
  payload;
375
283
  return requestOptionsJson;
376
284
  }
377
285
  async function loginWithPasskeyComplete(credentialJson) {
378
- const res = await axios.post(`${HEADLESS_BASE}/auth/webauthn/login`, { credential: credentialJson }, { withCredentials: true });
286
+ const res = await apiClient.post(`${HEADLESS_BASE}/auth/webauthn/login`, { credential: credentialJson });
379
287
  return res.data;
380
288
  }
381
289
  export async function loginWithPasskey() {
@@ -390,7 +298,6 @@ export async function loginWithPasskey() {
390
298
  assertion = await navigator.credentials.get({ publicKey: publicKeyOptions });
391
299
  }
392
300
  catch (err) {
393
- // Browser-interner Abbruch (z.B. Dialog weggeklickt)
394
301
  const e = new Error('Auth.PASSKEY_AUTH_CANCELLED');
395
302
  e.code = 'Auth.PASSKEY_AUTH_CANCELLED';
396
303
  throw e;
@@ -413,15 +320,14 @@ export async function loginWithPasskey() {
413
320
  return { user };
414
321
  }
415
322
  catch (err) {
416
- if (postError) {
323
+ if (postError)
417
324
  throw normaliseApiError(postError, 'Auth.PASSKEY_FAILED');
418
- }
419
325
  throw normaliseApiError(err, 'Auth.PASSKEY_FAILED');
420
326
  }
421
327
  }
422
328
  export async function fetchPasskeys() {
423
329
  try {
424
- const res = await axios.get(`${USERS_BASE}/passkeys/`, { withCredentials: true });
330
+ const res = await apiClient.get(`${USERS_BASE}/passkeys/`);
425
331
  return Array.isArray(res.data) ? res.data : [];
426
332
  }
427
333
  catch (error) {
@@ -430,7 +336,8 @@ export async function fetchPasskeys() {
430
336
  }
431
337
  export async function deletePasskey(id) {
432
338
  try {
433
- await axios.delete(`${USERS_BASE}/passkeys/${id}/`, { withCredentials: true });
339
+ // CHANGED: axios -> apiClient
340
+ await apiClient.delete(`${USERS_BASE}/passkeys/${id}/`);
434
341
  }
435
342
  catch (error) {
436
343
  throw normaliseApiError(error, 'Auth.PASSKEY_DELETE_FAILED');
@@ -446,7 +353,7 @@ export async function authenticateWithMFA({ code, credential }) {
446
353
  if (credential)
447
354
  payload.credential = credential;
448
355
  try {
449
- const res = await axios.post(`${HEADLESS_BASE}/auth/2fa/authenticate`, payload, { withCredentials: true });
356
+ const res = await apiClient.post(`${HEADLESS_BASE}/auth/2fa/authenticate`, payload);
450
357
  return res.data;
451
358
  }
452
359
  catch (error) {
@@ -454,17 +361,16 @@ export async function authenticateWithMFA({ code, credential }) {
454
361
  }
455
362
  }
456
363
  // -----------------------------
457
- // Authentication: password (MODIFIZIERT)
364
+ // Authentication: password
458
365
  // -----------------------------
459
366
  export async function loginWithPassword(email, password) {
460
367
  var _a, _b, _c;
461
368
  try {
462
- await axios.post(`${HEADLESS_BASE}/auth/login`, { email, password }, { withCredentials: true });
369
+ await apiClient.post(`${HEADLESS_BASE}/auth/login`, { email, password });
463
370
  }
464
371
  catch (error) {
465
372
  const status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status;
466
373
  const body = (_b = error.response) === null || _b === void 0 ? void 0 : _b.data;
467
- // Flows können in body.data.flows oder body.flows liegen
468
374
  const flows = ((_c = body === null || body === void 0 ? void 0 : body.data) === null || _c === void 0 ? void 0 : _c.flows) || (body === null || body === void 0 ? void 0 : body.flows) || [];
469
375
  const mfaFlow = Array.isArray(flows)
470
376
  ? flows.find((f) => f.id === 'mfa_authenticate')
@@ -472,45 +378,42 @@ export async function loginWithPassword(email, password) {
472
378
  if (status === 401 && mfaFlow && mfaFlow.is_pending) {
473
379
  return {
474
380
  needsMfa: true,
475
- availableTypes: mfaFlow.types || [], // ["recovery_codes", "totp", "webauthn"]
381
+ availableTypes: mfaFlow.types || [],
476
382
  };
477
383
  }
478
384
  if (status === 409) {
479
- // Already logged in – einfach weitermachen
385
+ // Already logged in
480
386
  }
481
387
  else {
482
388
  throw normaliseApiError(error, 'Auth.LOGIN_FAILED');
483
389
  }
484
390
  }
485
- // Erfolg ohne MFA
486
391
  const user = await fetchCurrentUser();
487
392
  return { user, needsMfa: false };
488
393
  }
489
- // 1. Status prüfen (Liste der aktiven Authenticators)
394
+ // -----------------------------
395
+ // Authenticators & MFA
396
+ // -----------------------------
490
397
  export async function fetchAuthenticators() {
491
- const res = await axios.get(`${HEADLESS_BASE}/account/authenticators`, { withCredentials: true });
398
+ const res = await apiClient.get(`${HEADLESS_BASE}/account/authenticators`);
492
399
  const body = res.data || {};
493
- // Headless gibt i.d.R. { status, data: [...] } zurück
494
400
  const items = Array.isArray(body.data) ? body.data : (Array.isArray(body) ? body : []);
495
401
  return items;
496
402
  }
497
- // 2. TOTP Einrichtung starten (liefert Secret & QR-URL)
498
403
  export async function requestTotpKey() {
499
404
  var _a;
500
405
  try {
501
- const res = await axios.get(`${HEADLESS_BASE}/account/authenticators/totp`, { withCredentials: true });
502
- // Fall: TOTP existiert bereits -> 200
406
+ const res = await apiClient.get(`${HEADLESS_BASE}/account/authenticators/totp`);
503
407
  const body = res.data || {};
504
408
  const data = body.data || body;
505
409
  return {
506
410
  exists: true,
507
- authenticator: data, // z.B. { id, type, created_at, ... }
411
+ authenticator: data,
508
412
  };
509
413
  }
510
414
  catch (error) {
511
415
  const { response } = error;
512
416
  if ((response === null || response === void 0 ? void 0 : response.status) === 404) {
513
- // Spezialfall von allauth: noch kein TOTP eingerichtet
514
417
  const meta = ((_a = response.data) === null || _a === void 0 ? void 0 : _a.meta) || {};
515
418
  return {
516
419
  exists: false,
@@ -523,7 +426,7 @@ export async function requestTotpKey() {
523
426
  }
524
427
  export async function activateTotp(code) {
525
428
  try {
526
- const res = await axios.post(`${HEADLESS_BASE}/account/authenticators/totp`, { code }, { withCredentials: true });
429
+ const res = await apiClient.post(`${HEADLESS_BASE}/account/authenticators/totp`, { code });
527
430
  return res.data;
528
431
  }
529
432
  catch (error) {
@@ -532,30 +435,26 @@ export async function activateTotp(code) {
532
435
  }
533
436
  export async function deactivateTotp() {
534
437
  try {
535
- const res = await axios.delete(`${HEADLESS_BASE}/account/authenticators/totp`, { withCredentials: true });
438
+ // CHANGED: axios -> apiClient
439
+ const res = await apiClient.delete(`${HEADLESS_BASE}/account/authenticators/totp`);
536
440
  return res.data;
537
441
  }
538
442
  catch (error) {
539
443
  throw normaliseApiError(error, 'Auth.TOTP_DEACTIVATE_FAILED');
540
444
  }
541
445
  }
542
- // -----------------------------
543
- // MFA: Recovery Codes
544
- // -----------------------------
545
446
  export async function fetchRecoveryCodes() {
546
447
  var _a;
547
448
  try {
548
- const res = await axios.get(`${HEADLESS_BASE}/account/authenticators/recovery-codes`, { withCredentials: true });
449
+ const res = await apiClient.get(`${HEADLESS_BASE}/account/authenticators/recovery-codes`);
549
450
  const body = res.data || {};
550
- // Inneres "data" herausziehen, sonst direkt body verwenden
551
451
  const data = body.data || body;
552
- return data; // { type, unused_codes, ... }
452
+ return data;
553
453
  }
554
454
  catch (error) {
555
455
  const status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status;
556
456
  if (status === 404) {
557
- // Noch keine Codes -> automatisch generieren
558
- const resPost = await axios.post(`${HEADLESS_BASE}/account/authenticators/recovery-codes`, {}, { withCredentials: true });
457
+ const resPost = await apiClient.post(`${HEADLESS_BASE}/account/authenticators/recovery-codes`, {});
559
458
  const body = resPost.data || {};
560
459
  const data = body.data || body;
561
460
  return data;
@@ -565,7 +464,7 @@ export async function fetchRecoveryCodes() {
565
464
  }
566
465
  export async function generateRecoveryCodes() {
567
466
  try {
568
- const res = await axios.post(`${HEADLESS_BASE}/account/authenticators/recovery-codes`, {}, { withCredentials: true });
467
+ const res = await apiClient.post(`${HEADLESS_BASE}/account/authenticators/recovery-codes`, {});
569
468
  const body = res.data || {};
570
469
  const data = body.data || body;
571
470
  return data;
@@ -576,14 +475,13 @@ export async function generateRecoveryCodes() {
576
475
  }
577
476
  export async function fetchOrGenerateRecoveryCodes() {
578
477
  try {
579
- const res = await axios.get(`${HEADLESS_BASE}/mfa/recovery_codes`, { withCredentials: true });
478
+ const res = await apiClient.get(`${HEADLESS_BASE}/mfa/recovery_codes`);
580
479
  return res.data;
581
480
  }
582
481
  catch (error) {
583
482
  const { response } = error;
584
483
  if ((response === null || response === void 0 ? void 0 : response.status) === 404) {
585
- // Noch keine Codes -> jetzt generieren
586
- const resPost = await axios.post(`${HEADLESS_BASE}/mfa/recovery_codes`, {}, { withCredentials: true });
484
+ const resPost = await apiClient.post(`${HEADLESS_BASE}/mfa/recovery_codes`, {});
587
485
  return resPost.data;
588
486
  }
589
487
  throw normaliseApiError(error, 'Auth.RECOVERY_CODES_FETCH_FAILED');
@@ -592,34 +490,29 @@ export async function fetchOrGenerateRecoveryCodes() {
592
490
  export function isStrongSession(session) {
593
491
  const methods = (session === null || session === void 0 ? void 0 : session.methods) || [];
594
492
  const used = methods.map((m) => m.method);
595
- // alles, was klar 2FA / starker Faktor ist:
596
493
  const strongMethods = ['totp', 'recovery_codes', 'webauthn'];
597
494
  return used.some((m) => strongMethods.includes(m));
598
495
  }
599
496
  export async function requestMfaSupportHelp(emailOrIdentifier, message = '') {
600
- // Wir nutzen hier die Users-API, nicht HEADLESS_BASE
601
497
  const payload = { email: emailOrIdentifier, message };
602
- const res = await axios.post(`${USERS_BASE}/mfa/support-help/`, payload, { withCredentials: true });
498
+ const res = await apiClient.post(`${USERS_BASE}/mfa/support-help/`, payload);
603
499
  return res.data;
604
500
  }
605
501
  export async function fetchRecoveryRequests(status = 'pending') {
606
- const res = await axios.get('/api/support/recovery-requests/', {
607
- params: { status },
608
- withCredentials: true,
609
- });
502
+ const res = await apiClient.get('/api/support/recovery-requests/', { params: { status } });
610
503
  return res.data;
611
504
  }
612
505
  export async function approveRecoveryRequest(id, supportNote) {
613
- const res = await axios.post(`/api/support/recovery-requests/${id}/approve/`, { support_note: supportNote || '' }, { withCredentials: true });
506
+ const res = await apiClient.post(`/api/support/recovery-requests/${id}/approve/`, { support_note: supportNote || '' });
614
507
  return res.data;
615
508
  }
616
509
  export async function rejectRecoveryRequest(id, supportNote) {
617
- const res = await axios.post(`/api/support/recovery-requests/${id}/reject/`, { support_note: supportNote || '' }, { withCredentials: true });
510
+ const res = await apiClient.post(`/api/support/recovery-requests/${id}/reject/`, { support_note: supportNote || '' });
618
511
  return res.data;
619
512
  }
620
513
  export async function loginWithRecoveryPassword(email, password, token) {
621
514
  try {
622
- await axios.post(`/api/support/recovery-requests/recovery-login/${token}/`, { email, password }, { withCredentials: true });
515
+ await apiClient.post(`/api/support/recovery-requests/recovery-login/${token}/`, { email, password });
623
516
  }
624
517
  catch (error) {
625
518
  throw normaliseApiError(error, 'Auth.RECOVERY_LOGIN_FAILED');
@@ -1,9 +1,10 @@
1
+ //src/auth/webauthnclient.jsx
1
2
  export async function registerPasskeyStart() {
2
- const res = await axios.post(`${HEADLESS_BASE}/mfa/webauthn/register/start`, {}, { withCredentials: true });
3
+ const res = await apiClient.post(`${HEADLESS_BASE}/mfa/webauthn/register/start`, {}, { withCredentials: true });
3
4
  return res.data; // enthält challenge, rpId etc.
4
5
  }
5
6
  export async function registerPasskeyComplete(publicKeyCredential) {
6
7
  const payload = serializePublicKeyCredential(publicKeyCredential);
7
- const res = await axios.post(`${HEADLESS_BASE}/mfa/webauthn/register/complete`, payload, { withCredentials: true });
8
+ const res = await apiClient.post(`${HEADLESS_BASE}/mfa/webauthn/register/complete`, payload, { withCredentials: true });
8
9
  return res.data;
9
10
  }
@@ -27,7 +27,7 @@ export function AccessCodeManager() {
27
27
  setErrorKey(null);
28
28
  setSuccessKey(null);
29
29
  try {
30
- const res = await axios.get(`${ACCESS_CODES_BASE}/`, {
30
+ const res = await apiClient.get(`${ACCESS_CODES_BASE}/`, {
31
31
  withCredentials: true,
32
32
  });
33
33
  setCodes(res.data || []);
@@ -54,7 +54,7 @@ export function AccessCodeManager() {
54
54
  setErrorKey(null);
55
55
  setSuccessKey(null);
56
56
  try {
57
- const res = await axios.post(`${ACCESS_CODES_BASE}/`, { code }, { withCredentials: true });
57
+ const res = await apiClient.post(`${ACCESS_CODES_BASE}/`, { code }, { withCredentials: true });
58
58
  setCodes((prev) => [...prev, res.data]);
59
59
  setSuccessKey('Auth.ACCESS_CODE_SAVE_SUCCESS');
60
60
  }
@@ -71,7 +71,7 @@ export function AccessCodeManager() {
71
71
  };
72
72
  const handleAddManual = async () => {
73
73
  if (!manualCode.trim()) {
74
- setErrorKey('Auth.ACCESS_CODE_REQUIRED_ADMIN');
74
+ setErrorKey('Auth.SIGNUP_ACCESS_CODE_REQUIRED');
75
75
  return;
76
76
  }
77
77
  await handleCreateCode(manualCode.trim());
@@ -95,7 +95,7 @@ export function AccessCodeManager() {
95
95
  return (_jsx(Box, { sx: { py: 3, display: 'flex', justifyContent: 'center' }, children: _jsx(CircularProgress, {}) }));
96
96
  }
97
97
  return (_jsxs(Box, { sx: { mt: 2 }, children: [errorKey && (_jsx(Alert, { severity: "error", sx: { mb: 2 }, children: t(errorKey) })), successKey && (_jsx(Alert, { severity: "success", sx: { mb: 2 }, children: t(successKey) })), _jsxs(Box, { sx: { mb: 3 }, children: [_jsx(Typography, { variant: "subtitle1", gutterBottom: true, children: t('Auth.ACCESS_CODE_SECTION_ACTIVE') }), codes.length === 0 ? (_jsx(Typography, { variant: "body2", children: t('Auth.ACCESS_CODE_NONE') })) : (_jsx(Stack, { direction: "row", flexWrap: "wrap", gap: 1, children: codes.map((code) => (_jsx(Chip, { label: code.code, onDelete: () => handleDelete(code.id), deleteIcon: _jsx(CloseIcon, {}) }, code.id))) }))] }), _jsxs(Box, { sx: { mb: 3 }, children: [_jsx(Typography, { variant: "subtitle1", gutterBottom: true, children: t('Auth.ACCESS_CODE_SECTION_GENERATE') }), _jsxs(Box, { sx: { maxWidth: 360 }, children: [_jsx(Typography, { variant: "body2", gutterBottom: true, children: t('Auth.ACCESS_CODE_LENGTH_LABEL', { length }) }), _jsx(Slider, { min: 6, max: 32, step: 1, value: length, onChange: (_, val) => setLength(val), valueLabelDisplay: "auto", disabled: submitting })] }), _jsx(Button, { variant: "contained", sx: { mt: 1 }, onClick: handleGenerateClick, disabled: submitting, children: submitting
98
- ? t('Auth.ACCESS_CODE_SAVING')
98
+ ? t('Auth.SAVE_BUTTON_LOADING')
99
99
  : t('Auth.ACCESS_CODE_GENERATE_BUTTON') })] }), _jsxs(Box, { sx: { mb: 2, maxWidth: 360 }, children: [_jsx(Typography, { variant: "subtitle1", gutterBottom: true, children: t('Auth.ACCESS_CODE_SECTION_MANUAL') }), _jsxs(Box, { sx: { display: 'flex', gap: 1 }, children: [_jsx(TextField, { label: t('Auth.ACCESS_CODE_LABEL'), fullWidth: true, value: manualCode, onChange: (e) => setManualCode(e.target.value), disabled: submitting }), _jsx(Button, { variant: "outlined", onClick: handleAddManual, disabled: submitting, children: t('Auth.ACCESS_CODE_ADD_BUTTON') })] })] })] }));
100
100
  }
101
101
  export default AccessCodeManager;
@@ -21,6 +21,6 @@ disabled = false, initialIdentifier = '', }) => {
21
21
  const supportsPasskey = !!onPasskeyLogin &&
22
22
  typeof window !== 'undefined' &&
23
23
  !!window.PublicKeyCredential;
24
- return (_jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 3 }, children: [error && (_jsx(Typography, { color: "error", gutterBottom: true, children: error })), supportsPasskey && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "contained", fullWidth: true, type: "button", onClick: onPasskeyLogin, disabled: disabled, children: t('Auth.LOGIN_USE_PASSKEY_BUTTON') }), _jsx(Divider, { sx: { my: 2 }, children: t('Auth.LOGIN_OR') })] })), _jsxs(Box, { component: "form", onSubmit: handleSubmit, sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx(TextField, { label: t('Auth.EMAIL_LABEL'), type: "email", required: true, fullWidth: true, value: identifier, onChange: (e) => setIdentifier(e.target.value), disabled: disabled }), _jsx(TextField, { label: t('Auth.LOGIN_PASSWORD_LABEL'), type: "password", required: true, fullWidth: true, value: password, onChange: (e) => setPassword(e.target.value), disabled: disabled }), _jsx(Button, { type: "submit", variant: "contained", fullWidth: true, disabled: disabled, children: t('Auth.LOGIN_SUBMIT') })] }), _jsxs(Box, { children: [_jsx(Divider, { sx: { my: 2 }, children: t('Auth.LOGIN_OR') }), _jsx(SocialLoginButtons, { onProviderClick: onSocialLogin })] }), _jsxs(Box, { children: [_jsx(Typography, { variant: "subtitle2", sx: { mb: 1 }, children: t('Auth.LOGIN_ACCOUNT_RECOVERY_TITLE') }), _jsxs(Box, { sx: { display: 'flex', gap: 1, flexWrap: 'wrap' }, children: [onSignUp && (_jsx(Button, { type: "button", variant: "outlined", onClick: onSignUp, disabled: disabled, children: t('Auth.LOGIN_SIGNUP_BUTTON') })), _jsx(Button, { type: "button", variant: "outlined", onClick: onForgotPassword, disabled: disabled, children: t('Auth.LOGIN_FORGOT_PASSWORD_BUTTON') })] })] })] }));
24
+ return (_jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 3 }, children: [error && (_jsx(Typography, { color: "error", gutterBottom: true, children: error })), supportsPasskey && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "contained", fullWidth: true, type: "button", onClick: onPasskeyLogin, disabled: disabled, children: t('Auth.LOGIN_USE_PASSKEY_BUTTON') }), _jsx(Divider, { sx: { my: 2 }, children: t('Auth.LOGIN_OR') })] })), _jsxs(Box, { component: "form", onSubmit: handleSubmit, sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx(TextField, { label: t('Auth.EMAIL_LABEL'), type: "email", required: true, fullWidth: true, value: identifier, onChange: (e) => setIdentifier(e.target.value), disabled: disabled }), _jsx(TextField, { label: t('Auth.LOGIN_PASSWORD_LABEL'), type: "password", required: true, fullWidth: true, value: password, onChange: (e) => setPassword(e.target.value), disabled: disabled }), _jsx(Button, { type: "submit", variant: "contained", fullWidth: true, disabled: disabled, children: t('Auth.PAGE_LOGIN_TITLE') })] }), _jsxs(Box, { children: [_jsx(Divider, { sx: { my: 2 }, children: t('Auth.LOGIN_OR') }), _jsx(SocialLoginButtons, { onProviderClick: onSocialLogin })] }), _jsxs(Box, { children: [_jsx(Typography, { variant: "subtitle2", sx: { mb: 1 }, children: t('Auth.LOGIN_ACCOUNT_RECOVERY_TITLE') }), _jsxs(Box, { sx: { display: 'flex', gap: 1, flexWrap: 'wrap' }, children: [onSignUp && (_jsx(Button, { type: "button", variant: "outlined", onClick: onSignUp, disabled: disabled, children: t('Auth.LOGIN_SIGNUP_BUTTON') })), _jsx(Button, { type: "button", variant: "outlined", onClick: onForgotPassword, disabled: disabled, children: t('Auth.LOGIN_FORGOT_PASSWORD_BUTTON') })] })] })] }));
25
25
  };
26
26
  export default LoginForm;