@djangocfg/api 2.1.455 → 2.1.456

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.
Files changed (87) hide show
  1. package/dist/auth.cjs +2654 -2920
  2. package/dist/auth.cjs.map +1 -1
  3. package/dist/auth.d.cts +18 -82
  4. package/dist/auth.d.ts +18 -82
  5. package/dist/auth.mjs +385 -2861
  6. package/dist/auth.mjs.map +1 -1
  7. package/dist/chunk-2G67QRNU.mjs +2096 -0
  8. package/dist/chunk-2G67QRNU.mjs.map +1 -0
  9. package/dist/chunk-32SRQGAC.mjs +2109 -0
  10. package/dist/chunk-32SRQGAC.mjs.map +1 -0
  11. package/dist/chunk-4BPRCONN.mjs +2098 -0
  12. package/dist/chunk-4BPRCONN.mjs.map +1 -0
  13. package/dist/chunk-5UZ2Z323.mjs +2021 -0
  14. package/dist/chunk-5UZ2Z323.mjs.map +1 -0
  15. package/dist/chunk-7KFTJXNM.mjs +2097 -0
  16. package/dist/chunk-7KFTJXNM.mjs.map +1 -0
  17. package/dist/chunk-BK4K5CVT.mjs +2019 -0
  18. package/dist/chunk-BK4K5CVT.mjs.map +1 -0
  19. package/dist/chunk-JLPJZ6WB.mjs +2020 -0
  20. package/dist/chunk-JLPJZ6WB.mjs.map +1 -0
  21. package/dist/chunk-TVU6PYJH.mjs +2032 -0
  22. package/dist/chunk-TVU6PYJH.mjs.map +1 -0
  23. package/dist/clients.cjs +2210 -1847
  24. package/dist/clients.cjs.map +1 -1
  25. package/dist/clients.d.cts +23 -0
  26. package/dist/clients.d.ts +23 -0
  27. package/dist/clients.mjs +14 -1845
  28. package/dist/clients.mjs.map +1 -1
  29. package/dist/hooks.cjs +1776 -962
  30. package/dist/hooks.cjs.map +1 -1
  31. package/dist/hooks.mjs +4 -1375
  32. package/dist/hooks.mjs.map +1 -1
  33. package/dist/index.cjs +2245 -1877
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +81 -4
  36. package/dist/index.d.ts +81 -4
  37. package/dist/index.mjs +20 -1860
  38. package/dist/index.mjs.map +1 -1
  39. package/dist/sdk.gen-2SQOPTWJ.mjs +26 -0
  40. package/dist/sdk.gen-2SQOPTWJ.mjs.map +1 -0
  41. package/dist/sdk.gen-HSGK4C5S.mjs +26 -0
  42. package/dist/sdk.gen-HSGK4C5S.mjs.map +1 -0
  43. package/dist/sdk.gen-NUK2VGHO.mjs +25 -0
  44. package/dist/sdk.gen-NUK2VGHO.mjs.map +1 -0
  45. package/dist/sdk.gen-O4KAQUZB.mjs +26 -0
  46. package/dist/sdk.gen-O4KAQUZB.mjs.map +1 -0
  47. package/dist/sdk.gen-PPAVSBNT.mjs +26 -0
  48. package/dist/sdk.gen-PPAVSBNT.mjs.map +1 -0
  49. package/dist/sdk.gen-XLHLOCJ2.mjs +25 -0
  50. package/dist/sdk.gen-XLHLOCJ2.mjs.map +1 -0
  51. package/dist/sdk.gen-ZOE6NQAL.mjs +26 -0
  52. package/dist/sdk.gen-ZOE6NQAL.mjs.map +1 -0
  53. package/dist/sdk.gen-ZT7LGJVO.mjs +26 -0
  54. package/dist/sdk.gen-ZT7LGJVO.mjs.map +1 -0
  55. package/package.json +2 -2
  56. package/src/_api/generated/_cfg_accounts/hooks/index.ts +1 -0
  57. package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenBlacklistCreate.ts +28 -0
  58. package/src/_api/generated/_cfg_accounts/openapi.json +99 -0
  59. package/src/_api/generated/_cfg_accounts/schemas/TokenBlacklistRequest.ts +11 -0
  60. package/src/_api/generated/_cfg_accounts/schemas/index.ts +1 -0
  61. package/src/_api/generated/_cfg_centrifugo/openapi.json +9 -0
  62. package/src/_api/generated/_cfg_totp/openapi.json +33 -0
  63. package/src/_api/generated/helpers/auth.ts +276 -31
  64. package/src/_api/generated/openapi.json +129 -0
  65. package/src/_api/generated/sdk.gen.ts +94 -16
  66. package/src/_api/generated/types.gen.ts +18 -0
  67. package/src/auth/__tests__/guard.test.ts +0 -31
  68. package/src/auth/constants.ts +6 -0
  69. package/src/auth/context/AccountsContext.tsx +14 -24
  70. package/src/auth/context/AuthContext.tsx +226 -609
  71. package/src/auth/hooks/index.ts +3 -4
  72. package/src/auth/hooks/useGithubAuth.ts +3 -3
  73. package/src/auth/hooks/useSession.ts +22 -0
  74. package/src/auth/hooks/useTwoFactor.ts +4 -4
  75. package/src/auth/middlewares/index.ts +5 -6
  76. package/src/auth/utils/guard.ts +0 -22
  77. package/src/auth/utils/index.ts +0 -2
  78. package/src/_api/generated/_cfg_accounts/events.ts +0 -198
  79. package/src/_api/generated/_cfg_centrifugo/events.ts +0 -198
  80. package/src/_api/generated/_cfg_totp/events.ts +0 -198
  81. package/src/auth/__tests__/jwt.test.ts +0 -119
  82. package/src/auth/__tests__/sessionBootstrap.test.ts +0 -111
  83. package/src/auth/__tests__/useTokenRefresh.dom.test.tsx +0 -167
  84. package/src/auth/hooks/useAuthGuard.ts +0 -35
  85. package/src/auth/hooks/useTokenRefresh.ts +0 -131
  86. package/src/auth/refreshHandler.ts +0 -79
  87. package/src/auth/utils/jwt.ts +0 -66
package/dist/auth.mjs CHANGED
@@ -1,6 +1,16 @@
1
1
  "use client";
2
- var __defProp = Object.defineProperty;
3
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
2
+ import {
3
+ APIError,
4
+ CfgAccounts,
5
+ CfgAccountsAuth,
6
+ CfgAccountsOauth,
7
+ CfgAccountsProfile,
8
+ CfgTotp,
9
+ CfgTotpSetup,
10
+ CfgTotpVerify,
11
+ __name,
12
+ auth
13
+ } from "./chunk-4BPRCONN.mjs";
4
14
 
5
15
  // src/auth/constants.ts
6
16
  var AUTH_CONSTANTS = {
@@ -11,26 +21,166 @@ var AUTH_CONSTANTS = {
11
21
  /** Backup code max length. */
12
22
  BACKUP_CODE_MAX_LENGTH: 12
13
23
  };
14
-
15
- // src/auth/utils/env.ts
16
- var isDev = process.env.NODE_ENV === "development";
17
- var isBrowser = typeof window !== "undefined";
18
- var isStaticBuild = process.env.NEXT_PUBLIC_STATIC_BUILD === "true";
19
- var dpopEnabled = process.env.NEXT_PUBLIC_DPOP_ENABLED === "true";
24
+ var DEFAULT_AUTH_PATH = "/auth";
25
+ var DEFAULT_CALLBACK_PATH = "/dashboard";
20
26
 
21
27
  // src/auth/context/AuthContext.tsx
22
28
  import { usePathname as usePathname3 } from "next/navigation";
23
29
  import {
24
30
  createContext as createContext2,
25
31
  memo as memo2,
26
- useCallback as useCallback12,
32
+ useCallback as useCallback11,
27
33
  useContext as useContext2,
28
- useEffect as useEffect9,
34
+ useEffect as useEffect7,
29
35
  useMemo as useMemo3,
30
36
  useRef as useRef6,
31
- useState as useState12
37
+ useState as useState11
32
38
  } from "react";
33
- import { SWRConfig } from "swr";
39
+
40
+ // src/_api/generated/helpers/logger.ts
41
+ import { createConsola } from "consola";
42
+ var DEFAULT_CONFIG = {
43
+ enabled: typeof process !== "undefined" && process.env.NODE_ENV !== "production",
44
+ logRequests: true,
45
+ logResponses: true,
46
+ logErrors: true,
47
+ logBodies: true,
48
+ logHeaders: false
49
+ };
50
+ var SENSITIVE_HEADERS = [
51
+ "authorization",
52
+ "cookie",
53
+ "set-cookie",
54
+ "x-api-key",
55
+ "x-csrf-token"
56
+ ];
57
+ var APILogger = class {
58
+ static {
59
+ __name(this, "APILogger");
60
+ }
61
+ config;
62
+ consola;
63
+ constructor(config = {}) {
64
+ this.config = { ...DEFAULT_CONFIG, ...config };
65
+ this.consola = config.consola || createConsola({
66
+ level: this.config.enabled ? 4 : 0
67
+ });
68
+ }
69
+ enable() {
70
+ this.config.enabled = true;
71
+ }
72
+ disable() {
73
+ this.config.enabled = false;
74
+ }
75
+ setConfig(config) {
76
+ this.config = { ...this.config, ...config };
77
+ }
78
+ filterHeaders(headers) {
79
+ if (!headers) return {};
80
+ const filtered = {};
81
+ Object.keys(headers).forEach((key) => {
82
+ filtered[key] = SENSITIVE_HEADERS.includes(key.toLowerCase()) ? "***" : headers[key] || "";
83
+ });
84
+ return filtered;
85
+ }
86
+ logRequest(request) {
87
+ if (!this.config.enabled || !this.config.logRequests) return;
88
+ const { method, url, headers, body } = request;
89
+ this.consola.start(`${method} ${url}`);
90
+ if (this.config.logHeaders && headers) this.consola.debug("Headers:", this.filterHeaders(headers));
91
+ if (this.config.logBodies && body) this.consola.debug("Body:", body);
92
+ }
93
+ logResponse(request, response) {
94
+ if (!this.config.enabled || !this.config.logResponses) return;
95
+ const { method, url } = request;
96
+ const { status, statusText, data, duration } = response;
97
+ this.consola.success(`${method} ${url} ${status} ${statusText} (${duration}ms)`);
98
+ if (this.config.logBodies && data) this.consola.debug("Response:", data);
99
+ }
100
+ logError(request, error) {
101
+ if (!this.config.enabled || !this.config.logErrors) return;
102
+ const { method, url } = request;
103
+ const { message, statusCode, fieldErrors, duration } = error;
104
+ this.consola.error(`${method} ${url} ${statusCode || "Network"} Error (${duration}ms)`);
105
+ this.consola.error("Message:", message);
106
+ if (fieldErrors && Object.keys(fieldErrors).length > 0) {
107
+ this.consola.error("Field Errors:");
108
+ Object.entries(fieldErrors).forEach(([field, errors]) => {
109
+ errors.forEach((err) => this.consola.error(` \u2022 ${field}: ${err}`));
110
+ });
111
+ }
112
+ }
113
+ info(message, ...args) {
114
+ if (this.config.enabled) this.consola.info(message, ...args);
115
+ }
116
+ warn(message, ...args) {
117
+ if (this.config.enabled) this.consola.warn(message, ...args);
118
+ }
119
+ error(message, ...args) {
120
+ if (this.config.enabled) this.consola.error(message, ...args);
121
+ }
122
+ debug(message, ...args) {
123
+ if (this.config.enabled) this.consola.debug(message, ...args);
124
+ }
125
+ success(message, ...args) {
126
+ if (this.config.enabled) this.consola.success(message, ...args);
127
+ }
128
+ withTag(tag) {
129
+ return this.consola.withTag(tag);
130
+ }
131
+ };
132
+ var defaultLogger = new APILogger();
133
+
134
+ // src/auth/utils/env.ts
135
+ var isDev = process.env.NODE_ENV === "development";
136
+ var isBrowser = typeof window !== "undefined";
137
+ var isStaticBuild = process.env.NEXT_PUBLIC_STATIC_BUILD === "true";
138
+ var dpopEnabled = process.env.NEXT_PUBLIC_DPOP_ENABLED === "true";
139
+
140
+ // src/log-control.ts
141
+ var verboseByDefault = isDev || isStaticBuild;
142
+ var DEFAULT_LEVEL = verboseByDefault ? 4 : 1;
143
+ var _level = DEFAULT_LEVEL;
144
+ var _subscribers = /* @__PURE__ */ new Set();
145
+ function getLogLevel() {
146
+ return _level;
147
+ }
148
+ __name(getLogLevel, "getLogLevel");
149
+ function setLogLevel(level) {
150
+ _level = level;
151
+ for (const fn of _subscribers) {
152
+ try {
153
+ fn(level);
154
+ } catch {
155
+ }
156
+ }
157
+ }
158
+ __name(setLogLevel, "setLogLevel");
159
+ function onLogLevelChange(fn) {
160
+ _subscribers.add(fn);
161
+ try {
162
+ fn(_level);
163
+ } catch {
164
+ }
165
+ return () => _subscribers.delete(fn);
166
+ }
167
+ __name(onLogLevelChange, "onLogLevelChange");
168
+ function applyRoleLogPolicy(opts) {
169
+ const devMode = opts.isDev ?? verboseByDefault;
170
+ if (opts.isAdmin || devMode) {
171
+ setLogLevel(4);
172
+ } else {
173
+ setLogLevel(1);
174
+ }
175
+ }
176
+ __name(applyRoleLogPolicy, "applyRoleLogPolicy");
177
+
178
+ // src/auth/hooks/useSession.ts
179
+ import { useSyncExternalStore } from "react";
180
+ function useSession() {
181
+ return useSyncExternalStore(auth.subscribe, auth.getSnapshot, auth.getServerSnapshot);
182
+ }
183
+ __name(useSession, "useSession");
34
184
 
35
185
  // src/auth/hooks/useCfgRouter.ts
36
186
  import { useRouter as useNextRouter } from "next/navigation";
@@ -234,48 +384,8 @@ var validateIdentifier = /* @__PURE__ */ __name((id) => EMAIL_REGEX.test(id), "v
234
384
  import { useCallback as useCallback5, useEffect as useEffect4, useRef as useRef4 } from "react";
235
385
 
236
386
  // src/auth/utils/logger.ts
237
- import { createConsola } from "consola";
238
-
239
- // src/log-control.ts
240
- var verboseByDefault = isDev || isStaticBuild;
241
- var DEFAULT_LEVEL = verboseByDefault ? 4 : 1;
242
- var _level = DEFAULT_LEVEL;
243
- var _subscribers = /* @__PURE__ */ new Set();
244
- function getLogLevel() {
245
- return _level;
246
- }
247
- __name(getLogLevel, "getLogLevel");
248
- function setLogLevel(level) {
249
- _level = level;
250
- for (const fn of _subscribers) {
251
- try {
252
- fn(level);
253
- } catch {
254
- }
255
- }
256
- }
257
- __name(setLogLevel, "setLogLevel");
258
- function onLogLevelChange(fn) {
259
- _subscribers.add(fn);
260
- try {
261
- fn(_level);
262
- } catch {
263
- }
264
- return () => _subscribers.delete(fn);
265
- }
266
- __name(onLogLevelChange, "onLogLevelChange");
267
- function applyRoleLogPolicy(opts) {
268
- const devMode = opts.isDev ?? verboseByDefault;
269
- if (opts.isAdmin || devMode) {
270
- setLogLevel(4);
271
- } else {
272
- setLogLevel(1);
273
- }
274
- }
275
- __name(applyRoleLogPolicy, "applyRoleLogPolicy");
276
-
277
- // src/auth/utils/logger.ts
278
- var logger = createConsola({
387
+ import { createConsola as createConsola2 } from "consola";
388
+ var logger = createConsola2({
279
389
  level: getLogLevel()
280
390
  }).withTag("api");
281
391
  onLogLevelChange((level) => {
@@ -306,2203 +416,38 @@ var useAutoAuth = /* @__PURE__ */ __name((options = {}) => {
306
416
  const { onOTPDetected, cleanupUrl = true, allowedPaths = ["/auth"] } = options;
307
417
  const queryParams = useQueryParams();
308
418
  const pathname = usePathname2();
309
- const router = useCfgRouter();
310
- const isAllowedPath = isAllowedAuthPath(pathname, allowedPaths);
311
- const queryOtp = queryParams.get("otp") || "";
312
- const queryEmail = queryParams.get("email") || void 0;
313
- const hasOTP = !!queryOtp;
314
- const isReady = !!pathname && hasOTP && isAllowedPath;
315
- const otpValid = queryOtp.length === AUTH_CONSTANTS.EMAIL_OTP_LENGTH;
316
- const onOTPDetectedRef = useRef3(onOTPDetected);
317
- onOTPDetectedRef.current = onOTPDetected;
318
- useEffect3(() => {
319
- if (!isReady || !otpValid) return;
320
- authLogger.info("OTP detected in URL on auth page:", queryOtp);
321
- onOTPDetectedRef.current?.(queryOtp, queryEmail);
322
- }, [isReady, otpValid, queryOtp, queryEmail]);
323
- useEffect3(() => {
324
- if (!isReady || !cleanupUrl || !queryOtp) return;
325
- const cleanQuery = Object.fromEntries(queryParams.entries());
326
- delete cleanQuery.otp;
327
- delete cleanQuery.email;
328
- const queryString = new URLSearchParams(cleanQuery).toString();
329
- const realPathname = typeof window !== "undefined" ? window.location.pathname : pathname;
330
- router.replace(queryString ? `${realPathname}?${queryString}` : realPathname);
331
- }, [isReady, cleanupUrl, queryOtp]);
332
- return {
333
- isReady,
334
- hasOTP,
335
- isAllowedPath
336
- };
337
- }, "useAutoAuth");
338
-
339
- // src/auth/hooks/useTwoFactor.ts
340
- import { useCallback as useCallback4, useState as useState3 } from "react";
341
-
342
- // src/_api/generated/helpers/errors.ts
343
- var APIError = class extends Error {
344
- constructor(statusCode, statusText, response, url, message) {
345
- super(message || `HTTP ${statusCode}: ${statusText}`);
346
- this.statusCode = statusCode;
347
- this.statusText = statusText;
348
- this.response = response;
349
- this.url = url;
350
- this.name = "APIError";
351
- }
352
- static {
353
- __name(this, "APIError");
354
- }
355
- get details() {
356
- if (typeof this.response === "object" && this.response !== null) {
357
- return this.response;
358
- }
359
- return null;
360
- }
361
- get fieldErrors() {
362
- const details = this.details;
363
- if (!details) return null;
364
- const fieldErrors = {};
365
- for (const [key, value] of Object.entries(details)) {
366
- if (Array.isArray(value)) fieldErrors[key] = value;
367
- }
368
- return Object.keys(fieldErrors).length > 0 ? fieldErrors : null;
369
- }
370
- get errorMessage() {
371
- const details = this.details;
372
- if (!details) return this.message;
373
- if (details.detail) {
374
- return Array.isArray(details.detail) ? details.detail.join(", ") : String(details.detail);
375
- }
376
- if (details.error) return String(details.error);
377
- if (details.message) return String(details.message);
378
- const fieldErrors = this.fieldErrors;
379
- if (fieldErrors) {
380
- const firstField = Object.keys(fieldErrors)[0];
381
- if (firstField) return `${firstField}: ${fieldErrors[firstField]?.join(", ")}`;
382
- }
383
- return this.message;
384
- }
385
- get isValidationError() {
386
- return this.statusCode === 400;
387
- }
388
- get isAuthError() {
389
- return this.statusCode === 401;
390
- }
391
- get isPermissionError() {
392
- return this.statusCode === 403;
393
- }
394
- get isNotFoundError() {
395
- return this.statusCode === 404;
396
- }
397
- get isServerError() {
398
- return this.statusCode >= 500 && this.statusCode < 600;
399
- }
400
- };
401
-
402
- // src/_api/generated/helpers/auth.ts
403
- var ACCESS_KEY = "cfg.access_token";
404
- var REFRESH_KEY = "cfg.refresh_token";
405
- var API_KEY_KEY = "cfg.api_key";
406
- var isBrowser2 = typeof window !== "undefined";
407
- var localStorageBackend = {
408
- get(key) {
409
- if (!isBrowser2) return null;
410
- try {
411
- return window.localStorage.getItem(key);
412
- } catch {
413
- return null;
414
- }
415
- },
416
- set(key, value) {
417
- if (!isBrowser2) return;
418
- try {
419
- if (value === null) window.localStorage.removeItem(key);
420
- else window.localStorage.setItem(key, value);
421
- } catch {
422
- }
423
- }
424
- };
425
- var COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
426
- var cookieBackend = {
427
- get(key) {
428
- if (!isBrowser2) return null;
429
- try {
430
- const re = new RegExp(`(?:^|;\\s*)${encodeURIComponent(key)}=([^;]*)`);
431
- const m = document.cookie.match(re);
432
- return m ? decodeURIComponent(m[1]) : null;
433
- } catch {
434
- return null;
435
- }
436
- },
437
- set(key, value) {
438
- if (!isBrowser2) return;
439
- try {
440
- const k = encodeURIComponent(key);
441
- const secure = window.location.protocol === "https:" ? "; Secure" : "";
442
- if (value === null) {
443
- document.cookie = `${k}=; Path=/; Max-Age=0; SameSite=Lax${secure}`;
444
- } else {
445
- const v = encodeURIComponent(value);
446
- document.cookie = `${k}=${v}; Path=/; Max-Age=${COOKIE_MAX_AGE}; SameSite=Lax${secure}`;
447
- }
448
- } catch {
449
- }
450
- }
451
- };
452
- var _storage = localStorageBackend;
453
- var _storageMode = "localStorage";
454
- function detectLocale() {
455
- try {
456
- if (typeof document !== "undefined") {
457
- const m = document.cookie.match(/(?:^|;\s*)NEXT_LOCALE=([^;]*)/);
458
- if (m) return decodeURIComponent(m[1]);
459
- }
460
- if (typeof navigator !== "undefined" && navigator.language) {
461
- return navigator.language;
462
- }
463
- } catch {
464
- }
465
- return null;
466
- }
467
- __name(detectLocale, "detectLocale");
468
- function defaultBaseUrl() {
469
- if (typeof window !== "undefined") {
470
- try {
471
- if (typeof process !== "undefined" && process.env) {
472
- if (process.env.NEXT_PUBLIC_STATIC_BUILD === "true") return "";
473
- if (process.env.NEXT_PUBLIC_API_PROXY_URL !== void 0)
474
- return process.env.NEXT_PUBLIC_API_PROXY_URL;
475
- return process.env.NEXT_PUBLIC_API_URL || "";
476
- }
477
- } catch {
478
- }
479
- return "";
480
- }
481
- try {
482
- if (typeof process !== "undefined" && process.env) {
483
- if (process.env.NEXT_PUBLIC_STATIC_BUILD === "true") return "";
484
- return process.env.NEXT_PUBLIC_API_URL || "";
485
- }
486
- } catch {
487
- }
488
- return "";
489
- }
490
- __name(defaultBaseUrl, "defaultBaseUrl");
491
- function defaultApiKey() {
492
- try {
493
- if (typeof process !== "undefined" && process.env?.NEXT_PUBLIC_API_KEY) {
494
- return process.env.NEXT_PUBLIC_API_KEY;
495
- }
496
- } catch {
497
- }
498
- return null;
499
- }
500
- __name(defaultApiKey, "defaultApiKey");
501
- var _localeOverride = null;
502
- var _apiKeyOverride = null;
503
- var _baseUrlOverride = null;
504
- var _withCredentials = true;
505
- var _onUnauthorized = null;
506
- var _refreshHandler = null;
507
- var _refreshInflight = null;
508
- var RETRY_MARKER = "X-Auth-Retry";
509
- var _client = null;
510
- function pushClientConfig() {
511
- if (!_client) return;
512
- _client.setConfig({
513
- baseUrl: auth.getBaseUrl(),
514
- credentials: _withCredentials ? "include" : "same-origin"
515
- });
516
- }
517
- __name(pushClientConfig, "pushClientConfig");
518
- var auth = {
519
- // ── Storage mode ──────────────────────────────────────────────────
520
- getStorageMode() {
521
- return _storageMode;
522
- },
523
- setStorageMode(mode) {
524
- _storageMode = mode;
525
- _storage = mode === "cookie" ? cookieBackend : localStorageBackend;
526
- },
527
- // ── Bearer token ──────────────────────────────────────────────────
528
- getToken() {
529
- return _storage.get(ACCESS_KEY);
530
- },
531
- setToken(token) {
532
- _storage.set(ACCESS_KEY, token);
533
- },
534
- getRefreshToken() {
535
- return _storage.get(REFRESH_KEY);
536
- },
537
- setRefreshToken(token) {
538
- _storage.set(REFRESH_KEY, token);
539
- },
540
- clearTokens() {
541
- _storage.set(ACCESS_KEY, null);
542
- _storage.set(REFRESH_KEY, null);
543
- },
544
- isAuthenticated() {
545
- return _storage.get(ACCESS_KEY) !== null;
546
- },
547
- // ── API key ───────────────────────────────────────────────────────
548
- getApiKey() {
549
- return _apiKeyOverride ?? _storage.get(API_KEY_KEY) ?? defaultApiKey();
550
- },
551
- setApiKey(key) {
552
- _apiKeyOverride = key;
553
- },
554
- setApiKeyPersist(key) {
555
- _apiKeyOverride = key;
556
- _storage.set(API_KEY_KEY, key);
557
- },
558
- clearApiKey() {
559
- _apiKeyOverride = null;
560
- _storage.set(API_KEY_KEY, null);
561
- },
562
- // ── Locale ────────────────────────────────────────────────────────
563
- getLocale() {
564
- return _localeOverride ?? detectLocale();
565
- },
566
- setLocale(locale) {
567
- _localeOverride = locale;
568
- },
569
- // ── Base URL ──────────────────────────────────────────────────────
570
- getBaseUrl() {
571
- const url = _baseUrlOverride ?? defaultBaseUrl();
572
- return url.replace(/\/$/, "");
573
- },
574
- setBaseUrl(url) {
575
- _baseUrlOverride = url ? url.replace(/\/$/, "") : null;
576
- pushClientConfig();
577
- },
578
- // ── Credentials toggle ────────────────────────────────────────────
579
- getWithCredentials() {
580
- return _withCredentials;
581
- },
582
- setWithCredentials(value) {
583
- _withCredentials = value;
584
- pushClientConfig();
585
- },
586
- // ── 401 handler ───────────────────────────────────────────────────
587
- /**
588
- * Fired when the server returns 401 AND no refresh path recovers it
589
- * (no refresh token, no refresh handler, refresh failed, or retry
590
- * still 401). The app should clear local state and redirect to login.
591
- *
592
- * NOT fired for 401 that gets transparently recovered by the refresh
593
- * handler — those are invisible to callers.
594
- */
595
- onUnauthorized(cb) {
596
- _onUnauthorized = cb;
597
- },
598
- /**
599
- * Register the refresh strategy. The handler receives the current
600
- * refresh token and must call your refresh endpoint, returning
601
- * `{ access, refresh? }` on success or `null` on failure.
602
- *
603
- * @example
604
- * auth.setRefreshHandler(async (refresh) => {
605
- * const { data } = await Auth.tokenRefreshCreate({ body: { refresh } });
606
- * return data ? { access: data.access, refresh: data.refresh } : null;
607
- * });
608
- */
609
- setRefreshHandler(fn) {
610
- _refreshHandler = fn;
611
- },
612
- /**
613
- * Proactively run the registered refresh handler right now, reusing the
614
- * SAME single-flight promise as the 401-recovery interceptor. Callers
615
- * (e.g. an expiry timer / focus / reconnect) get token rotation,
616
- * de-duplication and rotated-token persistence for free — they must NOT
617
- * re-implement any of it. Returns the fresh access token, or null if
618
- * there is no handler / no refresh token / the refresh failed.
619
- */
620
- refreshNow() {
621
- return tryRefresh();
622
- }
623
- };
624
- async function tryRefresh() {
625
- if (_refreshInflight) return _refreshInflight;
626
- if (!_refreshHandler) return null;
627
- const refresh = auth.getRefreshToken();
628
- if (!refresh) return null;
629
- _refreshInflight = (async () => {
630
- try {
631
- const result = await _refreshHandler(refresh);
632
- if (!result?.access) return null;
633
- auth.setToken(result.access);
634
- if (result.refresh) auth.setRefreshToken(result.refresh);
635
- return result.access;
636
- } catch {
637
- return null;
638
- } finally {
639
- _refreshInflight = null;
640
- }
641
- })();
642
- return _refreshInflight;
643
- }
644
- __name(tryRefresh, "tryRefresh");
645
- function dpopEnabled2() {
646
- try {
647
- return typeof process !== "undefined" && process.env?.NEXT_PUBLIC_DPOP_ENABLED === "true";
648
- } catch {
649
- return false;
650
- }
651
- }
652
- __name(dpopEnabled2, "dpopEnabled");
653
- var _DPOP_DB = "cfg-auth";
654
- var _DPOP_STORE = "keys";
655
- var _DPOP_KEY_ID = "dpop-ec-p256";
656
- function _idbOpen() {
657
- return new Promise((resolve, reject) => {
658
- const req = indexedDB.open(_DPOP_DB, 1);
659
- req.onupgradeneeded = () => req.result.createObjectStore(_DPOP_STORE);
660
- req.onsuccess = () => resolve(req.result);
661
- req.onerror = () => reject(req.error);
662
- });
663
- }
664
- __name(_idbOpen, "_idbOpen");
665
- function _idbGet(key) {
666
- return _idbOpen().then((db) => new Promise((resolve, reject) => {
667
- const tx = db.transaction(_DPOP_STORE, "readonly");
668
- const req = tx.objectStore(_DPOP_STORE).get(key);
669
- req.onsuccess = () => resolve(req.result);
670
- req.onerror = () => reject(req.error);
671
- }));
672
- }
673
- __name(_idbGet, "_idbGet");
674
- function _idbPut(key, value) {
675
- return _idbOpen().then((db) => new Promise((resolve, reject) => {
676
- const tx = db.transaction(_DPOP_STORE, "readwrite");
677
- tx.objectStore(_DPOP_STORE).put(value, key);
678
- tx.oncomplete = () => resolve();
679
- tx.onerror = () => reject(tx.error);
680
- }));
681
- }
682
- __name(_idbPut, "_idbPut");
683
- var _dpopKeyPromise = null;
684
- function _getDpopKeyPair() {
685
- if (_dpopKeyPromise) return _dpopKeyPromise;
686
- _dpopKeyPromise = (async () => {
687
- const existing = await _idbGet(_DPOP_KEY_ID).catch(() => void 0);
688
- if (existing) return existing;
689
- const pair = await crypto.subtle.generateKey(
690
- { name: "ECDSA", namedCurve: "P-256" },
691
- false,
692
- // extractable:false — JS can sign but never export the private key
693
- ["sign"]
694
- );
695
- await _idbPut(_DPOP_KEY_ID, pair).catch(() => {
696
- });
697
- return pair;
698
- })();
699
- return _dpopKeyPromise;
700
- }
701
- __name(_getDpopKeyPair, "_getDpopKeyPair");
702
- function _b64urlFromBytes(bytes) {
703
- const arr = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
704
- let s = "";
705
- for (let i = 0; i < arr.length; i++) s += String.fromCharCode(arr[i]);
706
- return btoa(s).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
707
- }
708
- __name(_b64urlFromBytes, "_b64urlFromBytes");
709
- function _b64urlFromString(str) {
710
- return _b64urlFromBytes(new TextEncoder().encode(str));
711
- }
712
- __name(_b64urlFromString, "_b64urlFromString");
713
- async function _publicJwk(pub) {
714
- const jwk = await crypto.subtle.exportKey("jwk", pub);
715
- return { kty: "EC", crv: "P-256", x: jwk.x, y: jwk.y };
716
- }
717
- __name(_publicJwk, "_publicJwk");
718
- async function _makeDpopProof(method, url) {
719
- try {
720
- const pair = await _getDpopKeyPair();
721
- const jwk = await _publicJwk(pair.publicKey);
722
- const header = { typ: "dpop+jwt", alg: "ES256", jwk };
723
- const htu = url.split("#")[0].split("?")[0];
724
- const jti = crypto.randomUUID && crypto.randomUUID() || _b64urlFromBytes(crypto.getRandomValues(new Uint8Array(16)));
725
- const payload = { htm: method.toUpperCase(), htu, iat: Math.floor(Date.now() / 1e3), jti };
726
- const signingInput = `${_b64urlFromString(JSON.stringify(header))}.${_b64urlFromString(JSON.stringify(payload))}`;
727
- const sig = await crypto.subtle.sign(
728
- { name: "ECDSA", hash: "SHA-256" },
729
- pair.privateKey,
730
- new TextEncoder().encode(signingInput)
731
- );
732
- return `${signingInput}.${_b64urlFromBytes(sig)}`;
733
- } catch {
734
- return null;
735
- }
736
- }
737
- __name(_makeDpopProof, "_makeDpopProof");
738
- function installAuthOnClient(client2) {
739
- if (_client) return;
740
- _client = client2;
741
- client2.setConfig({
742
- baseUrl: auth.getBaseUrl(),
743
- credentials: _withCredentials ? "include" : "same-origin"
744
- });
745
- client2.interceptors.request.use(async (request) => {
746
- const token = auth.getToken();
747
- if (token) request.headers.set("Authorization", `Bearer ${token}`);
748
- const locale = auth.getLocale();
749
- if (locale) request.headers.set("Accept-Language", locale);
750
- const apiKey = auth.getApiKey();
751
- if (apiKey && !request.headers.has("X-API-Key")) request.headers.set("X-API-Key", apiKey);
752
- try {
753
- const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
754
- if (tz) request.headers.set("X-Timezone", tz);
755
- } catch {
756
- }
757
- request.headers.set("X-Client-Time", (/* @__PURE__ */ new Date()).toISOString());
758
- if (dpopEnabled2() && typeof window !== "undefined") {
759
- const proof = await _makeDpopProof(request.method, request.url);
760
- if (proof) request.headers.set("DPoP", proof);
761
- }
762
- return request;
763
- });
764
- client2.interceptors.error.use((err, res, req) => {
765
- if (err instanceof APIError) return err;
766
- const url = req?.url ?? "";
767
- const status = res?.status ?? 0;
768
- const statusText = res?.statusText ?? "";
769
- return new APIError(status, statusText, err, url);
770
- });
771
- client2.interceptors.response.use(async (response, request) => {
772
- if (response.status !== 401) return response;
773
- if (request.headers.get(RETRY_MARKER)) {
774
- if (_onUnauthorized) {
775
- try {
776
- _onUnauthorized(response);
777
- } catch {
778
- }
779
- }
780
- return response;
781
- }
782
- const newToken = await tryRefresh();
783
- if (!newToken) {
784
- if (_onUnauthorized) {
785
- try {
786
- _onUnauthorized(response);
787
- } catch {
788
- }
789
- }
790
- return response;
791
- }
792
- const retry = request.clone();
793
- retry.headers.set("Authorization", `Bearer ${newToken}`);
794
- retry.headers.set(RETRY_MARKER, "1");
795
- if (dpopEnabled2() && typeof window !== "undefined") {
796
- const proof = await _makeDpopProof(retry.method, retry.url);
797
- if (proof) retry.headers.set("DPoP", proof);
798
- }
799
- try {
800
- const retried = await fetch(retry);
801
- if (retried.status === 401 && _onUnauthorized) {
802
- try {
803
- _onUnauthorized(retried);
804
- } catch {
805
- }
806
- }
807
- return retried;
808
- } catch {
809
- if (_onUnauthorized) {
810
- try {
811
- _onUnauthorized(response);
812
- } catch {
813
- }
814
- }
815
- return response;
816
- }
817
- });
818
- }
819
- __name(installAuthOnClient, "installAuthOnClient");
820
-
821
- // src/_api/generated/helpers/logger.ts
822
- import { createConsola as createConsola2 } from "consola";
823
- var DEFAULT_CONFIG = {
824
- enabled: typeof process !== "undefined" && process.env.NODE_ENV !== "production",
825
- logRequests: true,
826
- logResponses: true,
827
- logErrors: true,
828
- logBodies: true,
829
- logHeaders: false
830
- };
831
- var SENSITIVE_HEADERS = [
832
- "authorization",
833
- "cookie",
834
- "set-cookie",
835
- "x-api-key",
836
- "x-csrf-token"
837
- ];
838
- var APILogger = class {
839
- static {
840
- __name(this, "APILogger");
841
- }
842
- config;
843
- consola;
844
- constructor(config = {}) {
845
- this.config = { ...DEFAULT_CONFIG, ...config };
846
- this.consola = config.consola || createConsola2({
847
- level: this.config.enabled ? 4 : 0
848
- });
849
- }
850
- enable() {
851
- this.config.enabled = true;
852
- }
853
- disable() {
854
- this.config.enabled = false;
855
- }
856
- setConfig(config) {
857
- this.config = { ...this.config, ...config };
858
- }
859
- filterHeaders(headers) {
860
- if (!headers) return {};
861
- const filtered = {};
862
- Object.keys(headers).forEach((key) => {
863
- filtered[key] = SENSITIVE_HEADERS.includes(key.toLowerCase()) ? "***" : headers[key] || "";
864
- });
865
- return filtered;
866
- }
867
- logRequest(request) {
868
- if (!this.config.enabled || !this.config.logRequests) return;
869
- const { method, url, headers, body } = request;
870
- this.consola.start(`${method} ${url}`);
871
- if (this.config.logHeaders && headers) this.consola.debug("Headers:", this.filterHeaders(headers));
872
- if (this.config.logBodies && body) this.consola.debug("Body:", body);
873
- }
874
- logResponse(request, response) {
875
- if (!this.config.enabled || !this.config.logResponses) return;
876
- const { method, url } = request;
877
- const { status, statusText, data, duration } = response;
878
- this.consola.success(`${method} ${url} ${status} ${statusText} (${duration}ms)`);
879
- if (this.config.logBodies && data) this.consola.debug("Response:", data);
880
- }
881
- logError(request, error) {
882
- if (!this.config.enabled || !this.config.logErrors) return;
883
- const { method, url } = request;
884
- const { message, statusCode, fieldErrors, duration } = error;
885
- this.consola.error(`${method} ${url} ${statusCode || "Network"} Error (${duration}ms)`);
886
- this.consola.error("Message:", message);
887
- if (fieldErrors && Object.keys(fieldErrors).length > 0) {
888
- this.consola.error("Field Errors:");
889
- Object.entries(fieldErrors).forEach(([field, errors]) => {
890
- errors.forEach((err) => this.consola.error(` \u2022 ${field}: ${err}`));
891
- });
892
- }
893
- }
894
- info(message, ...args) {
895
- if (this.config.enabled) this.consola.info(message, ...args);
896
- }
897
- warn(message, ...args) {
898
- if (this.config.enabled) this.consola.warn(message, ...args);
899
- }
900
- error(message, ...args) {
901
- if (this.config.enabled) this.consola.error(message, ...args);
902
- }
903
- debug(message, ...args) {
904
- if (this.config.enabled) this.consola.debug(message, ...args);
905
- }
906
- success(message, ...args) {
907
- if (this.config.enabled) this.consola.success(message, ...args);
908
- }
909
- withTag(tag) {
910
- return this.consola.withTag(tag);
911
- }
912
- };
913
- var defaultLogger = new APILogger();
914
-
915
- // src/_api/generated/core/bodySerializer.gen.ts
916
- var serializeFormDataPair = /* @__PURE__ */ __name((data, key, value) => {
917
- if (typeof value === "string" || value instanceof Blob) {
918
- data.append(key, value);
919
- } else if (value instanceof Date) {
920
- data.append(key, value.toISOString());
921
- } else {
922
- data.append(key, JSON.stringify(value));
923
- }
924
- }, "serializeFormDataPair");
925
- var formDataBodySerializer = {
926
- bodySerializer: /* @__PURE__ */ __name((body) => {
927
- const data = new FormData();
928
- Object.entries(body).forEach(([key, value]) => {
929
- if (value === void 0 || value === null) {
930
- return;
931
- }
932
- if (Array.isArray(value)) {
933
- value.forEach((v) => serializeFormDataPair(data, key, v));
934
- } else {
935
- serializeFormDataPair(data, key, value);
936
- }
937
- });
938
- return data;
939
- }, "bodySerializer")
940
- };
941
- var jsonBodySerializer = {
942
- bodySerializer: /* @__PURE__ */ __name((body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value), "bodySerializer")
943
- };
944
-
945
- // src/_api/generated/core/params.gen.ts
946
- var extraPrefixesMap = {
947
- $body_: "body",
948
- $headers_: "headers",
949
- $path_: "path",
950
- $query_: "query"
951
- };
952
- var extraPrefixes = Object.entries(extraPrefixesMap);
953
-
954
- // src/_api/generated/core/serverSentEvents.gen.ts
955
- function createSseClient({
956
- onRequest,
957
- onSseError,
958
- onSseEvent,
959
- responseTransformer,
960
- responseValidator,
961
- sseDefaultRetryDelay,
962
- sseMaxRetryAttempts,
963
- sseMaxRetryDelay,
964
- sseSleepFn,
965
- url,
966
- ...options
967
- }) {
968
- let lastEventId;
969
- const sleep = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
970
- const createStream = /* @__PURE__ */ __name(async function* () {
971
- let retryDelay = sseDefaultRetryDelay ?? 3e3;
972
- let attempt = 0;
973
- const signal = options.signal ?? new AbortController().signal;
974
- while (true) {
975
- if (signal.aborted) break;
976
- attempt++;
977
- const headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers);
978
- if (lastEventId !== void 0) {
979
- headers.set("Last-Event-ID", lastEventId);
980
- }
981
- try {
982
- const requestInit = {
983
- redirect: "follow",
984
- ...options,
985
- body: options.serializedBody,
986
- headers,
987
- signal
988
- };
989
- let request = new Request(url, requestInit);
990
- if (onRequest) {
991
- request = await onRequest(url, requestInit);
992
- }
993
- const _fetch = options.fetch ?? globalThis.fetch;
994
- const response = await _fetch(request);
995
- if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`);
996
- if (!response.body) throw new Error("No body in SSE response");
997
- const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
998
- let buffer = "";
999
- const abortHandler = /* @__PURE__ */ __name(() => {
1000
- try {
1001
- reader.cancel();
1002
- } catch {
1003
- }
1004
- }, "abortHandler");
1005
- signal.addEventListener("abort", abortHandler);
1006
- try {
1007
- while (true) {
1008
- const { done, value } = await reader.read();
1009
- if (done) break;
1010
- buffer += value;
1011
- buffer = buffer.replace(/\r\n?/g, "\n");
1012
- const chunks = buffer.split("\n\n");
1013
- buffer = chunks.pop() ?? "";
1014
- for (const chunk of chunks) {
1015
- const lines = chunk.split("\n");
1016
- const dataLines = [];
1017
- let eventName;
1018
- for (const line of lines) {
1019
- if (line.startsWith("data:")) {
1020
- dataLines.push(line.replace(/^data:\s*/, ""));
1021
- } else if (line.startsWith("event:")) {
1022
- eventName = line.replace(/^event:\s*/, "");
1023
- } else if (line.startsWith("id:")) {
1024
- lastEventId = line.replace(/^id:\s*/, "");
1025
- } else if (line.startsWith("retry:")) {
1026
- const parsed = Number.parseInt(line.replace(/^retry:\s*/, ""), 10);
1027
- if (!Number.isNaN(parsed)) {
1028
- retryDelay = parsed;
1029
- }
1030
- }
1031
- }
1032
- let data;
1033
- let parsedJson = false;
1034
- if (dataLines.length) {
1035
- const rawData = dataLines.join("\n");
1036
- try {
1037
- data = JSON.parse(rawData);
1038
- parsedJson = true;
1039
- } catch {
1040
- data = rawData;
1041
- }
1042
- }
1043
- if (parsedJson) {
1044
- if (responseValidator) {
1045
- await responseValidator(data);
1046
- }
1047
- if (responseTransformer) {
1048
- data = await responseTransformer(data);
1049
- }
1050
- }
1051
- onSseEvent?.({
1052
- data,
1053
- event: eventName,
1054
- id: lastEventId,
1055
- retry: retryDelay
1056
- });
1057
- if (dataLines.length) {
1058
- yield data;
1059
- }
1060
- }
1061
- }
1062
- } finally {
1063
- signal.removeEventListener("abort", abortHandler);
1064
- reader.releaseLock();
1065
- }
1066
- break;
1067
- } catch (error) {
1068
- onSseError?.(error);
1069
- if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
1070
- break;
1071
- }
1072
- const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 3e4);
1073
- await sleep(backoff);
1074
- }
1075
- }
1076
- }, "createStream");
1077
- const stream = createStream();
1078
- return { stream };
1079
- }
1080
- __name(createSseClient, "createSseClient");
1081
-
1082
- // src/_api/generated/core/pathSerializer.gen.ts
1083
- var separatorArrayExplode = /* @__PURE__ */ __name((style) => {
1084
- switch (style) {
1085
- case "label":
1086
- return ".";
1087
- case "matrix":
1088
- return ";";
1089
- case "simple":
1090
- return ",";
1091
- default:
1092
- return "&";
1093
- }
1094
- }, "separatorArrayExplode");
1095
- var separatorArrayNoExplode = /* @__PURE__ */ __name((style) => {
1096
- switch (style) {
1097
- case "form":
1098
- return ",";
1099
- case "pipeDelimited":
1100
- return "|";
1101
- case "spaceDelimited":
1102
- return "%20";
1103
- default:
1104
- return ",";
1105
- }
1106
- }, "separatorArrayNoExplode");
1107
- var separatorObjectExplode = /* @__PURE__ */ __name((style) => {
1108
- switch (style) {
1109
- case "label":
1110
- return ".";
1111
- case "matrix":
1112
- return ";";
1113
- case "simple":
1114
- return ",";
1115
- default:
1116
- return "&";
1117
- }
1118
- }, "separatorObjectExplode");
1119
- var serializeArrayParam = /* @__PURE__ */ __name(({
1120
- allowReserved,
1121
- explode,
1122
- name,
1123
- style,
1124
- value
1125
- }) => {
1126
- if (!explode) {
1127
- const joinedValues2 = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
1128
- switch (style) {
1129
- case "label":
1130
- return `.${joinedValues2}`;
1131
- case "matrix":
1132
- return `;${name}=${joinedValues2}`;
1133
- case "simple":
1134
- return joinedValues2;
1135
- default:
1136
- return `${name}=${joinedValues2}`;
1137
- }
1138
- }
1139
- const separator = separatorArrayExplode(style);
1140
- const joinedValues = value.map((v) => {
1141
- if (style === "label" || style === "simple") {
1142
- return allowReserved ? v : encodeURIComponent(v);
1143
- }
1144
- return serializePrimitiveParam({
1145
- allowReserved,
1146
- name,
1147
- value: v
1148
- });
1149
- }).join(separator);
1150
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
1151
- }, "serializeArrayParam");
1152
- var serializePrimitiveParam = /* @__PURE__ */ __name(({
1153
- allowReserved,
1154
- name,
1155
- value
1156
- }) => {
1157
- if (value === void 0 || value === null) {
1158
- return "";
1159
- }
1160
- if (typeof value === "object") {
1161
- throw new Error(
1162
- "Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these."
1163
- );
1164
- }
1165
- return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
1166
- }, "serializePrimitiveParam");
1167
- var serializeObjectParam = /* @__PURE__ */ __name(({
1168
- allowReserved,
1169
- explode,
1170
- name,
1171
- style,
1172
- value,
1173
- valueOnly
1174
- }) => {
1175
- if (value instanceof Date) {
1176
- return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
1177
- }
1178
- if (style !== "deepObject" && !explode) {
1179
- let values = [];
1180
- Object.entries(value).forEach(([key, v]) => {
1181
- values = [...values, key, allowReserved ? v : encodeURIComponent(v)];
1182
- });
1183
- const joinedValues2 = values.join(",");
1184
- switch (style) {
1185
- case "form":
1186
- return `${name}=${joinedValues2}`;
1187
- case "label":
1188
- return `.${joinedValues2}`;
1189
- case "matrix":
1190
- return `;${name}=${joinedValues2}`;
1191
- default:
1192
- return joinedValues2;
1193
- }
1194
- }
1195
- const separator = separatorObjectExplode(style);
1196
- const joinedValues = Object.entries(value).map(
1197
- ([key, v]) => serializePrimitiveParam({
1198
- allowReserved,
1199
- name: style === "deepObject" ? `${name}[${key}]` : key,
1200
- value: v
1201
- })
1202
- ).join(separator);
1203
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
1204
- }, "serializeObjectParam");
1205
-
1206
- // src/_api/generated/core/utils.gen.ts
1207
- var PATH_PARAM_RE = /\{[^{}]+\}/g;
1208
- var defaultPathSerializer = /* @__PURE__ */ __name(({ path, url: _url }) => {
1209
- let url = _url;
1210
- const matches = _url.match(PATH_PARAM_RE);
1211
- if (matches) {
1212
- for (const match of matches) {
1213
- let explode = false;
1214
- let name = match.substring(1, match.length - 1);
1215
- let style = "simple";
1216
- if (name.endsWith("*")) {
1217
- explode = true;
1218
- name = name.substring(0, name.length - 1);
1219
- }
1220
- if (name.startsWith(".")) {
1221
- name = name.substring(1);
1222
- style = "label";
1223
- } else if (name.startsWith(";")) {
1224
- name = name.substring(1);
1225
- style = "matrix";
1226
- }
1227
- const value = path[name];
1228
- if (value === void 0 || value === null) {
1229
- continue;
1230
- }
1231
- if (Array.isArray(value)) {
1232
- url = url.replace(match, serializeArrayParam({ explode, name, style, value }));
1233
- continue;
1234
- }
1235
- if (typeof value === "object") {
1236
- url = url.replace(
1237
- match,
1238
- serializeObjectParam({
1239
- explode,
1240
- name,
1241
- style,
1242
- value,
1243
- valueOnly: true
1244
- })
1245
- );
1246
- continue;
1247
- }
1248
- if (style === "matrix") {
1249
- url = url.replace(
1250
- match,
1251
- `;${serializePrimitiveParam({
1252
- name,
1253
- value
1254
- })}`
1255
- );
1256
- continue;
1257
- }
1258
- const replaceValue = encodeURIComponent(
1259
- style === "label" ? `.${value}` : value
1260
- );
1261
- url = url.replace(match, replaceValue);
1262
- }
1263
- }
1264
- return url;
1265
- }, "defaultPathSerializer");
1266
- var getUrl = /* @__PURE__ */ __name(({
1267
- baseUrl,
1268
- path,
1269
- query,
1270
- querySerializer,
1271
- url: _url
1272
- }) => {
1273
- const pathUrl = _url.startsWith("/") ? _url : `/${_url}`;
1274
- let url = (baseUrl ?? "") + pathUrl;
1275
- if (path) {
1276
- url = defaultPathSerializer({ path, url });
1277
- }
1278
- let search = query ? querySerializer(query) : "";
1279
- if (search.startsWith("?")) {
1280
- search = search.substring(1);
1281
- }
1282
- if (search) {
1283
- url += `?${search}`;
1284
- }
1285
- return url;
1286
- }, "getUrl");
1287
- function getValidRequestBody(options) {
1288
- const hasBody = options.body !== void 0;
1289
- const isSerializedBody = hasBody && options.bodySerializer;
1290
- if (isSerializedBody) {
1291
- if ("serializedBody" in options) {
1292
- const hasSerializedBody = options.serializedBody !== void 0 && options.serializedBody !== "";
1293
- return hasSerializedBody ? options.serializedBody : null;
1294
- }
1295
- return options.body !== "" ? options.body : null;
1296
- }
1297
- if (hasBody) {
1298
- return options.body;
1299
- }
1300
- return void 0;
1301
- }
1302
- __name(getValidRequestBody, "getValidRequestBody");
1303
-
1304
- // src/_api/generated/core/auth.gen.ts
1305
- var getAuthToken = /* @__PURE__ */ __name(async (auth2, callback) => {
1306
- const token = typeof callback === "function" ? await callback(auth2) : callback;
1307
- if (!token) {
1308
- return;
1309
- }
1310
- if (auth2.scheme === "bearer") {
1311
- return `Bearer ${token}`;
1312
- }
1313
- if (auth2.scheme === "basic") {
1314
- return `Basic ${btoa(token)}`;
1315
- }
1316
- return token;
1317
- }, "getAuthToken");
1318
-
1319
- // src/_api/generated/client/utils.gen.ts
1320
- var createQuerySerializer = /* @__PURE__ */ __name(({
1321
- parameters = {},
1322
- ...args
1323
- } = {}) => {
1324
- const querySerializer = /* @__PURE__ */ __name((queryParams) => {
1325
- const search = [];
1326
- if (queryParams && typeof queryParams === "object") {
1327
- for (const name in queryParams) {
1328
- const value = queryParams[name];
1329
- if (value === void 0 || value === null) {
1330
- continue;
1331
- }
1332
- const options = parameters[name] || args;
1333
- if (Array.isArray(value)) {
1334
- const serializedArray = serializeArrayParam({
1335
- allowReserved: options.allowReserved,
1336
- explode: true,
1337
- name,
1338
- style: "form",
1339
- value,
1340
- ...options.array
1341
- });
1342
- if (serializedArray) search.push(serializedArray);
1343
- } else if (typeof value === "object") {
1344
- const serializedObject = serializeObjectParam({
1345
- allowReserved: options.allowReserved,
1346
- explode: true,
1347
- name,
1348
- style: "deepObject",
1349
- value,
1350
- ...options.object
1351
- });
1352
- if (serializedObject) search.push(serializedObject);
1353
- } else {
1354
- const serializedPrimitive = serializePrimitiveParam({
1355
- allowReserved: options.allowReserved,
1356
- name,
1357
- value
1358
- });
1359
- if (serializedPrimitive) search.push(serializedPrimitive);
1360
- }
1361
- }
1362
- }
1363
- return search.join("&");
1364
- }, "querySerializer");
1365
- return querySerializer;
1366
- }, "createQuerySerializer");
1367
- var getParseAs = /* @__PURE__ */ __name((contentType) => {
1368
- if (!contentType) {
1369
- return "stream";
1370
- }
1371
- const cleanContent = contentType.split(";")[0]?.trim();
1372
- if (!cleanContent) {
1373
- return;
1374
- }
1375
- if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) {
1376
- return "json";
1377
- }
1378
- if (cleanContent === "multipart/form-data") {
1379
- return "formData";
1380
- }
1381
- if (["application/", "audio/", "image/", "video/"].some((type) => cleanContent.startsWith(type))) {
1382
- return "blob";
1383
- }
1384
- if (cleanContent.startsWith("text/")) {
1385
- return "text";
1386
- }
1387
- return;
1388
- }, "getParseAs");
1389
- var checkForExistence = /* @__PURE__ */ __name((options, name) => {
1390
- if (!name) {
1391
- return false;
1392
- }
1393
- if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) {
1394
- return true;
1395
- }
1396
- return false;
1397
- }, "checkForExistence");
1398
- async function setAuthParams(options) {
1399
- for (const auth2 of options.security ?? []) {
1400
- if (checkForExistence(options, auth2.name)) {
1401
- continue;
1402
- }
1403
- const token = await getAuthToken(auth2, options.auth);
1404
- if (!token) {
1405
- continue;
1406
- }
1407
- const name = auth2.name ?? "Authorization";
1408
- switch (auth2.in) {
1409
- case "query":
1410
- if (!options.query) {
1411
- options.query = {};
1412
- }
1413
- options.query[name] = token;
1414
- break;
1415
- case "cookie":
1416
- options.headers.append("Cookie", `${name}=${token}`);
1417
- break;
1418
- case "header":
1419
- default:
1420
- options.headers.set(name, token);
1421
- break;
1422
- }
1423
- }
1424
- }
1425
- __name(setAuthParams, "setAuthParams");
1426
- var buildUrl = /* @__PURE__ */ __name((options) => getUrl({
1427
- baseUrl: options.baseUrl,
1428
- path: options.path,
1429
- query: options.query,
1430
- querySerializer: typeof options.querySerializer === "function" ? options.querySerializer : createQuerySerializer(options.querySerializer),
1431
- url: options.url
1432
- }), "buildUrl");
1433
- var mergeConfigs = /* @__PURE__ */ __name((a, b) => {
1434
- const config = { ...a, ...b };
1435
- if (config.baseUrl?.endsWith("/")) {
1436
- config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
1437
- }
1438
- config.headers = mergeHeaders(a.headers, b.headers);
1439
- return config;
1440
- }, "mergeConfigs");
1441
- var headersEntries = /* @__PURE__ */ __name((headers) => {
1442
- const entries = [];
1443
- headers.forEach((value, key) => {
1444
- entries.push([key, value]);
1445
- });
1446
- return entries;
1447
- }, "headersEntries");
1448
- var mergeHeaders = /* @__PURE__ */ __name((...headers) => {
1449
- const mergedHeaders = new Headers();
1450
- for (const header of headers) {
1451
- if (!header) {
1452
- continue;
1453
- }
1454
- const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header);
1455
- for (const [key, value] of iterator) {
1456
- if (value === null) {
1457
- mergedHeaders.delete(key);
1458
- } else if (Array.isArray(value)) {
1459
- for (const v of value) {
1460
- mergedHeaders.append(key, v);
1461
- }
1462
- } else if (value !== void 0) {
1463
- mergedHeaders.set(
1464
- key,
1465
- typeof value === "object" ? JSON.stringify(value) : value
1466
- );
1467
- }
1468
- }
1469
- }
1470
- return mergedHeaders;
1471
- }, "mergeHeaders");
1472
- var Interceptors = class {
1473
- static {
1474
- __name(this, "Interceptors");
1475
- }
1476
- fns = [];
1477
- clear() {
1478
- this.fns = [];
1479
- }
1480
- eject(id) {
1481
- const index = this.getInterceptorIndex(id);
1482
- if (this.fns[index]) {
1483
- this.fns[index] = null;
1484
- }
1485
- }
1486
- exists(id) {
1487
- const index = this.getInterceptorIndex(id);
1488
- return Boolean(this.fns[index]);
1489
- }
1490
- getInterceptorIndex(id) {
1491
- if (typeof id === "number") {
1492
- return this.fns[id] ? id : -1;
1493
- }
1494
- return this.fns.indexOf(id);
1495
- }
1496
- update(id, fn) {
1497
- const index = this.getInterceptorIndex(id);
1498
- if (this.fns[index]) {
1499
- this.fns[index] = fn;
1500
- return id;
1501
- }
1502
- return false;
1503
- }
1504
- use(fn) {
1505
- this.fns.push(fn);
1506
- return this.fns.length - 1;
1507
- }
1508
- };
1509
- var createInterceptors = /* @__PURE__ */ __name(() => ({
1510
- error: new Interceptors(),
1511
- request: new Interceptors(),
1512
- response: new Interceptors()
1513
- }), "createInterceptors");
1514
- var defaultQuerySerializer = createQuerySerializer({
1515
- allowReserved: false,
1516
- array: {
1517
- explode: true,
1518
- style: "form"
1519
- },
1520
- object: {
1521
- explode: true,
1522
- style: "deepObject"
1523
- }
1524
- });
1525
- var defaultHeaders = {
1526
- "Content-Type": "application/json"
1527
- };
1528
- var createConfig = /* @__PURE__ */ __name((override = {}) => ({
1529
- ...jsonBodySerializer,
1530
- headers: defaultHeaders,
1531
- parseAs: "auto",
1532
- querySerializer: defaultQuerySerializer,
1533
- ...override
1534
- }), "createConfig");
1535
-
1536
- // src/_api/generated/client/client.gen.ts
1537
- var createClient = /* @__PURE__ */ __name((config = {}) => {
1538
- let _config = mergeConfigs(createConfig(), config);
1539
- const getConfig = /* @__PURE__ */ __name(() => ({ ..._config }), "getConfig");
1540
- const setConfig = /* @__PURE__ */ __name((config2) => {
1541
- _config = mergeConfigs(_config, config2);
1542
- return getConfig();
1543
- }, "setConfig");
1544
- const interceptors = createInterceptors();
1545
- const beforeRequest = /* @__PURE__ */ __name(async (options) => {
1546
- const opts = {
1547
- ..._config,
1548
- ...options,
1549
- fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
1550
- headers: mergeHeaders(_config.headers, options.headers),
1551
- serializedBody: void 0
1552
- };
1553
- if (opts.security) {
1554
- await setAuthParams(opts);
1555
- }
1556
- if (opts.requestValidator) {
1557
- await opts.requestValidator(opts);
1558
- }
1559
- if (opts.body !== void 0 && opts.bodySerializer) {
1560
- opts.serializedBody = opts.bodySerializer(opts.body);
1561
- }
1562
- if (opts.body === void 0 || opts.serializedBody === "") {
1563
- opts.headers.delete("Content-Type");
1564
- }
1565
- const resolvedOpts = opts;
1566
- const url = buildUrl(resolvedOpts);
1567
- return { opts: resolvedOpts, url };
1568
- }, "beforeRequest");
1569
- const request = /* @__PURE__ */ __name(async (options) => {
1570
- const throwOnError = options.throwOnError ?? _config.throwOnError;
1571
- const responseStyle = options.responseStyle ?? _config.responseStyle;
1572
- let request2;
1573
- let response;
1574
- try {
1575
- const { opts, url } = await beforeRequest(options);
1576
- const requestInit = {
1577
- redirect: "follow",
1578
- ...opts,
1579
- body: getValidRequestBody(opts)
1580
- };
1581
- request2 = new Request(url, requestInit);
1582
- for (const fn of interceptors.request.fns) {
1583
- if (fn) {
1584
- request2 = await fn(request2, opts);
1585
- }
1586
- }
1587
- const _fetch = opts.fetch;
1588
- response = await _fetch(request2);
1589
- for (const fn of interceptors.response.fns) {
1590
- if (fn) {
1591
- response = await fn(response, request2, opts);
1592
- }
1593
- }
1594
- const result = {
1595
- request: request2,
1596
- response
1597
- };
1598
- if (response.ok) {
1599
- const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
1600
- if (response.status === 204 || response.headers.get("Content-Length") === "0") {
1601
- let emptyData;
1602
- switch (parseAs) {
1603
- case "arrayBuffer":
1604
- case "blob":
1605
- case "text":
1606
- emptyData = await response[parseAs]();
1607
- break;
1608
- case "formData":
1609
- emptyData = new FormData();
1610
- break;
1611
- case "stream":
1612
- emptyData = response.body;
1613
- break;
1614
- case "json":
1615
- default:
1616
- emptyData = {};
1617
- break;
1618
- }
1619
- return opts.responseStyle === "data" ? emptyData : {
1620
- data: emptyData,
1621
- ...result
1622
- };
1623
- }
1624
- let data;
1625
- switch (parseAs) {
1626
- case "arrayBuffer":
1627
- case "blob":
1628
- case "formData":
1629
- case "text":
1630
- data = await response[parseAs]();
1631
- break;
1632
- case "json": {
1633
- const text = await response.text();
1634
- data = text ? JSON.parse(text) : {};
1635
- break;
1636
- }
1637
- case "stream":
1638
- return opts.responseStyle === "data" ? response.body : {
1639
- data: response.body,
1640
- ...result
1641
- };
1642
- }
1643
- if (parseAs === "json") {
1644
- if (opts.responseValidator) {
1645
- await opts.responseValidator(data);
1646
- }
1647
- if (opts.responseTransformer) {
1648
- data = await opts.responseTransformer(data);
1649
- }
1650
- }
1651
- return opts.responseStyle === "data" ? data : {
1652
- data,
1653
- ...result
1654
- };
1655
- }
1656
- const textError = await response.text();
1657
- let jsonError;
1658
- try {
1659
- jsonError = JSON.parse(textError);
1660
- } catch {
1661
- }
1662
- throw jsonError ?? textError;
1663
- } catch (error) {
1664
- let finalError = error;
1665
- for (const fn of interceptors.error.fns) {
1666
- if (fn) {
1667
- finalError = await fn(finalError, response, request2, options);
1668
- }
1669
- }
1670
- finalError = finalError || {};
1671
- if (throwOnError) {
1672
- throw finalError;
1673
- }
1674
- return responseStyle === "data" ? void 0 : {
1675
- error: finalError,
1676
- request: request2,
1677
- response
1678
- };
1679
- }
1680
- }, "request");
1681
- const makeMethodFn = /* @__PURE__ */ __name((method) => (options) => request({ ...options, method }), "makeMethodFn");
1682
- const makeSseFn = /* @__PURE__ */ __name((method) => async (options) => {
1683
- const { opts, url } = await beforeRequest(options);
1684
- return createSseClient({
1685
- ...opts,
1686
- body: opts.body,
1687
- method,
1688
- onRequest: /* @__PURE__ */ __name(async (url2, init) => {
1689
- let request2 = new Request(url2, init);
1690
- for (const fn of interceptors.request.fns) {
1691
- if (fn) {
1692
- request2 = await fn(request2, opts);
1693
- }
1694
- }
1695
- return request2;
1696
- }, "onRequest"),
1697
- serializedBody: getValidRequestBody(opts),
1698
- url
1699
- });
1700
- }, "makeSseFn");
1701
- const _buildUrl = /* @__PURE__ */ __name((options) => buildUrl({ ..._config, ...options }), "_buildUrl");
1702
- return {
1703
- buildUrl: _buildUrl,
1704
- connect: makeMethodFn("CONNECT"),
1705
- delete: makeMethodFn("DELETE"),
1706
- get: makeMethodFn("GET"),
1707
- getConfig,
1708
- head: makeMethodFn("HEAD"),
1709
- interceptors,
1710
- options: makeMethodFn("OPTIONS"),
1711
- patch: makeMethodFn("PATCH"),
1712
- post: makeMethodFn("POST"),
1713
- put: makeMethodFn("PUT"),
1714
- request,
1715
- setConfig,
1716
- sse: {
1717
- connect: makeSseFn("CONNECT"),
1718
- delete: makeSseFn("DELETE"),
1719
- get: makeSseFn("GET"),
1720
- head: makeSseFn("HEAD"),
1721
- options: makeSseFn("OPTIONS"),
1722
- patch: makeSseFn("PATCH"),
1723
- post: makeSseFn("POST"),
1724
- put: makeSseFn("PUT"),
1725
- trace: makeSseFn("TRACE")
1726
- },
1727
- trace: makeMethodFn("TRACE")
1728
- };
1729
- }, "createClient");
1730
-
1731
- // src/_api/generated/client.gen.ts
1732
- var client = createClient(createConfig({ baseUrl: "http://localhost:8000" }));
1733
- installAuthOnClient(client);
1734
-
1735
- // src/_api/generated/sdk.gen.ts
1736
- var CfgAccountsApiKey = class {
1737
- static {
1738
- __name(this, "CfgAccountsApiKey");
1739
- }
1740
- /**
1741
- * Get API key details
1742
- *
1743
- * Retrieve the current user's API key (masked) and metadata.
1744
- */
1745
- static cfgAccountsApiKeyRetrieve(options) {
1746
- return (options?.client ?? client).get({
1747
- security: [
1748
- { scheme: "bearer", type: "http" },
1749
- {
1750
- in: "cookie",
1751
- name: "sessionid",
1752
- type: "apiKey"
1753
- },
1754
- { name: "X-API-Key", type: "apiKey" }
1755
- ],
1756
- url: "/cfg/accounts/api-key/",
1757
- ...options
1758
- });
1759
- }
1760
- /**
1761
- * Regenerate API key
1762
- *
1763
- * Generate a new API key. The full key is returned only once.
1764
- */
1765
- static cfgAccountsApiKeyRegenerateCreate(options) {
1766
- return (options.client ?? client).post({
1767
- security: [
1768
- { scheme: "bearer", type: "http" },
1769
- {
1770
- in: "cookie",
1771
- name: "sessionid",
1772
- type: "apiKey"
1773
- },
1774
- { name: "X-API-Key", type: "apiKey" }
1775
- ],
1776
- url: "/cfg/accounts/api-key/regenerate/",
1777
- ...options,
1778
- headers: {
1779
- "Content-Type": "application/json",
1780
- ...options.headers
1781
- }
1782
- });
1783
- }
1784
- /**
1785
- * Reveal API key
1786
- *
1787
- * Return the current full API key WITHOUT rotating it. The same durable value every one of the user's agents uses — for the signed-in user to copy and paste into agent onboarding. Default GET stays masked; this is the explicit reveal action.
1788
- */
1789
- static cfgAccountsApiKeyRevealCreate(options) {
1790
- return (options.client ?? client).post({
1791
- security: [
1792
- { scheme: "bearer", type: "http" },
1793
- {
1794
- in: "cookie",
1795
- name: "sessionid",
1796
- type: "apiKey"
1797
- },
1798
- { name: "X-API-Key", type: "apiKey" }
1799
- ],
1800
- url: "/cfg/accounts/api-key/reveal/",
1801
- ...options,
1802
- headers: {
1803
- "Content-Type": "application/json",
1804
- ...options.headers
1805
- }
1806
- });
1807
- }
1808
- /**
1809
- * Test API key
1810
- *
1811
- * Test whether an API key is valid without consuming it.
1812
- */
1813
- static cfgAccountsApiKeyTestCreate(options) {
1814
- return (options.client ?? client).post({
1815
- security: [
1816
- { scheme: "bearer", type: "http" },
1817
- {
1818
- in: "cookie",
1819
- name: "sessionid",
1820
- type: "apiKey"
1821
- },
1822
- { name: "X-API-Key", type: "apiKey" }
1823
- ],
1824
- url: "/cfg/accounts/api-key/test/",
1825
- ...options,
1826
- headers: {
1827
- "Content-Type": "application/json",
1828
- ...options.headers
1829
- }
1830
- });
1831
- }
1832
- };
1833
- var CfgAccountsOauth = class {
1834
- static {
1835
- __name(this, "CfgAccountsOauth");
1836
- }
1837
- /**
1838
- * List OAuth connections
1839
- *
1840
- * Get all OAuth connections for the current user.
1841
- */
1842
- static cfgAccountsOauthConnectionsList(options) {
1843
- return (options?.client ?? client).get({
1844
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
1845
- url: "/cfg/accounts/oauth/connections/",
1846
- ...options
1847
- });
1848
- }
1849
- /**
1850
- * Disconnect OAuth provider
1851
- *
1852
- * Remove OAuth connection for the specified provider.
1853
- */
1854
- static cfgAccountsOauthDisconnectCreate(options) {
1855
- return (options.client ?? client).post({
1856
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
1857
- url: "/cfg/accounts/oauth/disconnect/",
1858
- ...options,
1859
- headers: {
1860
- "Content-Type": "application/json",
1861
- ...options.headers
1862
- }
1863
- });
1864
- }
1865
- /**
1866
- * Start GitHub OAuth
1867
- *
1868
- * Generate GitHub OAuth authorization URL. Redirect user to this URL to start authentication.
1869
- */
1870
- static cfgAccountsOauthGithubAuthorizeCreate(options) {
1871
- return (options?.client ?? client).post({
1872
- url: "/cfg/accounts/oauth/github/authorize/",
1873
- ...options,
1874
- headers: {
1875
- "Content-Type": "application/json",
1876
- ...options?.headers
1877
- }
1878
- });
1879
- }
1880
- /**
1881
- * Complete GitHub OAuth
1882
- *
1883
- * Exchange authorization code for JWT tokens. Call this after GitHub redirects back with code.
1884
- */
1885
- static cfgAccountsOauthGithubCallbackCreate(options) {
1886
- return (options.client ?? client).post({
1887
- url: "/cfg/accounts/oauth/github/callback/",
1888
- ...options,
1889
- headers: {
1890
- "Content-Type": "application/json",
1891
- ...options.headers
1892
- }
1893
- });
1894
- }
1895
- /**
1896
- * List OAuth providers
1897
- *
1898
- * Get list of available OAuth providers for authentication.
1899
- */
1900
- static cfgAccountsOauthProvidersRetrieve(options) {
1901
- return (options?.client ?? client).get({ url: "/cfg/accounts/oauth/providers/", ...options });
1902
- }
1903
- };
1904
- var CfgAccounts = class {
1905
- static {
1906
- __name(this, "CfgAccounts");
1907
- }
1908
- /**
1909
- * Request OTP code to email.
1910
- */
1911
- static cfgAccountsOtpRequestCreate(options) {
1912
- return (options.client ?? client).post({
1913
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
1914
- url: "/cfg/accounts/otp/request/",
1915
- ...options,
1916
- headers: {
1917
- "Content-Type": "application/json",
1918
- ...options.headers
1919
- }
1920
- });
1921
- }
1922
- /**
1923
- * Verify OTP code and return JWT tokens or 2FA session.
1924
- *
1925
- * If user has 2FA enabled:
1926
- * - Returns requires_2fa=True with session_id
1927
- * - Client must complete 2FA verification at /cfg/totp/verify/
1928
- *
1929
- * If user has no 2FA:
1930
- * - Returns JWT tokens and user data directly
1931
- */
1932
- static cfgAccountsOtpVerifyCreate(options) {
1933
- return (options.client ?? client).post({
1934
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
1935
- url: "/cfg/accounts/otp/verify/",
1936
- ...options,
1937
- headers: {
1938
- "Content-Type": "application/json",
1939
- ...options.headers
1940
- }
1941
- });
1942
- }
1943
- };
1944
- var CfgAccountsProfile = class {
1945
- static {
1946
- __name(this, "CfgAccountsProfile");
1947
- }
1948
- /**
1949
- * Get current user profile
1950
- *
1951
- * Retrieve the current authenticated user's profile information.
1952
- */
1953
- static cfgAccountsProfileRetrieve(options) {
1954
- return (options?.client ?? client).get({
1955
- security: [{ scheme: "bearer", type: "http" }, {
1956
- in: "cookie",
1957
- name: "sessionid",
1958
- type: "apiKey"
1959
- }],
1960
- url: "/cfg/accounts/profile/",
1961
- ...options
1962
- });
1963
- }
1964
- /**
1965
- * Upload user avatar
1966
- *
1967
- * Upload avatar image for the current authenticated user. Accepts multipart/form-data with 'avatar' field.
1968
- */
1969
- static cfgAccountsProfileAvatarCreate(options) {
1970
- return (options?.client ?? client).post({
1971
- ...formDataBodySerializer,
1972
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
1973
- url: "/cfg/accounts/profile/avatar/",
1974
- ...options,
1975
- headers: {
1976
- "Content-Type": null,
1977
- ...options?.headers
1978
- }
1979
- });
1980
- }
1981
- /**
1982
- * Delete user account
1983
- *
1984
- *
1985
- * Permanently delete the current user's account.
1986
- *
1987
- * This operation:
1988
- * - Deactivates the account (user cannot log in)
1989
- * - Anonymizes personal data (GDPR compliance)
1990
- * - Frees up the email address for re-registration
1991
- * - Preserves audit trail
1992
- *
1993
- * The account can be restored by an administrator if needed.
1994
- *
1995
- */
1996
- static cfgAccountsProfileDeleteCreate(options) {
1997
- return (options?.client ?? client).post({
1998
- security: [{ scheme: "bearer", type: "http" }, {
1999
- in: "cookie",
2000
- name: "sessionid",
2001
- type: "apiKey"
2002
- }],
2003
- url: "/cfg/accounts/profile/delete/",
2004
- ...options
2005
- });
2006
- }
2007
- /**
2008
- * Partial update user profile
2009
- *
2010
- * Partially update the current authenticated user's profile information. Supports avatar upload.
2011
- */
2012
- static cfgAccountsProfilePartialPartialUpdate(options) {
2013
- return (options?.client ?? client).patch({
2014
- security: [{ scheme: "bearer", type: "http" }, {
2015
- in: "cookie",
2016
- name: "sessionid",
2017
- type: "apiKey"
2018
- }],
2019
- url: "/cfg/accounts/profile/partial/",
2020
- ...options,
2021
- headers: {
2022
- "Content-Type": "application/json",
2023
- ...options?.headers
2024
- }
2025
- });
2026
- }
2027
- /**
2028
- * Partial update user profile
2029
- *
2030
- * Partially update the current authenticated user's profile information. Supports avatar upload.
2031
- */
2032
- static cfgAccountsProfilePartialUpdate(options) {
2033
- return (options?.client ?? client).put({
2034
- security: [{ scheme: "bearer", type: "http" }, {
2035
- in: "cookie",
2036
- name: "sessionid",
2037
- type: "apiKey"
2038
- }],
2039
- url: "/cfg/accounts/profile/partial/",
2040
- ...options,
2041
- headers: {
2042
- "Content-Type": "application/json",
2043
- ...options?.headers
2044
- }
2045
- });
2046
- }
2047
- /**
2048
- * Update user profile
2049
- *
2050
- * Update the current authenticated user's profile information.
2051
- */
2052
- static cfgAccountsProfileUpdatePartialUpdate(options) {
2053
- return (options?.client ?? client).patch({
2054
- security: [{ scheme: "bearer", type: "http" }, {
2055
- in: "cookie",
2056
- name: "sessionid",
2057
- type: "apiKey"
2058
- }],
2059
- url: "/cfg/accounts/profile/update/",
2060
- ...options,
2061
- headers: {
2062
- "Content-Type": "application/json",
2063
- ...options?.headers
2064
- }
2065
- });
2066
- }
2067
- /**
2068
- * Update user profile
2069
- *
2070
- * Update the current authenticated user's profile information.
2071
- */
2072
- static cfgAccountsProfileUpdateUpdate(options) {
2073
- return (options?.client ?? client).put({
2074
- security: [{ scheme: "bearer", type: "http" }, {
2075
- in: "cookie",
2076
- name: "sessionid",
2077
- type: "apiKey"
2078
- }],
2079
- url: "/cfg/accounts/profile/update/",
2080
- ...options,
2081
- headers: {
2082
- "Content-Type": "application/json",
2083
- ...options?.headers
2084
- }
2085
- });
2086
- }
2087
- };
2088
- var CfgAccountsAuth = class {
2089
- static {
2090
- __name(this, "CfgAccountsAuth");
2091
- }
2092
- /**
2093
- * Refresh JWT token.
2094
- *
2095
- * DPoP-aware: when the incoming refresh token is key-bound (`cnf.jkt`), the
2096
- * rotated access/refresh in the response are re-stamped with the same `cnf`
2097
- * (stock SimpleJWT drops it from the derived access), and a matching DPoP
2098
- * proof is required on the refresh request — so a stolen refresh token can't
2099
- * be used to mint fresh tokens.
2100
- */
2101
- static cfgAccountsTokenRefreshCreate(options) {
2102
- return (options.client ?? client).post({
2103
- url: "/cfg/accounts/token/refresh/",
2104
- ...options,
2105
- headers: {
2106
- "Content-Type": "application/json",
2107
- ...options.headers
2108
- }
2109
- });
2110
- }
2111
- };
2112
- var CfgCentrifugo = class {
2113
- static {
2114
- __name(this, "CfgCentrifugo");
2115
- }
2116
- /**
2117
- * Get Centrifugo connection token
2118
- *
2119
- * Generate JWT token for WebSocket connection to Centrifugo. Token includes user's allowed channels based on their permissions. Requires authentication.
2120
- */
2121
- static cfgCentrifugoAuthTokenRetrieve(options) {
2122
- return (options?.client ?? client).get({
2123
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
2124
- url: "/cfg/centrifugo/auth/token/",
2125
- ...options
2126
- });
2127
- }
2128
- };
2129
- var CfgTotpBackupCodes = class {
2130
- static {
2131
- __name(this, "CfgTotpBackupCodes");
2132
- }
2133
- /**
2134
- * Get backup codes status for user.
2135
- */
2136
- static cfgTotpBackupCodesRetrieve(options) {
2137
- return (options?.client ?? client).get({
2138
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
2139
- url: "/cfg/totp/backup-codes/",
2140
- ...options
2141
- });
2142
- }
2143
- /**
2144
- * Regenerate backup codes.
2145
- *
2146
- * Requires TOTP code for verification.
2147
- * Invalidates all existing codes.
2148
- */
2149
- static cfgTotpBackupCodesRegenerateCreate(options) {
2150
- return (options.client ?? client).post({
2151
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
2152
- url: "/cfg/totp/backup-codes/regenerate/",
2153
- ...options,
2154
- headers: {
2155
- "Content-Type": "application/json",
2156
- ...options.headers
2157
- }
2158
- });
2159
- }
2160
- };
2161
- var CfgTotp = class {
2162
- static {
2163
- __name(this, "CfgTotp");
2164
- }
2165
- /**
2166
- * List all TOTP devices for user.
2167
- */
2168
- static cfgTotpDevicesRetrieve(options) {
2169
- return (options?.client ?? client).get({
2170
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
2171
- url: "/cfg/totp/devices/",
2172
- ...options
2173
- });
2174
- }
2175
- /**
2176
- * Delete a TOTP device.
2177
- *
2178
- * Requires verification code if removing the last/primary device.
2179
- */
2180
- static cfgTotpDevicesDestroy(options) {
2181
- return (options.client ?? client).delete({
2182
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
2183
- url: "/cfg/totp/devices/{id}/",
2184
- ...options
2185
- });
2186
- }
2187
- /**
2188
- * Completely disable 2FA for account.
2189
- *
2190
- * Requires verification code.
2191
- */
2192
- static cfgTotpDisableCreate(options) {
2193
- return (options.client ?? client).post({
2194
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
2195
- url: "/cfg/totp/disable/",
2196
- ...options,
2197
- headers: {
2198
- "Content-Type": "application/json",
2199
- ...options.headers
2200
- }
2201
- });
2202
- }
2203
- };
2204
- var CfgTotpSetup = class {
2205
- static {
2206
- __name(this, "CfgTotpSetup");
2207
- }
2208
- /**
2209
- * Start 2FA setup process.
2210
- *
2211
- * Creates a new TOTP device and returns QR code for scanning.
2212
- */
2213
- static cfgTotpSetupCreate(options) {
2214
- return (options?.client ?? client).post({
2215
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
2216
- url: "/cfg/totp/setup/",
2217
- ...options,
2218
- headers: {
2219
- "Content-Type": "application/json",
2220
- ...options?.headers
2221
- }
2222
- });
2223
- }
2224
- /**
2225
- * Confirm 2FA setup with first valid code.
2226
- *
2227
- * Activates the device and generates backup codes.
2228
- */
2229
- static cfgTotpSetupConfirmCreate(options) {
2230
- return (options.client ?? client).post({
2231
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
2232
- url: "/cfg/totp/setup/confirm/",
2233
- ...options,
2234
- headers: {
2235
- "Content-Type": "application/json",
2236
- ...options.headers
2237
- }
2238
- });
2239
- }
2240
- };
2241
- var CfgTotpVerify = class {
2242
- static {
2243
- __name(this, "CfgTotpVerify");
2244
- }
2245
- /**
2246
- * Verify TOTP code for 2FA session.
2247
- *
2248
- * Completes authentication and returns JWT tokens on success.
2249
- */
2250
- static cfgTotpVerifyCreate(options) {
2251
- return (options.client ?? client).post({
2252
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
2253
- url: "/cfg/totp/verify/",
2254
- ...options,
2255
- headers: {
2256
- "Content-Type": "application/json",
2257
- ...options.headers
2258
- }
2259
- });
2260
- }
2261
- /**
2262
- * Verify backup recovery code for 2FA session.
2263
- *
2264
- * Alternative verification method when TOTP device unavailable.
2265
- */
2266
- static cfgTotpVerifyBackupCreate(options) {
2267
- return (options.client ?? client).post({
2268
- security: [{ name: "X-API-Key", type: "apiKey" }, { scheme: "bearer", type: "http" }],
2269
- url: "/cfg/totp/verify/backup/",
2270
- ...options,
2271
- headers: {
2272
- "Content-Type": "application/json",
2273
- ...options.headers
2274
- }
2275
- });
2276
- }
2277
- };
2278
-
2279
- // src/_api/generated/_cfg_accounts/api.ts
2280
- var API = class {
2281
- static {
2282
- __name(this, "API");
2283
- }
2284
- logger;
2285
- cfgAccountsApiKey = CfgAccountsApiKey;
2286
- cfgAccountsOauth = CfgAccountsOauth;
2287
- cfgAccounts = CfgAccounts;
2288
- cfgAccountsProfile = CfgAccountsProfile;
2289
- cfgAccountsAuth = CfgAccountsAuth;
2290
- constructor(_baseUrl, opts = {}) {
2291
- this.logger = new APILogger(opts.logger);
2292
- if (_baseUrl) auth.setBaseUrl(_baseUrl);
2293
- if (opts.locale !== void 0) auth.setLocale(opts.locale);
2294
- if (opts.apiKey !== void 0) auth.setApiKey(opts.apiKey);
2295
- if (opts.withCredentials !== void 0) auth.setWithCredentials(opts.withCredentials);
2296
- }
2297
- // ── Base URL ────────────────────────────────────────────────────────────
2298
- getBaseUrl() {
2299
- return auth.getBaseUrl();
2300
- }
2301
- setBaseUrl(url) {
2302
- auth.setBaseUrl(url);
2303
- }
2304
- // ── Tokens ──────────────────────────────────────────────────────────────
2305
- getToken() {
2306
- return auth.getToken();
2307
- }
2308
- setToken(token) {
2309
- auth.setToken(token);
2310
- }
2311
- getRefreshToken() {
2312
- return auth.getRefreshToken();
2313
- }
2314
- setRefreshToken(token) {
2315
- auth.setRefreshToken(token);
2316
- }
2317
- clearToken() {
2318
- auth.clearTokens();
2319
- }
2320
- isAuthenticated() {
2321
- return auth.isAuthenticated();
2322
- }
2323
- // ── Locale / API key ────────────────────────────────────────────────────
2324
- getLocale() {
2325
- return auth.getLocale();
2326
- }
2327
- setLocale(locale) {
2328
- auth.setLocale(locale);
2329
- }
2330
- getApiKey() {
2331
- return auth.getApiKey();
2332
- }
2333
- setApiKey(key) {
2334
- auth.setApiKey(key);
2335
- }
2336
- // ── 401 handling ────────────────────────────────────────────────────────
2337
- /** Fired only on terminal 401 (after refresh+retry path is exhausted). */
2338
- onUnauthorized(cb) {
2339
- auth.onUnauthorized(cb);
2340
- }
2341
- /** Provide a refresh strategy. See `auth.setRefreshHandler` for the contract. */
2342
- setRefreshHandler(fn) {
2343
- auth.setRefreshHandler(fn);
2344
- }
2345
- /**
2346
- * Proactively refresh now via the registered handler, sharing the single
2347
- * 401-recovery flight (rotation + dedup + rotated-token persistence).
2348
- * See `auth.refreshNow`.
2349
- */
2350
- refreshNow() {
2351
- return auth.refreshNow();
2352
- }
2353
- };
2354
-
2355
- // src/_api/generated/_cfg_centrifugo/api.ts
2356
- var API2 = class {
2357
- static {
2358
- __name(this, "API");
2359
- }
2360
- logger;
2361
- cfgCentrifugo = CfgCentrifugo;
2362
- constructor(_baseUrl, opts = {}) {
2363
- this.logger = new APILogger(opts.logger);
2364
- if (_baseUrl) auth.setBaseUrl(_baseUrl);
2365
- if (opts.locale !== void 0) auth.setLocale(opts.locale);
2366
- if (opts.apiKey !== void 0) auth.setApiKey(opts.apiKey);
2367
- if (opts.withCredentials !== void 0) auth.setWithCredentials(opts.withCredentials);
2368
- }
2369
- // ── Base URL ────────────────────────────────────────────────────────────
2370
- getBaseUrl() {
2371
- return auth.getBaseUrl();
2372
- }
2373
- setBaseUrl(url) {
2374
- auth.setBaseUrl(url);
2375
- }
2376
- // ── Tokens ──────────────────────────────────────────────────────────────
2377
- getToken() {
2378
- return auth.getToken();
2379
- }
2380
- setToken(token) {
2381
- auth.setToken(token);
2382
- }
2383
- getRefreshToken() {
2384
- return auth.getRefreshToken();
2385
- }
2386
- setRefreshToken(token) {
2387
- auth.setRefreshToken(token);
2388
- }
2389
- clearToken() {
2390
- auth.clearTokens();
2391
- }
2392
- isAuthenticated() {
2393
- return auth.isAuthenticated();
2394
- }
2395
- // ── Locale / API key ────────────────────────────────────────────────────
2396
- getLocale() {
2397
- return auth.getLocale();
2398
- }
2399
- setLocale(locale) {
2400
- auth.setLocale(locale);
2401
- }
2402
- getApiKey() {
2403
- return auth.getApiKey();
2404
- }
2405
- setApiKey(key) {
2406
- auth.setApiKey(key);
2407
- }
2408
- // ── 401 handling ────────────────────────────────────────────────────────
2409
- /** Fired only on terminal 401 (after refresh+retry path is exhausted). */
2410
- onUnauthorized(cb) {
2411
- auth.onUnauthorized(cb);
2412
- }
2413
- /** Provide a refresh strategy. See `auth.setRefreshHandler` for the contract. */
2414
- setRefreshHandler(fn) {
2415
- auth.setRefreshHandler(fn);
2416
- }
2417
- /**
2418
- * Proactively refresh now via the registered handler, sharing the single
2419
- * 401-recovery flight (rotation + dedup + rotated-token persistence).
2420
- * See `auth.refreshNow`.
2421
- */
2422
- refreshNow() {
2423
- return auth.refreshNow();
2424
- }
2425
- };
2426
-
2427
- // src/_api/generated/_cfg_totp/api.ts
2428
- var API3 = class {
2429
- static {
2430
- __name(this, "API");
2431
- }
2432
- logger;
2433
- cfgTotpBackupCodes = CfgTotpBackupCodes;
2434
- cfgTotp = CfgTotp;
2435
- cfgTotpSetup = CfgTotpSetup;
2436
- cfgTotpVerify = CfgTotpVerify;
2437
- constructor(_baseUrl, opts = {}) {
2438
- this.logger = new APILogger(opts.logger);
2439
- if (_baseUrl) auth.setBaseUrl(_baseUrl);
2440
- if (opts.locale !== void 0) auth.setLocale(opts.locale);
2441
- if (opts.apiKey !== void 0) auth.setApiKey(opts.apiKey);
2442
- if (opts.withCredentials !== void 0) auth.setWithCredentials(opts.withCredentials);
2443
- }
2444
- // ── Base URL ────────────────────────────────────────────────────────────
2445
- getBaseUrl() {
2446
- return auth.getBaseUrl();
2447
- }
2448
- setBaseUrl(url) {
2449
- auth.setBaseUrl(url);
2450
- }
2451
- // ── Tokens ──────────────────────────────────────────────────────────────
2452
- getToken() {
2453
- return auth.getToken();
2454
- }
2455
- setToken(token) {
2456
- auth.setToken(token);
2457
- }
2458
- getRefreshToken() {
2459
- return auth.getRefreshToken();
2460
- }
2461
- setRefreshToken(token) {
2462
- auth.setRefreshToken(token);
2463
- }
2464
- clearToken() {
2465
- auth.clearTokens();
2466
- }
2467
- isAuthenticated() {
2468
- return auth.isAuthenticated();
2469
- }
2470
- // ── Locale / API key ────────────────────────────────────────────────────
2471
- getLocale() {
2472
- return auth.getLocale();
2473
- }
2474
- setLocale(locale) {
2475
- auth.setLocale(locale);
2476
- }
2477
- getApiKey() {
2478
- return auth.getApiKey();
2479
- }
2480
- setApiKey(key) {
2481
- auth.setApiKey(key);
2482
- }
2483
- // ── 401 handling ────────────────────────────────────────────────────────
2484
- /** Fired only on terminal 401 (after refresh+retry path is exhausted). */
2485
- onUnauthorized(cb) {
2486
- auth.onUnauthorized(cb);
2487
- }
2488
- /** Provide a refresh strategy. See `auth.setRefreshHandler` for the contract. */
2489
- setRefreshHandler(fn) {
2490
- auth.setRefreshHandler(fn);
2491
- }
2492
- /**
2493
- * Proactively refresh now via the registered handler, sharing the single
2494
- * 401-recovery flight (rotation + dedup + rotated-token persistence).
2495
- * See `auth.refreshNow`.
2496
- */
2497
- refreshNow() {
2498
- return auth.refreshNow();
2499
- }
2500
- };
419
+ const router = useCfgRouter();
420
+ const isAllowedPath = isAllowedAuthPath(pathname, allowedPaths);
421
+ const queryOtp = queryParams.get("otp") || "";
422
+ const queryEmail = queryParams.get("email") || void 0;
423
+ const hasOTP = !!queryOtp;
424
+ const isReady = !!pathname && hasOTP && isAllowedPath;
425
+ const otpValid = queryOtp.length === AUTH_CONSTANTS.EMAIL_OTP_LENGTH;
426
+ const onOTPDetectedRef = useRef3(onOTPDetected);
427
+ onOTPDetectedRef.current = onOTPDetected;
428
+ useEffect3(() => {
429
+ if (!isReady || !otpValid) return;
430
+ authLogger.info("OTP detected in URL on auth page:", queryOtp);
431
+ onOTPDetectedRef.current?.(queryOtp, queryEmail);
432
+ }, [isReady, otpValid, queryOtp, queryEmail]);
433
+ useEffect3(() => {
434
+ if (!isReady || !cleanupUrl || !queryOtp) return;
435
+ const cleanQuery = Object.fromEntries(queryParams.entries());
436
+ delete cleanQuery.otp;
437
+ delete cleanQuery.email;
438
+ const queryString = new URLSearchParams(cleanQuery).toString();
439
+ const realPathname = typeof window !== "undefined" ? window.location.pathname : pathname;
440
+ router.replace(queryString ? `${realPathname}?${queryString}` : realPathname);
441
+ }, [isReady, cleanupUrl, queryOtp]);
442
+ return {
443
+ isReady,
444
+ hasOTP,
445
+ isAllowedPath
446
+ };
447
+ }, "useAutoAuth");
2501
448
 
2502
- // src/_api/generated/index.ts
2503
- var CfgAccountsApi = new API();
2504
- var CfgCentrifugoApi = new API2();
2505
- var CfgTotpApi = new API3();
449
+ // src/auth/hooks/useTwoFactor.ts
450
+ import { useCallback as useCallback4, useState as useState3 } from "react";
2506
451
 
2507
452
  // src/auth/utils/analytics.ts
2508
453
  var AnalyticsEvent = /* @__PURE__ */ ((AnalyticsEvent2) => {
@@ -2553,8 +498,7 @@ var useTwoFactor = /* @__PURE__ */ __name((options = {}) => {
2553
498
  setError(null);
2554
499
  }, []);
2555
500
  const handleSuccess = useCallback4((response) => {
2556
- CfgAccountsApi.setToken(response.access_token);
2557
- CfgAccountsApi.setRefreshToken(response.refresh_token);
501
+ auth.setSession({ access: response.access_token, refresh: response.refresh_token });
2558
502
  if (response.warning) {
2559
503
  setWarning(response.warning);
2560
504
  }
@@ -3035,8 +979,7 @@ var useGithubAuth = /* @__PURE__ */ __name((options = {}) => {
3035
979
  throw new Error("Invalid response from OAuth callback");
3036
980
  }
3037
981
  authLogger.info("GitHub OAuth successful, user:", response.user);
3038
- CfgAccountsApi.setToken(response.access);
3039
- CfgAccountsApi.setRefreshToken(response.refresh);
982
+ auth.setSession({ access: response.access, refresh: response.refresh });
3040
983
  Analytics.event("auth_login_success" /* AUTH_LOGIN_SUCCESS */, {
3041
984
  category: "auth" /* AUTH */,
3042
985
  label: "github"
@@ -3457,30 +1400,10 @@ var useAuthRedirectManager = /* @__PURE__ */ __name((options = {}) => {
3457
1400
  };
3458
1401
  }, "useAuthRedirectManager");
3459
1402
 
3460
- // src/auth/hooks/useAuthGuard.ts
3461
- import { useEffect as useEffect5, useState as useState8 } from "react";
3462
- var useAuthGuard = /* @__PURE__ */ __name((options = {}) => {
3463
- const { redirectTo = "/auth", requireAuth = true, saveRedirectUrl: shouldSaveUrl = true } = options;
3464
- const { isAuthenticated, isLoading, saveRedirectUrl } = useAuth();
3465
- const router = useCfgRouter();
3466
- const [isRedirecting, setIsRedirecting] = useState8(false);
3467
- useEffect5(() => {
3468
- if (!isLoading && requireAuth && !isAuthenticated && !isRedirecting) {
3469
- if (shouldSaveUrl && typeof window !== "undefined") {
3470
- const currentUrl = window.location.pathname + window.location.search;
3471
- saveRedirectUrl(currentUrl);
3472
- }
3473
- setIsRedirecting(true);
3474
- router.push(redirectTo);
3475
- }
3476
- }, [isAuthenticated, isLoading, router, redirectTo, requireAuth, isRedirecting, shouldSaveUrl, saveRedirectUrl]);
3477
- return { isAuthenticated, isLoading, isRedirecting };
3478
- }, "useAuthGuard");
3479
-
3480
1403
  // src/auth/hooks/useLocalStorage.ts
3481
- import { useState as useState9 } from "react";
1404
+ import { useState as useState8 } from "react";
3482
1405
  function useLocalStorage(key, initialValue) {
3483
- const [storedValue, setStoredValue] = useState9(() => {
1406
+ const [storedValue, setStoredValue] = useState8(() => {
3484
1407
  if (typeof window === "undefined") {
3485
1408
  return initialValue;
3486
1409
  }
@@ -3775,150 +1698,16 @@ function getCacheMetadata() {
3775
1698
  }
3776
1699
  __name(getCacheMetadata, "getCacheMetadata");
3777
1700
 
3778
- // src/auth/hooks/useTokenRefresh.ts
3779
- import { useCallback as useCallback9, useEffect as useEffect7 } from "react";
3780
-
3781
- // src/auth/refreshHandler.ts
3782
- var _registered = false;
3783
- function ensureRefreshHandler() {
3784
- if (_registered) return;
3785
- _registered = true;
3786
- CfgAccountsApi.setRefreshHandler(async (refresh) => {
3787
- const result = await CfgAccountsAuth.cfgAccountsTokenRefreshCreate({
3788
- body: { refresh },
3789
- throwOnError: true
3790
- });
3791
- const access = result.data?.access;
3792
- if (!access) {
3793
- authLogger.error("Refresh response missing access token");
3794
- return null;
3795
- }
3796
- return { access, refresh: result.data?.refresh ?? refresh };
3797
- });
3798
- authLogger.debug("Canonical refresh handler registered");
3799
- }
3800
- __name(ensureRefreshHandler, "ensureRefreshHandler");
3801
- function triggerRefresh() {
3802
- ensureRefreshHandler();
3803
- const maybe = CfgAccountsApi;
3804
- if (typeof maybe.refreshNow === "function") {
3805
- return maybe.refreshNow();
3806
- }
3807
- authLogger.warn("api.refreshNow() unavailable \u2014 run `make generate` to regenerate the client");
3808
- return Promise.resolve(null);
3809
- }
3810
- __name(triggerRefresh, "triggerRefresh");
3811
-
3812
- // src/auth/utils/jwt.ts
3813
- function decodeSegment(segment) {
3814
- try {
3815
- const base64 = segment.replace(/-/g, "+").replace(/_/g, "/");
3816
- if (typeof atob !== "function") return null;
3817
- const json = atob(base64);
3818
- return JSON.parse(json);
3819
- } catch {
3820
- return null;
3821
- }
3822
- }
3823
- __name(decodeSegment, "decodeSegment");
3824
- function getTokenExpiry(token) {
3825
- if (!token || typeof token !== "string") return null;
3826
- const parts = token.split(".");
3827
- if (parts.length !== 3) return null;
3828
- const payload = decodeSegment(parts[1]);
3829
- if (!payload || typeof payload !== "object") return null;
3830
- const exp = payload.exp;
3831
- if (typeof exp !== "number" || !Number.isFinite(exp)) return null;
3832
- return exp * 1e3;
3833
- }
3834
- __name(getTokenExpiry, "getTokenExpiry");
3835
- function isTokenExpired(token, skewMs = 0, now = Date.now()) {
3836
- const expiry = getTokenExpiry(token);
3837
- if (expiry === null) return true;
3838
- return expiry - skewMs <= now;
3839
- }
3840
- __name(isTokenExpired, "isTokenExpired");
3841
- function isTokenExpiringSoon(token, thresholdMs, now = Date.now()) {
3842
- const expiry = getTokenExpiry(token);
3843
- if (expiry === null) return false;
3844
- return expiry - now < thresholdMs;
3845
- }
3846
- __name(isTokenExpiringSoon, "isTokenExpiringSoon");
3847
-
3848
- // src/auth/hooks/useTokenRefresh.ts
3849
- var TOKEN_REFRESH_THRESHOLD_MS = 10 * 60 * 1e3;
3850
- var CHECK_INTERVAL_MS = 5 * 60 * 1e3;
3851
- function useTokenRefresh(options = {}) {
3852
- const { enabled = true, onRefresh, onRefreshError } = options;
3853
- const refreshToken = useCallback9(async () => {
3854
- if (!CfgAccountsApi.getRefreshToken()) {
3855
- authLogger.warn("No refresh token available");
3856
- return false;
3857
- }
3858
- authLogger.info("Refreshing token...");
3859
- try {
3860
- const newAccessToken = await triggerRefresh();
3861
- if (!newAccessToken) {
3862
- throw new Error("Token refresh failed");
3863
- }
3864
- authLogger.info("Token refreshed successfully");
3865
- onRefresh?.(newAccessToken);
3866
- return true;
3867
- } catch (error) {
3868
- authLogger.error("Token refresh error:", error);
3869
- onRefreshError?.(error instanceof Error ? error : new Error(String(error)));
3870
- return false;
3871
- }
3872
- }, [onRefresh, onRefreshError]);
3873
- const checkAndRefresh = useCallback9(async () => {
3874
- const token = CfgAccountsApi.getToken();
3875
- if (!token) return;
3876
- if (isTokenExpiringSoon(token, TOKEN_REFRESH_THRESHOLD_MS)) {
3877
- authLogger.info("Token expiring soon, refreshing proactively");
3878
- await refreshToken();
3879
- }
3880
- }, [refreshToken]);
3881
- useEffect7(() => {
3882
- if (!enabled) return;
3883
- checkAndRefresh();
3884
- const intervalId = setInterval(checkAndRefresh, CHECK_INTERVAL_MS);
3885
- return () => clearInterval(intervalId);
3886
- }, [enabled, checkAndRefresh]);
3887
- useEffect7(() => {
3888
- if (!enabled) return;
3889
- const handleFocus = /* @__PURE__ */ __name(() => {
3890
- authLogger.debug("Window focused, checking token...");
3891
- checkAndRefresh();
3892
- }, "handleFocus");
3893
- window.addEventListener("focus", handleFocus);
3894
- return () => window.removeEventListener("focus", handleFocus);
3895
- }, [enabled, checkAndRefresh]);
3896
- useEffect7(() => {
3897
- if (!enabled) return;
3898
- const handleOnline = /* @__PURE__ */ __name(() => {
3899
- authLogger.info("Network reconnected, checking token...");
3900
- checkAndRefresh();
3901
- }, "handleOnline");
3902
- window.addEventListener("online", handleOnline);
3903
- return () => window.removeEventListener("online", handleOnline);
3904
- }, [enabled, checkAndRefresh]);
3905
- return {
3906
- refreshToken,
3907
- checkAndRefresh
3908
- };
3909
- }
3910
- __name(useTokenRefresh, "useTokenRefresh");
3911
-
3912
1701
  // src/auth/hooks/useDeleteAccount.ts
3913
- import { useCallback as useCallback10, useState as useState10 } from "react";
1702
+ import { useCallback as useCallback9, useState as useState9 } from "react";
3914
1703
  var useDeleteAccount = /* @__PURE__ */ __name(() => {
3915
- const [isLoading, setIsLoading] = useState10(false);
3916
- const [error, setError] = useState10(null);
1704
+ const [isLoading, setIsLoading] = useState9(false);
1705
+ const [error, setError] = useState9(null);
3917
1706
  const { logout } = useAuth();
3918
- const clearError = useCallback10(() => {
1707
+ const clearError = useCallback9(() => {
3919
1708
  setError(null);
3920
1709
  }, []);
3921
- const deleteAccount = useCallback10(async () => {
1710
+ const deleteAccount = useCallback9(async () => {
3922
1711
  setIsLoading(true);
3923
1712
  setError(null);
3924
1713
  try {
@@ -3947,39 +1736,15 @@ var useDeleteAccount = /* @__PURE__ */ __name(() => {
3947
1736
  };
3948
1737
  }, "useDeleteAccount");
3949
1738
 
3950
- // src/auth/utils/guard.ts
3951
- function resolveGuardIsLoading(s) {
3952
- if (!s.mounted) return true;
3953
- if (!s.requireAuth) return false;
3954
- return s.authLoading || s.isRedirecting || !s.isAuthenticated;
3955
- }
3956
- __name(resolveGuardIsLoading, "resolveGuardIsLoading");
3957
- function shouldRedirectToAuth(s) {
3958
- return s.mounted && s.requireAuth && !s.authLoading && !s.isAuthenticated && !s.isRedirecting;
3959
- }
3960
- __name(shouldRedirectToAuth, "shouldRedirectToAuth");
3961
- function resolveGuardIsAuthenticated(s) {
3962
- return !s.requireAuth || s.isAuthenticated;
3963
- }
3964
- __name(resolveGuardIsAuthenticated, "resolveGuardIsAuthenticated");
3965
- function nextAuthEvaluationDelay(accessExp, refreshExp, now) {
3966
- const future = [accessExp, refreshExp].filter(
3967
- (d) => d !== null && d > now
3968
- );
3969
- if (future.length === 0) return null;
3970
- return Math.max(0, Math.min(...future) - now) + 1e3;
3971
- }
3972
- __name(nextAuthEvaluationDelay, "nextAuthEvaluationDelay");
3973
-
3974
1739
  // src/auth/context/AccountsContext.tsx
3975
1740
  import {
3976
1741
  createContext,
3977
- useCallback as useCallback11,
1742
+ useCallback as useCallback10,
3978
1743
  useContext,
3979
- useEffect as useEffect8,
1744
+ useEffect as useEffect6,
3980
1745
  useMemo as useMemo2,
3981
1746
  useRef as useRef5,
3982
- useState as useState11
1747
+ useState as useState10
3983
1748
  } from "react";
3984
1749
 
3985
1750
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsApiKeyRegenerateCreate.ts
@@ -4432,9 +2197,12 @@ function useCfgAccountsProfileUpdateUpdate(config) {
4432
2197
  }
4433
2198
  __name(useCfgAccountsProfileUpdateUpdate, "useCfgAccountsProfileUpdateUpdate");
4434
2199
 
4435
- // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenRefreshCreate.ts
2200
+ // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenBlacklistCreate.ts
4436
2201
  import useSWRMutation15 from "swr/mutation";
4437
2202
 
2203
+ // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenRefreshCreate.ts
2204
+ import useSWRMutation16 from "swr/mutation";
2205
+
4438
2206
  // src/_api/generated/_cfg_accounts/schemas/TokenRefresh.ts
4439
2207
  import { z as z19 } from "zod";
4440
2208
  var TokenRefreshSchema = z19.object({
@@ -4442,53 +2210,6 @@ var TokenRefreshSchema = z19.object({
4442
2210
  refresh: z19.string()
4443
2211
  });
4444
2212
 
4445
- // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenRefreshCreate.ts
4446
- function useCfgAccountsTokenRefreshCreate(config) {
4447
- return useSWRMutation15(
4448
- ["cfg_accounts_token_refresh_create"],
4449
- async (_key, { arg }) => {
4450
- const res = await CfgAccountsAuth.cfgAccountsTokenRefreshCreate({ ...arg, throwOnError: true });
4451
- const data = res.data;
4452
- const parsed = TokenRefreshSchema.safeParse(data);
4453
- if (!parsed.success) {
4454
- console.warn(
4455
- "[zod] response did not match schema",
4456
- {
4457
- operation: "cfg_accounts_token_refresh_create",
4458
- method: "POST",
4459
- path: "/cfg/accounts/token/refresh/",
4460
- issues: parsed.error.issues,
4461
- data
4462
- }
4463
- );
4464
- if (typeof window !== "undefined") {
4465
- try {
4466
- window.dispatchEvent(
4467
- new CustomEvent("zod-validation-error", {
4468
- detail: {
4469
- operation: "cfg_accounts_token_refresh_create",
4470
- method: "POST",
4471
- path: "/cfg/accounts/token/refresh/",
4472
- issues: parsed.error.issues,
4473
- data,
4474
- timestamp: /* @__PURE__ */ new Date()
4475
- },
4476
- bubbles: true,
4477
- cancelable: false
4478
- })
4479
- );
4480
- } catch {
4481
- }
4482
- }
4483
- return data;
4484
- }
4485
- return parsed.data;
4486
- },
4487
- config
4488
- );
4489
- }
4490
- __name(useCfgAccountsTokenRefreshCreate, "useCfgAccountsTokenRefreshCreate");
4491
-
4492
2213
  // src/_api/generated/_cfg_accounts/schemas/APIKeyRequest.ts
4493
2214
  import { z as z20 } from "zod";
4494
2215
  var APIKeyRequestSchema = z20.object({
@@ -4578,28 +2299,34 @@ var PatchedCfgUserUpdateRequestSchema = z30.object({
4578
2299
  timezone: z30.string().max(64).optional()
4579
2300
  });
4580
2301
 
4581
- // src/_api/generated/_cfg_accounts/schemas/TokenRefreshRequest.ts
2302
+ // src/_api/generated/_cfg_accounts/schemas/TokenBlacklistRequest.ts
4582
2303
  import { z as z31 } from "zod";
4583
- var TokenRefreshRequestSchema = z31.object({
2304
+ var TokenBlacklistRequestSchema = z31.object({
4584
2305
  refresh: z31.string().min(1)
4585
2306
  });
4586
2307
 
2308
+ // src/_api/generated/_cfg_accounts/schemas/TokenRefreshRequest.ts
2309
+ import { z as z32 } from "zod";
2310
+ var TokenRefreshRequestSchema = z32.object({
2311
+ refresh: z32.string().min(1)
2312
+ });
2313
+
4587
2314
  // src/auth/context/AccountsContext.tsx
4588
2315
  import { jsx } from "react/jsx-runtime";
4589
2316
  var AccountsContext = createContext(void 0);
4590
2317
  function AccountsProvider({ children }) {
4591
- const [profile, setProfile] = useState11(() => {
2318
+ const [profile, setProfile] = useState10(() => {
4592
2319
  const cached = getCachedProfile();
4593
2320
  return cached || void 0;
4594
2321
  });
4595
- const [isLoadingProfile, setIsLoadingProfile] = useState11(false);
4596
- const [profileError, setProfileError] = useState11(null);
2322
+ const [isLoadingProfile, setIsLoadingProfile] = useState10(false);
2323
+ const [profileError, setProfileError] = useState10(null);
4597
2324
  const profileRef = useRef5(profile);
4598
2325
  const isLoadingRef = useRef5(false);
4599
- useEffect8(() => {
2326
+ useEffect6(() => {
4600
2327
  profileRef.current = profile;
4601
2328
  }, [profile]);
4602
- useEffect8(() => {
2329
+ useEffect6(() => {
4603
2330
  isLoadingRef.current = isLoadingProfile;
4604
2331
  }, [isLoadingProfile]);
4605
2332
  const { trigger: triggerProfileUpdate } = useCfgAccountsProfileUpdateUpdate();
@@ -4607,8 +2334,7 @@ function AccountsProvider({ children }) {
4607
2334
  const { trigger: triggerAvatar } = useCfgAccountsProfileAvatarCreate();
4608
2335
  const { trigger: triggerOtpRequest } = useCfgAccountsOtpRequestCreate();
4609
2336
  const { trigger: triggerOtpVerify } = useCfgAccountsOtpVerifyCreate();
4610
- const { trigger: triggerTokenRefresh } = useCfgAccountsTokenRefreshCreate();
4611
- const refreshProfile = useCallback11(async (options) => {
2337
+ const refreshProfile = useCallback10(async (options) => {
4612
2338
  const { callerId, force } = options || {};
4613
2339
  if (isLoadingRef.current) {
4614
2340
  authLogger.debug(`Profile loading in progress, skipping (caller: ${callerId})`);
@@ -4660,8 +2386,7 @@ function AccountsProvider({ children }) {
4660
2386
  return result;
4661
2387
  }
4662
2388
  if (result.access && result.refresh) {
4663
- CfgAccountsApi.setToken(result.access);
4664
- CfgAccountsApi.setRefreshToken(result.refresh);
2389
+ auth.setSession({ access: result.access, refresh: result.refresh });
4665
2390
  try {
4666
2391
  await refreshProfile({ callerId: "verifyOTP", force: true });
4667
2392
  } catch (profileError2) {
@@ -4670,17 +2395,14 @@ function AccountsProvider({ children }) {
4670
2395
  }
4671
2396
  return result;
4672
2397
  }, "verifyOTP");
4673
- const refreshToken = /* @__PURE__ */ __name(async (refresh) => {
4674
- const body = { refresh };
4675
- const result = await triggerTokenRefresh({ body });
4676
- if (result.access) {
4677
- CfgAccountsApi.setToken(result.access);
4678
- CfgAccountsApi.setRefreshToken(refresh);
2398
+ const logout = useCallback10(() => {
2399
+ const refresh = auth.getRefreshToken();
2400
+ if (refresh) {
2401
+ CfgAccountsAuth.cfgAccountsTokenBlacklistCreate({ body: { refresh } }).catch(() => {
2402
+ authLogger.warn("Refresh-token blacklist failed (logged out locally anyway)");
2403
+ });
4679
2404
  }
4680
- return result;
4681
- }, "refreshToken");
4682
- const logout = useCallback11(() => {
4683
- CfgAccountsApi.clearToken();
2405
+ auth.clearSession();
4684
2406
  setProfile(void 0);
4685
2407
  setProfileError(null);
4686
2408
  clearProfileCache();
@@ -4695,7 +2417,6 @@ function AccountsProvider({ children }) {
4695
2417
  refreshProfile,
4696
2418
  requestOTP,
4697
2419
  verifyOTP,
4698
- refreshToken,
4699
2420
  logout
4700
2421
  }), [
4701
2422
  profile,
@@ -4707,7 +2428,6 @@ function AccountsProvider({ children }) {
4707
2428
  refreshProfile,
4708
2429
  requestOTP,
4709
2430
  verifyOTP,
4710
- refreshToken,
4711
2431
  logout
4712
2432
  ]);
4713
2433
  return /* @__PURE__ */ jsx(AccountsContext.Provider, { value, children });
@@ -4725,282 +2445,117 @@ __name(useAccountsContext, "useAccountsContext");
4725
2445
  // src/auth/context/AuthContext.tsx
4726
2446
  import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
4727
2447
  var defaultRoutes = {
4728
- auth: "/auth",
4729
- defaultCallback: "/dashboard",
4730
- defaultAuthCallback: "/auth"
2448
+ auth: DEFAULT_AUTH_PATH,
2449
+ defaultCallback: DEFAULT_CALLBACK_PATH,
2450
+ defaultAuthCallback: DEFAULT_AUTH_PATH
4731
2451
  };
4732
- var AuthContext = createContext2(void 0);
4733
2452
  var EMAIL_STORAGE_KEY = "auth_email";
4734
- var hasValidTokens = /* @__PURE__ */ __name(() => {
4735
- if (typeof window === "undefined") return false;
4736
- return CfgAccountsApi.isAuthenticated();
4737
- }, "hasValidTokens");
4738
- var isSessionDeadOnBootstrap = /* @__PURE__ */ __name((accessToken, refreshToken, now = Date.now()) => {
4739
- const accessDead = isTokenExpired(accessToken, 0, now);
4740
- if (!accessDead) return false;
4741
- const refreshDead = isTokenExpired(refreshToken, 0, now);
4742
- return refreshDead;
4743
- }, "isSessionDeadOnBootstrap");
4744
- var isSessionAlive = /* @__PURE__ */ __name((now = Date.now()) => {
4745
- if (typeof window === "undefined") return false;
4746
- return !isSessionDeadOnBootstrap(
4747
- CfgAccountsApi.getToken(),
4748
- CfgAccountsApi.getRefreshToken(),
4749
- now
4750
- );
4751
- }, "isSessionAlive");
2453
+ var AuthContext = createContext2(void 0);
2454
+ var apiErrorMessage = /* @__PURE__ */ __name((error) => {
2455
+ const body = error.response;
2456
+ return body?.error || body?.detail || body?.message || error.errorMessage;
2457
+ }, "apiErrorMessage");
4752
2458
  var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4753
2459
  const accounts = useAccountsContext();
4754
- ensureRefreshHandler();
2460
+ const session = useSession();
2461
+ const isAuthenticated = session.status === "authenticated";
2462
+ const router = useCfgRouter();
2463
+ const pathname = usePathname3();
2464
+ const queryParams = useQueryParams();
2465
+ const [storedEmail, setStoredEmail, clearStoredEmail] = useLocalStorage(
2466
+ EMAIL_STORAGE_KEY,
2467
+ null
2468
+ );
4755
2469
  const redirectManager = useAuthRedirectManager({
4756
2470
  fallbackUrl: config?.routes?.defaultCallback || defaultRoutes.defaultCallback,
4757
2471
  clearOnUse: true
4758
2472
  });
4759
- const [isLoading, setIsLoading] = useState12(() => {
4760
- if (typeof window !== "undefined") {
4761
- const hasTokens = hasValidTokens();
4762
- return !hasTokens;
4763
- }
4764
- return true;
4765
- });
4766
- const [initialized, setInitialized] = useState12(false);
4767
- const [authTick, setAuthTick] = useState12(0);
4768
- const bumpAuthTick = useCallback12(() => setAuthTick((t) => t + 1), []);
4769
- useEffect9(() => {
4770
- if (typeof window === "undefined") return;
4771
- const delay = nextAuthEvaluationDelay(
4772
- getTokenExpiry(CfgAccountsApi.getToken()),
4773
- getTokenExpiry(CfgAccountsApi.getRefreshToken()),
4774
- Date.now()
4775
- );
4776
- if (delay === null) return;
4777
- const timer = setTimeout(bumpAuthTick, Math.min(delay, 2e9));
4778
- return () => clearTimeout(timer);
4779
- }, [authTick, bumpAuthTick]);
4780
- const onUnauthorizedRef = useRef6(false);
4781
- const router = useCfgRouter();
4782
- const pathname = usePathname3();
4783
- const queryParams = useQueryParams();
4784
- const [storedEmail, setStoredEmail, clearStoredEmail] = useLocalStorage(EMAIL_STORAGE_KEY, null);
4785
- const user = accounts.profile;
4786
- const userRef = useRef6(user);
4787
2473
  const configRef = useRef6(config);
4788
- const isLoadingProfileRef = useRef6(false);
4789
- useEffect9(() => {
4790
- userRef.current = user;
4791
- }, [user]);
4792
- useEffect9(() => {
2474
+ useEffect7(() => {
4793
2475
  configRef.current = config;
4794
2476
  }, [config]);
4795
- const clearAuthState = useCallback12((caller) => {
4796
- authLogger.info("clearAuthState >> caller", caller);
4797
- CfgAccountsApi.clearToken();
4798
- clearProfileCache();
4799
- setInitialized(true);
4800
- setIsLoading(false);
4801
- bumpAuthTick();
4802
- }, [bumpAuthTick]);
4803
- const handleProactiveRefreshError = useCallback12((error) => {
4804
- authLogger.warn("Proactive token refresh failed \u2014 session is dead, redirecting to login:", error.message);
4805
- if (onUnauthorizedRef.current) return;
4806
- onUnauthorizedRef.current = true;
4807
- clearAuthState("proactiveRefresh:failed");
4808
- const authCallbackUrl = configRef.current?.routes?.defaultAuthCallback || defaultRoutes.defaultAuthCallback;
4809
- router.hardReplace(authCallbackUrl);
4810
- }, [clearAuthState, router]);
4811
- useTokenRefresh({
4812
- enabled: true,
4813
- onRefresh: /* @__PURE__ */ __name(() => {
4814
- authLogger.info("Token auto-refreshed successfully");
4815
- }, "onRefresh"),
4816
- onRefreshError: handleProactiveRefreshError
4817
- });
4818
- const handleGlobalAuthError = useCallback12((error, context = "API Request") => {
4819
- const isAuthError = error?.status === 401 || error?.statusCode === 401 || error?.code === "token_not_valid" || error?.code === "authentication_failed";
4820
- if (isAuthError) {
4821
- authLogger.warn(`Authentication error in ${context}, clearing tokens`);
4822
- clearAuthState(`globalAuthError:${context}`);
4823
- return true;
2477
+ const accountsRef = useRef6(accounts);
2478
+ useEffect7(() => {
2479
+ accountsRef.current = accounts;
2480
+ }, [accounts]);
2481
+ const [profileSettled, setProfileSettled] = useState11(false);
2482
+ const hasProfile = Boolean(accounts.profile);
2483
+ const profileAttemptedRef = useRef6(false);
2484
+ useEffect7(() => {
2485
+ if (!isAuthenticated) {
2486
+ profileAttemptedRef.current = false;
2487
+ if (auth.getToken() || auth.getRefreshToken()) {
2488
+ authLogger.warn("Dead session in storage \u2014 clearing");
2489
+ auth.clearSession();
2490
+ clearProfileCache();
2491
+ }
2492
+ setProfileSettled(true);
2493
+ return;
4824
2494
  }
4825
- if (error?.success === false) {
4826
- authLogger.warn(`Non-auth error in ${context} (not clearing session):`, error?.message || error);
2495
+ if (hasProfile || profileAttemptedRef.current) {
2496
+ setProfileSettled(true);
2497
+ return;
4827
2498
  }
4828
- return false;
4829
- }, [clearAuthState]);
4830
- useEffect9(() => {
4831
- const handler = /* @__PURE__ */ __name(() => {
4832
- if (onUnauthorizedRef.current) return;
4833
- onUnauthorizedRef.current = true;
4834
- authLogger.warn("Unrecoverable 401 (refresh failed) \u2014 clearing session and redirecting to login");
4835
- clearAuthState("onUnauthorized:401");
4836
- const authCallbackUrl = configRef.current?.routes?.defaultAuthCallback || defaultRoutes.defaultAuthCallback;
4837
- router.hardReplace(authCallbackUrl);
4838
- }, "handler");
4839
- CfgAccountsApi.onUnauthorized(handler);
2499
+ profileAttemptedRef.current = true;
2500
+ let cancelled = false;
2501
+ accountsRef.current.refreshProfile({ callerId: "AuthProvider:bootstrap" }).catch((error) => {
2502
+ authLogger.warn("Profile load failed (session kept):", error);
2503
+ }).finally(() => {
2504
+ if (!cancelled) setProfileSettled(true);
2505
+ });
4840
2506
  return () => {
4841
- CfgAccountsApi.onUnauthorized(null);
2507
+ cancelled = true;
4842
2508
  };
4843
- }, [clearAuthState, router]);
4844
- const isAutoLoggingOutRef = useRef6(false);
4845
- const swrOnError = useCallback12((error) => {
4846
- const isAuthError = error?.status === 401 || error?.statusCode === 401 || error?.code === "token_not_valid" || error?.code === "authentication_failed";
4847
- if (isAuthError && !isAutoLoggingOutRef.current) {
4848
- isAutoLoggingOutRef.current = true;
4849
- authLogger.warn("SWR 401 error detected, auto-logout");
4850
- clearAuthState("swrOnError:401");
2509
+ }, [isAuthenticated, hasProfile]);
2510
+ const isLoading = !profileSettled;
2511
+ const expiredHandledRef = useRef6(false);
2512
+ useEffect7(() => {
2513
+ const unsubscribe = auth.onSessionExpired(() => {
2514
+ if (expiredHandledRef.current) return;
2515
+ expiredHandledRef.current = true;
2516
+ authLogger.warn("Session expired (terminal 401) \u2014 redirecting to login");
2517
+ clearProfileCache();
2518
+ Analytics.event("auth_session_expired" /* AUTH_SESSION_EXPIRED */, {
2519
+ category: "auth" /* AUTH */
2520
+ });
4851
2521
  const authCallbackUrl = configRef.current?.routes?.defaultAuthCallback || defaultRoutes.defaultAuthCallback;
4852
2522
  router.hardReplace(authCallbackUrl);
4853
- }
4854
- }, [clearAuthState, router]);
4855
- const swrConfig = useMemo3(() => ({ onError: swrOnError }), [swrOnError]);
4856
- const loadCurrentProfile = useCallback12(async (callerId) => {
4857
- const finalCallerId = callerId || "AuthContext.loadCurrentProfile";
4858
- if (isLoadingProfileRef.current) {
4859
- authLogger.debug(`Profile loading already in progress, skipping duplicate call from: ${finalCallerId}`);
4860
- return;
4861
- }
4862
- authLogger.debug(`loadCurrentProfile called by: ${finalCallerId}`);
4863
- try {
4864
- isLoadingProfileRef.current = true;
4865
- const isAuth = CfgAccountsApi.isAuthenticated();
4866
- const token = CfgAccountsApi.getToken();
4867
- if (!isAuth) {
4868
- authLogger.warn("No valid authentication token, throwing error");
4869
- throw new Error("No valid authentication token");
4870
- }
4871
- if (accounts.profile && !accounts.isLoadingProfile) {
4872
- authLogger.debug("Profile already loaded in AccountsContext, skipping API call");
4873
- setInitialized(true);
4874
- return;
4875
- }
4876
- const refreshedProfile = await accounts.refreshProfile({ callerId: finalCallerId });
4877
- if (refreshedProfile) {
4878
- authLogger.info("Profile loaded successfully:", refreshedProfile.id);
4879
- } else {
4880
- authLogger.warn("Profile refresh returned undefined - but keeping tokens");
4881
- }
4882
- setInitialized(true);
4883
- } catch (error) {
4884
- authLogger.error("Failed to load profile:", error);
4885
- const isAuthError = error?.status === 401 || error?.statusCode === 401 || error?.code === "token_not_valid" || error?.code === "authentication_failed";
4886
- if (isAuthError) {
4887
- authLogger.warn("Authentication error, clearing session");
4888
- clearAuthState("loadCurrentProfile:authError");
4889
- } else {
4890
- authLogger.warn("Profile load failed but keeping session (non-auth error)");
4891
- setInitialized(true);
4892
- }
4893
- } finally {
4894
- isLoadingProfileRef.current = false;
4895
- }
4896
- }, [clearAuthState, handleGlobalAuthError, accounts]);
4897
- useEffect9(() => {
4898
- if (initialized) return;
4899
- const initializeAuth = /* @__PURE__ */ __name(async () => {
4900
- authLogger.info("Initializing auth...");
4901
- const isInIframe = typeof window !== "undefined" && window.self !== window.top;
4902
- authLogger.info("Is in iframe:", isInIframe);
4903
- const token = CfgAccountsApi.getToken();
4904
- const refreshToken2 = CfgAccountsApi.getRefreshToken();
4905
- authLogger.info("Token from API:", token ? `${token.substring(0, 20)}...` : "null");
4906
- authLogger.info("Refresh token from API:", refreshToken2 ? `${refreshToken2.substring(0, 20)}...` : "null");
4907
- authLogger.info("localStorage keys:", Object.keys(localStorage).filter((k) => k.includes("token") || k.includes("auth")));
4908
- if (!isInIframe && isSessionDeadOnBootstrap(token, refreshToken2)) {
4909
- authLogger.warn("Bootstrap: dead session in storage (access + refresh both unusable) \u2014 clearing and showing login");
4910
- clearAuthState("initializeAuth:deadSession");
4911
- return;
4912
- }
4913
- const hasTokens = hasValidTokens();
4914
- authLogger.info("Has tokens:", hasTokens);
4915
- if (userRef.current) {
4916
- authLogger.info("Profile already loaded from AccountsContext cache, skipping API request");
4917
- setInitialized(true);
4918
- setIsLoading(false);
4919
- return;
4920
- }
4921
- const cachedProfile = getCachedProfile();
4922
- if (cachedProfile) {
4923
- authLogger.info("Profile found in localStorage cache, skipping API request");
4924
- setInitialized(true);
4925
- setIsLoading(false);
4926
- return;
4927
- }
4928
- if (isInIframe && !hasTokens) {
4929
- authLogger.info("Running in iframe without tokens - waiting for parent to send via postMessage");
4930
- authLogger.info("AdminLayout will handle auth initialization, skipping AuthContext init");
4931
- setInitialized(true);
4932
- setIsLoading(false);
4933
- return;
4934
- }
4935
- if (hasTokens) {
4936
- setIsLoading(true);
4937
- try {
4938
- authLogger.info("No cached profile found, loading from API...");
4939
- await loadCurrentProfile("AuthContext.initializeAuth");
4940
- } catch (error) {
4941
- authLogger.error("Failed to load profile during initialization:", error);
4942
- const isAuthError = error?.status === 401 || error?.statusCode === 401 || error?.code === "token_not_valid" || error?.code === "authentication_failed";
4943
- if (isAuthError) {
4944
- clearAuthState("initializeAuth:authError");
4945
- } else {
4946
- authLogger.warn("Init profile load failed but keeping session");
4947
- setInitialized(true);
4948
- }
4949
- }
4950
- setIsLoading(false);
4951
- } else {
4952
- setInitialized(true);
4953
- setIsLoading(false);
4954
- }
4955
- }, "initializeAuth");
4956
- initializeAuth();
4957
- }, [initialized]);
4958
- useEffect9(() => {
4959
- if (!initialized) return;
4960
- const isAuthenticated = CfgAccountsApi.isAuthenticated();
2523
+ });
2524
+ return unsubscribe;
2525
+ }, [router]);
2526
+ useEffect7(() => {
2527
+ if (!isAuthenticated) return;
4961
2528
  const authRoute = config?.routes?.auth || defaultRoutes.auth;
4962
- const isAuthPage = pathname === authRoute;
4963
- const flowParam = queryParams.get("flow");
4964
- if (isAuthenticated && isAuthPage && !flowParam) {
4965
- const callbackUrl = config?.routes?.defaultCallback || defaultRoutes.defaultCallback;
4966
- router.push(callbackUrl);
2529
+ if (pathname === authRoute && !queryParams.get("flow")) {
2530
+ router.push(config?.routes?.defaultCallback || defaultRoutes.defaultCallback);
4967
2531
  }
4968
- }, [initialized, pathname, queryParams, config?.routes]);
4969
- const pushToDefaultCallbackUrl = useCallback12(() => {
4970
- const callbackUrl = config?.routes?.defaultCallback || defaultRoutes.defaultCallback;
4971
- router.push(callbackUrl);
4972
- }, [config?.routes, router]);
4973
- const pushToDefaultAuthCallbackUrl = useCallback12(() => {
4974
- const authCallbackUrl = config?.routes?.defaultAuthCallback || defaultRoutes.defaultAuthCallback;
4975
- router.push(authCallbackUrl);
4976
- }, [config?.routes, router]);
4977
- const checkAuthAndRedirect = useCallback12(async () => {
4978
- try {
4979
- setIsLoading(true);
4980
- const isAuthenticated = CfgAccountsApi.isAuthenticated();
4981
- if (isAuthenticated) {
4982
- await loadCurrentProfile();
4983
- if (userRef.current) {
4984
- pushToDefaultCallbackUrl();
4985
- }
4986
- } else {
4987
- pushToDefaultAuthCallbackUrl();
4988
- }
4989
- } catch (error) {
4990
- authLogger.error("Failed to check authentication:", error);
4991
- if (!handleGlobalAuthError(error, "checkAuthAndRedirect")) {
4992
- clearAuthState("checkAuthAndRedirect");
2532
+ }, [isAuthenticated, pathname, queryParams, config?.routes, router]);
2533
+ const loadCurrentProfile = useCallback11(async (callerId) => {
2534
+ if (!auth.isAuthenticated()) {
2535
+ throw new Error("No valid authentication token");
2536
+ }
2537
+ await accountsRef.current.refreshProfile({
2538
+ callerId: callerId || "AuthContext.loadCurrentProfile"
2539
+ });
2540
+ }, []);
2541
+ const checkAuthAndRedirect = useCallback11(async () => {
2542
+ const routes = configRef.current?.routes;
2543
+ if (auth.isAuthenticated()) {
2544
+ try {
2545
+ await loadCurrentProfile("checkAuthAndRedirect");
2546
+ } catch (error) {
2547
+ authLogger.warn("checkAuthAndRedirect: profile load failed", error);
4993
2548
  }
4994
- pushToDefaultAuthCallbackUrl();
4995
- } finally {
4996
- setIsLoading(false);
2549
+ router.push(routes?.defaultCallback || defaultRoutes.defaultCallback);
2550
+ } else {
2551
+ router.push(routes?.defaultAuthCallback || defaultRoutes.defaultAuthCallback);
4997
2552
  }
4998
- }, [loadCurrentProfile, clearAuthState, pushToDefaultCallbackUrl, pushToDefaultAuthCallbackUrl, handleGlobalAuthError]);
4999
- const requestOTP = useCallback12(
2553
+ }, [loadCurrentProfile, router]);
2554
+ const requestOTP = useCallback11(
5000
2555
  async (identifier, sourceUrl) => {
5001
- CfgAccountsApi.clearToken();
2556
+ auth.clearSession();
5002
2557
  try {
5003
- const result = await accounts.requestOTP({
2558
+ const result = await accountsRef.current.requestOTP({
5004
2559
  identifier,
5005
2560
  source_url: sourceUrl
5006
2561
  });
@@ -5010,33 +2565,30 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
5010
2565
  });
5011
2566
  return {
5012
2567
  success: true,
5013
- message: result.message || `OTP code sent to your email address`,
2568
+ message: result.message || "OTP code sent to your email address",
5014
2569
  webmail: result.webmail ?? null
5015
2570
  };
5016
2571
  } catch (error) {
5017
2572
  authLogger.error("Request OTP error:", error);
5018
2573
  if (error instanceof APIError) {
5019
- const retryAfter = error.response?.retry_after ?? error.response?.retryAfter;
5020
- const message = error.response?.error || error.response?.detail || error.response?.message || error.errorMessage;
2574
+ const body = error.response;
2575
+ const retryAfter = body?.retry_after ?? body?.retryAfter;
5021
2576
  return {
5022
2577
  success: false,
5023
2578
  statusCode: error.statusCode,
5024
- message,
2579
+ message: apiErrorMessage(error),
5025
2580
  retryAfter: typeof retryAfter === "number" ? retryAfter : void 0
5026
2581
  };
5027
2582
  }
5028
- return {
5029
- success: false,
5030
- message: "Failed to send OTP"
5031
- };
2583
+ return { success: false, message: "Failed to send OTP" };
5032
2584
  }
5033
2585
  },
5034
- [accounts]
2586
+ []
5035
2587
  );
5036
- const verifyOTP = useCallback12(
2588
+ const verifyOTP = useCallback11(
5037
2589
  async (identifier, otpCode, sourceUrl, redirectUrl, skipRedirect) => {
5038
2590
  try {
5039
- const result = await accounts.verifyOTP({
2591
+ const result = await accountsRef.current.verifyOTP({
5040
2592
  identifier,
5041
2593
  otp: otpCode,
5042
2594
  source_url: sourceUrl
@@ -5053,15 +2605,11 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
5053
2605
  }
5054
2606
  if (!result.access || !result.refresh) {
5055
2607
  authLogger.error("Verify OTP returned invalid response:", result);
5056
- return {
5057
- success: false,
5058
- message: "Invalid OTP verification response"
5059
- };
2608
+ return { success: false, message: "Invalid OTP verification response" };
5060
2609
  }
5061
2610
  if (identifier.includes("@")) {
5062
2611
  setStoredEmail(identifier);
5063
2612
  }
5064
- await new Promise((resolve) => setTimeout(resolve, 200));
5065
2613
  Analytics.event("auth_login_success" /* AUTH_LOGIN_SUCCESS */, {
5066
2614
  category: "auth" /* AUTH */,
5067
2615
  label: "email"
@@ -5071,7 +2619,7 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
5071
2619
  }
5072
2620
  if (!skipRedirect) {
5073
2621
  const savedRedirect = redirectManager.useAndClearRedirect();
5074
- const finalRedirectUrl = redirectUrl || savedRedirect || config?.routes?.defaultCallback || defaultRoutes.defaultCallback;
2622
+ const finalRedirectUrl = redirectUrl || savedRedirect || configRef.current?.routes?.defaultCallback || defaultRoutes.defaultCallback;
5075
2623
  authLogger.info("Redirecting after auth to:", finalRedirectUrl);
5076
2624
  router.hardPush(finalRedirectUrl);
5077
2625
  }
@@ -5088,96 +2636,62 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
5088
2636
  label: "email"
5089
2637
  });
5090
2638
  if (error instanceof APIError) {
5091
- const message = error.response?.error || error.response?.detail || error.response?.message || error.errorMessage;
5092
- return { success: false, message };
2639
+ return { success: false, message: apiErrorMessage(error) };
5093
2640
  }
5094
- return {
5095
- success: false,
5096
- message: "Failed to verify OTP"
5097
- };
2641
+ return { success: false, message: "Failed to verify OTP" };
5098
2642
  }
5099
2643
  },
5100
- [setStoredEmail, config?.routes?.defaultCallback, accounts, router]
2644
+ [setStoredEmail, redirectManager, router]
5101
2645
  );
5102
- const refreshToken = useCallback12(async () => {
5103
- try {
5104
- const refreshTokenValue = CfgAccountsApi.getRefreshToken();
5105
- if (!refreshTokenValue) {
5106
- clearAuthState("refreshToken:noToken");
5107
- Analytics.event("auth_session_expired" /* AUTH_SESSION_EXPIRED */, {
5108
- category: "auth" /* AUTH */
5109
- });
5110
- return {
5111
- success: false,
5112
- message: "No refresh token available"
5113
- };
5114
- }
5115
- await accounts.refreshToken(refreshTokenValue);
2646
+ const refreshToken = useCallback11(async () => {
2647
+ const access = await auth.refreshNow();
2648
+ if (access) {
5116
2649
  Analytics.event("auth_token_refresh" /* AUTH_TOKEN_REFRESH */, {
5117
2650
  category: "auth" /* AUTH */
5118
2651
  });
5119
- return {
5120
- success: true,
5121
- message: "Token refreshed"
5122
- };
5123
- } catch (error) {
5124
- authLogger.error("Refresh token error:", error);
5125
- clearAuthState("refreshToken:error");
5126
- Analytics.event("auth_token_refresh_fail" /* AUTH_TOKEN_REFRESH_FAIL */, {
5127
- category: "auth" /* AUTH */
5128
- });
5129
- return {
5130
- success: false,
5131
- message: "Error refreshing token"
5132
- };
2652
+ return { success: true, message: "Token refreshed" };
5133
2653
  }
5134
- }, [clearAuthState, accounts]);
5135
- const logout = useCallback12(() => {
2654
+ Analytics.event("auth_token_refresh_fail" /* AUTH_TOKEN_REFRESH_FAIL */, {
2655
+ category: "auth" /* AUTH */
2656
+ });
2657
+ return { success: false, message: "Error refreshing token" };
2658
+ }, []);
2659
+ const logout = useCallback11(() => {
5136
2660
  Analytics.event("auth_logout" /* AUTH_LOGOUT */, {
5137
2661
  category: "auth" /* AUTH */
5138
2662
  });
5139
- accounts.logout();
5140
- setInitialized(true);
5141
- setIsLoading(false);
5142
- const authCallbackUrl = config?.routes?.defaultAuthCallback || defaultRoutes.defaultAuthCallback;
2663
+ accountsRef.current.logout();
2664
+ const authCallbackUrl = configRef.current?.routes?.defaultAuthCallback || defaultRoutes.defaultAuthCallback;
5143
2665
  router.hardReplace(authCallbackUrl);
5144
- }, [accounts, config?.routes?.defaultAuthCallback, router]);
5145
- const isAdminUser = useMemo3(() => {
5146
- return Boolean(user?.is_staff || user?.is_superuser);
5147
- }, [user]);
5148
- useEffect9(() => {
2666
+ }, [router]);
2667
+ const user = accounts.profile ?? null;
2668
+ const isAdminUser = Boolean(user?.is_staff || user?.is_superuser);
2669
+ useEffect7(() => {
5149
2670
  applyRoleLogPolicy({ isAdmin: isAdminUser });
5150
2671
  }, [isAdminUser]);
5151
- const updateProfile = useCallback12(
2672
+ const updateProfile = useCallback11(
5152
2673
  async (data) => {
5153
- const result = await accounts.partialUpdateProfile(data);
5154
- return result;
5155
- },
5156
- [accounts]
5157
- );
5158
- const uploadAvatar = useCallback12(
5159
- async (avatar) => {
5160
- const result = await accounts.uploadAvatar(avatar);
2674
+ const result = await accountsRef.current.partialUpdateProfile(data);
5161
2675
  return result;
5162
2676
  },
5163
- [accounts]
2677
+ []
5164
2678
  );
2679
+ const uploadAvatar = useCallback11(async (avatar) => {
2680
+ const result = await accountsRef.current.uploadAvatar(avatar);
2681
+ return result;
2682
+ }, []);
5165
2683
  const value = useMemo3(
5166
2684
  () => ({
5167
2685
  user,
5168
2686
  isLoading,
5169
- // Authenticated iff the session is locally alive (access valid OR a usable
5170
- // refresh token) — validated by `exp`, NOT by mere token presence. This is
5171
- // what makes the guard self-sufficient: an expired session reads as
5172
- // unauthenticated WITHOUT waiting for a server 401 (which CSP / a hung
5173
- // request / offline can swallow). `authTick` (in deps) forces recompute
5174
- // after tokens are cleared/set, since token state lives in storage.
5175
- isAuthenticated: isSessionAlive(),
2687
+ // Reactive: flips via the store snapshot (token writes, refreshes,
2688
+ // expiry timer, cross-tab/cross-store sync) — no ticks, no polling.
2689
+ isAuthenticated,
5176
2690
  isAdminUser,
5177
2691
  loadCurrentProfile,
5178
2692
  checkAuthAndRedirect,
5179
- getToken: /* @__PURE__ */ __name(() => CfgAccountsApi.getToken(), "getToken"),
5180
- getRefreshToken: /* @__PURE__ */ __name(() => CfgAccountsApi.getRefreshToken(), "getRefreshToken"),
2693
+ getToken: /* @__PURE__ */ __name(() => auth.getToken(), "getToken"),
2694
+ getRefreshToken: /* @__PURE__ */ __name(() => auth.getRefreshToken(), "getRefreshToken"),
5181
2695
  getSavedEmail: /* @__PURE__ */ __name(() => storedEmail, "getSavedEmail"),
5182
2696
  saveEmail: setStoredEmail,
5183
2697
  clearSavedEmail: clearStoredEmail,
@@ -5185,20 +2699,17 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
5185
2699
  verifyOTP,
5186
2700
  refreshToken,
5187
2701
  logout,
5188
- // Redirect URL methods
5189
2702
  saveRedirectUrl: redirectManager.setRedirect,
5190
2703
  getRedirectUrl: redirectManager.getFinalRedirectUrl,
5191
2704
  clearRedirectUrl: redirectManager.clearRedirect,
5192
2705
  hasRedirectUrl: redirectManager.hasRedirect,
5193
- // Profile management
5194
2706
  updateProfile,
5195
2707
  uploadAvatar
5196
2708
  }),
5197
2709
  [
5198
2710
  user,
5199
2711
  isLoading,
5200
- authTick,
5201
- // recompute isAuthenticated when tokens are cleared/set
2712
+ isAuthenticated,
5202
2713
  isAdminUser,
5203
2714
  loadCurrentProfile,
5204
2715
  checkAuthAndRedirect,
@@ -5214,7 +2725,7 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
5214
2725
  uploadAvatar
5215
2726
  ]
5216
2727
  );
5217
- return /* @__PURE__ */ jsx2(AuthContext.Provider, { value, children: /* @__PURE__ */ jsx2(SWRConfig, { value: swrConfig, children }) });
2728
+ return /* @__PURE__ */ jsx2(AuthContext.Provider, { value, children });
5218
2729
  }, "AuthProviderInternal");
5219
2730
  function AuthProviderRaw({ children, config, enabled = true }) {
5220
2731
  if (!enabled) return /* @__PURE__ */ jsx2(Fragment, { children });
@@ -5253,12 +2764,12 @@ var defaultAuthState = {
5253
2764
  authLogger.warn("useAuth: refreshToken called outside AuthProvider");
5254
2765
  return { success: false, message: "AuthProvider not available" };
5255
2766
  }, "refreshToken"),
5256
- logout: /* @__PURE__ */ __name(async (_options) => {
2767
+ logout: /* @__PURE__ */ __name(() => {
5257
2768
  authLogger.warn("useAuth: logout called outside AuthProvider");
5258
2769
  }, "logout"),
5259
2770
  saveRedirectUrl: /* @__PURE__ */ __name(() => {
5260
2771
  }, "saveRedirectUrl"),
5261
- getRedirectUrl: /* @__PURE__ */ __name(() => null, "getRedirectUrl"),
2772
+ getRedirectUrl: /* @__PURE__ */ __name(() => "", "getRedirectUrl"),
5262
2773
  clearRedirectUrl: /* @__PURE__ */ __name(() => {
5263
2774
  }, "clearRedirectUrl"),
5264
2775
  hasRedirectUrl: /* @__PURE__ */ __name(() => false, "hasRedirectUrl"),
@@ -5305,6 +2816,22 @@ var formatAuthError = /* @__PURE__ */ __name((error) => {
5305
2816
  }
5306
2817
  return "An unexpected error occurred";
5307
2818
  }, "formatAuthError");
2819
+
2820
+ // src/auth/utils/guard.ts
2821
+ function resolveGuardIsLoading(s) {
2822
+ if (!s.mounted) return true;
2823
+ if (!s.requireAuth) return false;
2824
+ return s.authLoading || s.isRedirecting || !s.isAuthenticated;
2825
+ }
2826
+ __name(resolveGuardIsLoading, "resolveGuardIsLoading");
2827
+ function shouldRedirectToAuth(s) {
2828
+ return s.mounted && s.requireAuth && !s.authLoading && !s.isAuthenticated && !s.isRedirecting;
2829
+ }
2830
+ __name(shouldRedirectToAuth, "shouldRedirectToAuth");
2831
+ function resolveGuardIsAuthenticated(s) {
2832
+ return !s.requireAuth || s.isAuthenticated;
2833
+ }
2834
+ __name(resolveGuardIsAuthenticated, "resolveGuardIsAuthenticated");
5308
2835
  export {
5309
2836
  AUTH_CONSTANTS,
5310
2837
  AccountsProvider,
@@ -5313,6 +2840,8 @@ export {
5313
2840
  AnalyticsEvent,
5314
2841
  AuthContext_default as AuthContext,
5315
2842
  AuthProvider,
2843
+ DEFAULT_AUTH_PATH,
2844
+ DEFAULT_CALLBACK_PATH,
5316
2845
  PatchedCfgUserUpdateRequestSchema,
5317
2846
  authLogger,
5318
2847
  clearProfileCache,
@@ -5321,13 +2850,9 @@ export {
5321
2850
  formatAuthError,
5322
2851
  getCacheMetadata,
5323
2852
  getCachedProfile,
5324
- getTokenExpiry,
5325
2853
  hasValidCache,
5326
2854
  isAllowedAuthPath,
5327
- isTokenExpired,
5328
- isTokenExpiringSoon,
5329
2855
  logger,
5330
- nextAuthEvaluationDelay,
5331
2856
  normalizePath,
5332
2857
  resolveGuardIsAuthenticated,
5333
2858
  resolveGuardIsLoading,
@@ -5337,7 +2862,6 @@ export {
5337
2862
  useAuth,
5338
2863
  useAuthForm,
5339
2864
  useAuthFormState,
5340
- useAuthGuard,
5341
2865
  useAuthRedirectManager,
5342
2866
  useAuthValidation,
5343
2867
  useAutoAuth,
@@ -5347,8 +2871,8 @@ export {
5347
2871
  useGithubAuth,
5348
2872
  useLocalStorage,
5349
2873
  useQueryParams,
2874
+ useSession,
5350
2875
  useSessionStorage,
5351
- useTokenRefresh,
5352
2876
  useTwoFactor,
5353
2877
  useTwoFactorSetup,
5354
2878
  useTwoFactorStatus,