@djangocfg/api 2.1.333 → 2.1.334

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/dist/auth.mjs CHANGED
@@ -343,6 +343,9 @@ var _apiKeyOverride = null;
343
343
  var _baseUrlOverride = null;
344
344
  var _withCredentials = true;
345
345
  var _onUnauthorized = null;
346
+ var _refreshHandler = null;
347
+ var _refreshInflight = null;
348
+ var RETRY_MARKER = "X-Auth-Retry";
346
349
  var _client = null;
347
350
  function pushClientConfig() {
348
351
  if (!_client) return;
@@ -421,10 +424,53 @@ var auth = {
421
424
  pushClientConfig();
422
425
  },
423
426
  // ── 401 handler ───────────────────────────────────────────────────
427
+ /**
428
+ * Fired when the server returns 401 AND no refresh path recovers it
429
+ * (no refresh token, no refresh handler, refresh failed, or retry
430
+ * still 401). The app should clear local state and redirect to login.
431
+ *
432
+ * NOT fired for 401 that gets transparently recovered by the refresh
433
+ * handler — those are invisible to callers.
434
+ */
424
435
  onUnauthorized(cb) {
425
436
  _onUnauthorized = cb;
437
+ },
438
+ /**
439
+ * Register the refresh strategy. The handler receives the current
440
+ * refresh token and must call your refresh endpoint, returning
441
+ * `{ access, refresh? }` on success or `null` on failure.
442
+ *
443
+ * @example
444
+ * auth.setRefreshHandler(async (refresh) => {
445
+ * const { data } = await Auth.tokenRefreshCreate({ body: { refresh } });
446
+ * return data ? { access: data.access, refresh: data.refresh } : null;
447
+ * });
448
+ */
449
+ setRefreshHandler(fn) {
450
+ _refreshHandler = fn;
426
451
  }
427
452
  };
453
+ async function tryRefresh() {
454
+ if (_refreshInflight) return _refreshInflight;
455
+ if (!_refreshHandler) return null;
456
+ const refresh = auth.getRefreshToken();
457
+ if (!refresh) return null;
458
+ _refreshInflight = (async () => {
459
+ try {
460
+ const result = await _refreshHandler(refresh);
461
+ if (!result?.access) return null;
462
+ auth.setToken(result.access);
463
+ if (result.refresh) auth.setRefreshToken(result.refresh);
464
+ return result.access;
465
+ } catch {
466
+ return null;
467
+ } finally {
468
+ _refreshInflight = null;
469
+ }
470
+ })();
471
+ return _refreshInflight;
472
+ }
473
+ __name(tryRefresh, "tryRefresh");
428
474
  function installAuthOnClient(client2) {
429
475
  if (_client) return;
430
476
  _client = client2;
@@ -441,14 +487,48 @@ function installAuthOnClient(client2) {
441
487
  if (apiKey) request.headers.set("X-API-Key", apiKey);
442
488
  return request;
443
489
  });
444
- client2.interceptors.response.use((response) => {
445
- if (response.status === 401 && _onUnauthorized) {
446
- try {
447
- _onUnauthorized(response);
448
- } catch {
490
+ client2.interceptors.response.use(async (response, request) => {
491
+ if (response.status !== 401) return response;
492
+ if (request.headers.get(RETRY_MARKER)) {
493
+ if (_onUnauthorized) {
494
+ try {
495
+ _onUnauthorized(response);
496
+ } catch {
497
+ }
449
498
  }
499
+ return response;
500
+ }
501
+ const newToken = await tryRefresh();
502
+ if (!newToken) {
503
+ if (_onUnauthorized) {
504
+ try {
505
+ _onUnauthorized(response);
506
+ } catch {
507
+ }
508
+ }
509
+ return response;
510
+ }
511
+ const retry = request.clone();
512
+ retry.headers.set("Authorization", `Bearer ${newToken}`);
513
+ retry.headers.set(RETRY_MARKER, "1");
514
+ try {
515
+ const retried = await fetch(retry);
516
+ if (retried.status === 401 && _onUnauthorized) {
517
+ try {
518
+ _onUnauthorized(retried);
519
+ } catch {
520
+ }
521
+ }
522
+ return retried;
523
+ } catch {
524
+ if (_onUnauthorized) {
525
+ try {
526
+ _onUnauthorized(response);
527
+ } catch {
528
+ }
529
+ }
530
+ return response;
450
531
  }
451
- return response;
452
532
  });
453
533
  }
454
534
  __name(installAuthOnClient, "installAuthOnClient");
@@ -599,6 +679,15 @@ var API = class {
599
679
  setApiKey(key) {
600
680
  auth.setApiKey(key);
601
681
  }
682
+ // ── 401 handling ────────────────────────────────────────────────────────
683
+ /** Fired only on terminal 401 (after refresh+retry path is exhausted). */
684
+ onUnauthorized(cb) {
685
+ auth.onUnauthorized(cb);
686
+ }
687
+ /** Provide a refresh strategy. See `auth.setRefreshHandler` for the contract. */
688
+ setRefreshHandler(fn) {
689
+ auth.setRefreshHandler(fn);
690
+ }
602
691
  };
603
692
 
604
693
  // src/_api/generated/helpers/errors.ts
@@ -713,6 +802,15 @@ var API2 = class {
713
802
  setApiKey(key) {
714
803
  auth.setApiKey(key);
715
804
  }
805
+ // ── 401 handling ────────────────────────────────────────────────────────
806
+ /** Fired only on terminal 401 (after refresh+retry path is exhausted). */
807
+ onUnauthorized(cb) {
808
+ auth.onUnauthorized(cb);
809
+ }
810
+ /** Provide a refresh strategy. See `auth.setRefreshHandler` for the contract. */
811
+ setRefreshHandler(fn) {
812
+ auth.setRefreshHandler(fn);
813
+ }
716
814
  };
717
815
 
718
816
  // src/_api/generated/_cfg_totp/api.ts
@@ -767,6 +865,15 @@ var API3 = class {
767
865
  setApiKey(key) {
768
866
  auth.setApiKey(key);
769
867
  }
868
+ // ── 401 handling ────────────────────────────────────────────────────────
869
+ /** Fired only on terminal 401 (after refresh+retry path is exhausted). */
870
+ onUnauthorized(cb) {
871
+ auth.onUnauthorized(cb);
872
+ }
873
+ /** Provide a refresh strategy. See `auth.setRefreshHandler` for the contract. */
874
+ setRefreshHandler(fn) {
875
+ auth.setRefreshHandler(fn);
876
+ }
770
877
  };
771
878
 
772
879
  // src/_api/generated/index.ts