@djangocfg/api 2.1.582 → 2.1.583

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 (41) hide show
  1. package/README.md +18 -0
  2. package/dist/auth.cjs +272 -80
  3. package/dist/auth.cjs.map +1 -1
  4. package/dist/auth.mjs +272 -80
  5. package/dist/auth.mjs.map +1 -1
  6. package/dist/clients.cjs +243 -54
  7. package/dist/clients.cjs.map +1 -1
  8. package/dist/clients.mjs +243 -54
  9. package/dist/clients.mjs.map +1 -1
  10. package/dist/hooks.cjs +243 -54
  11. package/dist/hooks.cjs.map +1 -1
  12. package/dist/hooks.mjs +243 -54
  13. package/dist/hooks.mjs.map +1 -1
  14. package/dist/index.cjs +248 -54
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +85 -1
  17. package/dist/index.d.ts +85 -1
  18. package/dist/index.mjs +248 -54
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/storage.cjs +269 -0
  21. package/dist/storage.cjs.map +1 -0
  22. package/dist/storage.d.cts +85 -0
  23. package/dist/storage.d.ts +85 -0
  24. package/dist/storage.mjs +248 -0
  25. package/dist/storage.mjs.map +1 -0
  26. package/package.json +8 -2
  27. package/src/__tests__/noStorageLiterals.test.ts +27 -0
  28. package/src/__tests__/storage.test.ts +134 -0
  29. package/src/__tests__/storageSsr.test.ts +14 -0
  30. package/src/_api/generated/helpers/auth.ts +27 -64
  31. package/src/_api/generated/helpers/index.ts +12 -0
  32. package/src/_api/generated/helpers/keys.ts +328 -0
  33. package/src/auth/__tests__/authRedirect.test.ts +1 -1
  34. package/src/auth/__tests__/profileCache.test.ts +1 -1
  35. package/src/auth/context/AuthContext.tsx +2 -1
  36. package/src/auth/hooks/useAuthRedirect.ts +3 -2
  37. package/src/auth/hooks/useGithubAuth.ts +13 -8
  38. package/src/auth/hooks/useLocalStorage.ts +7 -7
  39. package/src/auth/hooks/useProfileCache.ts +2 -1
  40. package/src/auth/hooks/useSessionStorage.ts +7 -7
  41. package/src/storage.ts +21 -0
package/README.md CHANGED
@@ -102,6 +102,24 @@ valid, so the auth form cannot fix it, and redirecting would loop on the saved
102
102
  URL. Render a distinct "not authorised" state instead. `resolveGuardIsLoading`
103
103
  returns `false` once forbidden, so the preloader never spins on it.
104
104
 
105
+ ## Storage keys
106
+
107
+ Every browser-storage key is `cfg.<area>.<name>` (framework) or
108
+ `<owner>.<area>.<name>` (app). Use the registry, never a literal or raw `localStorage`:
109
+
110
+ ```ts
111
+ import { CFG_KEYS, cfgStorage, createStorage } from '@djangocfg/api/storage';
112
+
113
+ cfgStorage.read(CFG_KEYS.email.key);
114
+ cfgStorage.clearAll(); // sign-out: removes personal keys
115
+
116
+ const storage = createStorage('kino');
117
+ storage.writeJSON(storage.key('player', 'volume'), 0.4);
118
+ ```
119
+
120
+ Old key names are not migrated. Full rules, the key list and cross-tab behavior:
121
+ [`@docs/STORAGE_KEYS.md`](./@docs/STORAGE_KEYS.md).
122
+
105
123
  ## Token storage & DPoP
106
124
 
107
125
  The token lives in the shared `auth` store (localStorage by default, switchable
package/dist/auth.cjs CHANGED
@@ -297,77 +297,264 @@ var APIError = class extends Error {
297
297
  }
298
298
  };
299
299
 
300
- // src/_api/generated/helpers/auth.ts
301
- var ACCESS_KEY = "cfg.access_token";
302
- var REFRESH_KEY = "cfg.refresh_token";
303
- var API_KEY_KEY = "cfg.api_key";
304
- var isBrowser = typeof window !== "undefined";
305
- var localStorageBackend = {
306
- get(key) {
307
- if (!isBrowser) return null;
308
- try {
309
- return window.localStorage.getItem(key);
310
- } catch {
311
- return null;
300
+ // src/_api/generated/helpers/keys.ts
301
+ var k = /* @__PURE__ */ __name((key, store, personal) => ({ key, store, personal }), "k");
302
+ var f = /* @__PURE__ */ __name((prefix, store, personal) => ({ prefix, store, personal }), "f");
303
+ var CFG_KEYS = {
304
+ accessToken: k("cfg.auth.access_token", "local", true),
305
+ refreshToken: k("cfg.auth.refresh_token", "local", true),
306
+ apiKey: k("cfg.auth.api_key", "local", true),
307
+ email: k("cfg.auth.email", "local", false),
308
+ emailTs: k("cfg.auth.email_ts", "local", false),
309
+ redirectUrl: k("cfg.auth.redirect_url", "session", true),
310
+ redirectUrlTs: k("cfg.auth.redirect_url_ts", "session", true),
311
+ oauthState: k("cfg.auth.oauth_state", "session", true),
312
+ oauthProvider: k("cfg.auth.oauth_provider", "session", true),
313
+ oauthRememberMe: k("cfg.auth.oauth_remember_me", "session", true),
314
+ profileCache: k("cfg.profile.cache", "local", true),
315
+ monitorSessionId: k("cfg.monitor.session_id", "local", false),
316
+ monitorSessionCookie: k("cfg.monitor.session_id", "cookie", false),
317
+ monitorDebug: k("cfg.monitor.debug", "local", false),
318
+ uiTabId: k("cfg.ui.tab_id", "session", false),
319
+ uiRouterSerial: k("cfg.ui.router_serial", "session", false),
320
+ uiState: k("cfg.ui.state", "local", false),
321
+ chatSpeechLanguage: k("cfg.chat.speech_language", "local", false),
322
+ chatRecentTools: k("cfg.chat.recent_tools", "local", false),
323
+ formsSpeechDebug: k("cfg.forms.speech_debug", "local", false),
324
+ formsSpeechPrefs: k("cfg.forms.speech_prefs", "local", false),
325
+ agentPlaygroundApiKeyId: k("cfg.agent.playground_api_key_id", "session", true),
326
+ agentPlaygroundBearer: k("cfg.agent.playground_bearer", "session", true),
327
+ agentEndpointDoc: k("cfg.agent.endpoint_doc", "session", false)
328
+ };
329
+ var CFG_FAMILIES = {
330
+ chatDraft: f("cfg.chat.draft.", "session", true),
331
+ dataTree: f("cfg.data.tree.", "local", false),
332
+ agentEndpointDraft: f("cfg.agent.endpoint_draft.", "local", false)
333
+ };
334
+ var OWNER_RE = /^[a-z][a-z0-9_]*$/;
335
+ function normalizeSegment(raw) {
336
+ return raw.trim().toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/^_+|_+$/g, "");
337
+ }
338
+ __name(normalizeSegment, "normalizeSegment");
339
+ var hasWindow = /* @__PURE__ */ __name(() => typeof window !== "undefined", "hasWindow");
340
+ function nativeStorage(store) {
341
+ if (!hasWindow()) return null;
342
+ try {
343
+ return store === "session" ? window.sessionStorage : window.localStorage;
344
+ } catch {
345
+ return null;
346
+ }
347
+ }
348
+ __name(nativeStorage, "nativeStorage");
349
+ function cookieNames() {
350
+ if (!hasWindow()) return [];
351
+ try {
352
+ return document.cookie.split("; ").map((part) => decodeURIComponent(part.split("=")[0] ?? "")).filter(Boolean);
353
+ } catch {
354
+ return [];
355
+ }
356
+ }
357
+ __name(cookieNames, "cookieNames");
358
+ function createStorage(owner, options = {}) {
359
+ if (!OWNER_RE.test(owner)) {
360
+ throw new TypeError(`createStorage: owner "${owner}" must match ${OWNER_RE}`);
361
+ }
362
+ const prefix = `${owner}.`;
363
+ const pattern = owner === "cfg" ? /^cfg(\.[a-z0-9_]+)+$/ : new RegExp(`^(cfg|${owner})(\\.[a-z0-9_]+)+$`);
364
+ const cookieMaxAge = options.cookieMaxAgeSeconds ?? 60 * 60 * 24 * 30;
365
+ const specs = Object.values(options.keys ?? {});
366
+ const families = Object.values(options.families ?? {});
367
+ const specByKey = /* @__PURE__ */ new Map();
368
+ for (const spec of specs) specByKey.set(spec.key, [...specByKey.get(spec.key) ?? [], spec]);
369
+ const memory = {
370
+ local: /* @__PURE__ */ new Map(),
371
+ session: /* @__PURE__ */ new Map(),
372
+ cookie: /* @__PURE__ */ new Map()
373
+ };
374
+ const isValid = /* @__PURE__ */ __name((key) => pattern.test(key), "isValid");
375
+ const assertValid = /* @__PURE__ */ __name((key) => {
376
+ if (!isValid(key)) throw new TypeError(`storage key "${key}" must match ${pattern}`);
377
+ }, "assertValid");
378
+ const assertOwned = /* @__PURE__ */ __name((key) => {
379
+ assertValid(key);
380
+ if (!key.startsWith(prefix)) throw new TypeError(`storage key "${key}" is not owned by "${owner}"`);
381
+ }, "assertOwned");
382
+ function rawGet(store, key) {
383
+ if (!hasWindow()) return null;
384
+ if (store === "cookie") {
385
+ try {
386
+ const escaped = encodeURIComponent(key).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
387
+ const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${escaped}=([^;]*)`));
388
+ if (match?.[1] !== void 0) return decodeURIComponent(match[1]);
389
+ } catch {
390
+ }
391
+ return memory.cookie.get(key) ?? null;
312
392
  }
313
- },
314
- set(key, value) {
315
- if (!isBrowser) return;
316
393
  try {
317
- if (value === null) window.localStorage.removeItem(key);
318
- else window.localStorage.setItem(key, value);
394
+ const value = nativeStorage(store)?.getItem(key) ?? null;
395
+ if (value !== null) return value;
319
396
  } catch {
320
397
  }
398
+ return memory[store].get(key) ?? null;
321
399
  }
322
- };
323
- var sessionStorageBackend = {
324
- get(key) {
325
- if (!isBrowser) return null;
400
+ __name(rawGet, "rawGet");
401
+ function rawSet(store, key, value) {
402
+ if (!hasWindow()) return false;
326
403
  try {
327
- return window.sessionStorage.getItem(key);
404
+ if (store === "cookie") {
405
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
406
+ document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${cookieMaxAge}; SameSite=Lax${secure}`;
407
+ if (rawGet("cookie", key) === value && !memory.cookie.has(key)) return true;
408
+ memory.cookie.set(key, value);
409
+ return false;
410
+ }
411
+ const native = nativeStorage(store);
412
+ if (!native) throw new Error("storage unavailable");
413
+ native.setItem(key, value);
414
+ memory[store].delete(key);
415
+ return true;
328
416
  } catch {
329
- return null;
417
+ memory[store].set(key, value);
418
+ return false;
330
419
  }
331
- },
332
- set(key, value) {
333
- if (!isBrowser) return;
420
+ }
421
+ __name(rawSet, "rawSet");
422
+ function rawRemove(store, key) {
423
+ memory[store].delete(key);
424
+ if (!hasWindow()) return;
334
425
  try {
335
- if (value === null) window.sessionStorage.removeItem(key);
336
- else window.sessionStorage.setItem(key, value);
426
+ if (store === "cookie") {
427
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
428
+ document.cookie = `${encodeURIComponent(key)}=; Path=/; Max-Age=0; SameSite=Lax${secure}`;
429
+ } else {
430
+ nativeStorage(store)?.removeItem(key);
431
+ }
337
432
  } catch {
338
433
  }
339
434
  }
340
- };
341
- var COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
342
- var cookieBackend = {
343
- get(key) {
344
- if (!isBrowser) return null;
435
+ __name(rawRemove, "rawRemove");
436
+ function resolveStore(key, store) {
437
+ return store ?? specByKey.get(key)?.[0]?.store ?? "local";
438
+ }
439
+ __name(resolveStore, "resolveStore");
440
+ function listKeys(store, startsWith) {
441
+ const out = [];
345
442
  try {
346
- const re = new RegExp(`(?:^|;\\s*)${encodeURIComponent(key)}=([^;]*)`);
347
- const m = document.cookie.match(re);
348
- const value = m?.[1];
349
- return value === void 0 ? null : decodeURIComponent(value);
443
+ const native = nativeStorage(store);
444
+ if (native) {
445
+ for (let i = 0; i < native.length; i += 1) {
446
+ const name = native.key(i);
447
+ if (name?.startsWith(startsWith)) out.push(name);
448
+ }
449
+ }
350
450
  } catch {
351
- return null;
352
451
  }
353
- },
354
- set(key, value) {
355
- if (!isBrowser) return;
356
- try {
357
- const k = encodeURIComponent(key);
358
- const secure = window.location.protocol === "https:" ? "; Secure" : "";
359
- if (value === null) {
360
- document.cookie = `${k}=; Path=/; Max-Age=0; SameSite=Lax${secure}`;
361
- } else {
362
- const v = encodeURIComponent(value);
363
- document.cookie = `${k}=${v}; Path=/; Max-Age=${COOKIE_MAX_AGE}; SameSite=Lax${secure}`;
452
+ for (const name of memory[store].keys()) if (name.startsWith(startsWith) && !out.includes(name)) out.push(name);
453
+ return out;
454
+ }
455
+ __name(listKeys, "listKeys");
456
+ const familyKey = /* @__PURE__ */ __name((family, id) => {
457
+ const part = normalizeSegment(id);
458
+ if (!part) throw new TypeError("storage family id is empty after normalisation");
459
+ return family.prefix + part;
460
+ }, "familyKey");
461
+ const api = {
462
+ owner,
463
+ key(...parts) {
464
+ const segments = parts.map(normalizeSegment);
465
+ if (segments.length === 0 || segments.some((segment) => !segment)) {
466
+ throw new TypeError(`storage key parts must be non-empty: ${JSON.stringify(parts)}`);
364
467
  }
365
- } catch {
468
+ return `${prefix}${segments.join(".")}`;
469
+ },
470
+ familyKey,
471
+ isValid,
472
+ read(key, store) {
473
+ assertValid(key);
474
+ const target = resolveStore(key, store);
475
+ return rawGet(target, key);
476
+ },
477
+ write(key, value, store) {
478
+ assertOwned(key);
479
+ const target = resolveStore(key, store);
480
+ return rawSet(target, key, value);
481
+ },
482
+ remove(key, store) {
483
+ assertOwned(key);
484
+ const target = resolveStore(key, store);
485
+ rawRemove(target, key);
486
+ },
487
+ readJSON(key, store) {
488
+ const raw = api.read(key, store);
489
+ if (raw === null) return null;
490
+ try {
491
+ return JSON.parse(raw);
492
+ } catch {
493
+ return null;
494
+ }
495
+ },
496
+ writeJSON(key, value, store) {
497
+ return api.write(key, JSON.stringify(value), store);
498
+ },
499
+ keys(store = "local") {
500
+ return listKeys(store, prefix);
501
+ },
502
+ clearAll({ all = false } = {}) {
503
+ for (const spec of specs) {
504
+ if (!all && !spec.personal) continue;
505
+ rawRemove(spec.store, spec.key);
506
+ }
507
+ for (const family of families) {
508
+ if (!all && !family.personal) continue;
509
+ for (const name of listKeys(family.store, family.prefix)) rawRemove(family.store, name);
510
+ }
511
+ if (all) {
512
+ for (const store of ["local", "session"]) {
513
+ for (const name of listKeys(store, prefix)) rawRemove(store, name);
514
+ }
515
+ for (const name of cookieNames()) if (name.startsWith(prefix)) rawRemove("cookie", name);
516
+ }
517
+ },
518
+ onChange(key, listener, store = "local") {
519
+ assertValid(key);
520
+ if (!hasWindow()) return () => {
521
+ };
522
+ const handler = /* @__PURE__ */ __name((event) => {
523
+ if (event.storageArea !== nativeStorage(store)) return;
524
+ if (event.key === null || event.key === key) listener(event.key === null ? null : event.newValue);
525
+ }, "handler");
526
+ window.addEventListener("storage", handler);
527
+ return () => window.removeEventListener("storage", handler);
366
528
  }
367
- }
529
+ };
530
+ return api;
531
+ }
532
+ __name(createStorage, "createStorage");
533
+ var cfgStorage = createStorage("cfg", {
534
+ keys: CFG_KEYS,
535
+ families: CFG_FAMILIES
536
+ });
537
+
538
+ // src/_api/generated/helpers/auth.ts
539
+ var ACCESS_KEY = "cfg.auth.access_token";
540
+ var REFRESH_KEY = "cfg.auth.refresh_token";
541
+ var API_KEY_KEY = "cfg.auth.api_key";
542
+ var storage = true ? cfgStorage : createStorage2("cfg");
543
+ var isBrowser = typeof window !== "undefined";
544
+ var STORE_OF = {
545
+ localStorage: "local",
546
+ sessionStorage: "session",
547
+ cookie: "cookie"
368
548
  };
369
549
  function backendFor(mode) {
370
- return mode === "cookie" ? cookieBackend : mode === "sessionStorage" ? sessionStorageBackend : localStorageBackend;
550
+ const store = STORE_OF[mode];
551
+ return {
552
+ get: /* @__PURE__ */ __name((key) => storage.read(key, store), "get"),
553
+ set(key, value) {
554
+ if (value === null) storage.remove(key, store);
555
+ else storage.write(key, value, store);
556
+ }
557
+ };
371
558
  }
372
559
  __name(backendFor, "backendFor");
373
560
  var _storageMode = "localStorage";
@@ -556,10 +743,12 @@ var auth = {
556
743
  notifySessionChanged();
557
744
  },
558
745
  clearTokens() {
559
- for (const backend of [localStorageBackend, sessionStorageBackend, cookieBackend]) {
746
+ for (const mode of ["localStorage", "sessionStorage", "cookie"]) {
747
+ const backend = backendFor(mode);
560
748
  backend.set(ACCESS_KEY, null);
561
749
  backend.set(REFRESH_KEY, null);
562
750
  }
751
+ storage.clearAll();
563
752
  notifySessionChanged();
564
753
  },
565
754
  /** Session-aware: token PRESENT and not past its `exp` (or a live refresh
@@ -751,7 +940,7 @@ function dpopEnabled() {
751
940
  }
752
941
  }
753
942
  __name(dpopEnabled, "dpopEnabled");
754
- var _DPOP_DB = "cfg-auth";
943
+ var _DPOP_DB = "cfg.auth.dpop";
755
944
  var _DPOP_STORE = "keys";
756
945
  var _DPOP_KEY_ID = "dpop-ec-p256";
757
946
  function _idbOpen() {
@@ -3086,6 +3275,9 @@ var logAuthFailure = /* @__PURE__ */ __name((log, message, error) => {
3086
3275
  }, "logAuthFailure");
3087
3276
 
3088
3277
  // src/auth/hooks/useGithubAuth.ts
3278
+ var OAUTH_STATE_KEY = CFG_KEYS.oauthState.key;
3279
+ var OAUTH_PROVIDER_KEY = CFG_KEYS.oauthProvider.key;
3280
+ var OAUTH_REMEMBER_KEY = CFG_KEYS.oauthRememberMe.key;
3089
3281
  var useGithubAuth = /* @__PURE__ */ __name((options = {}) => {
3090
3282
  const { sourceUrl, rememberMe = false, onSuccess, onError, onRequires2FA, redirectUrl, skipRedirect = false } = options;
3091
3283
  const router = useCfgRouter();
@@ -3113,9 +3305,9 @@ var useGithubAuth = /* @__PURE__ */ __name((options = {}) => {
3113
3305
  }
3114
3306
  authLogger.info("Redirecting to GitHub...", response.authorization_url);
3115
3307
  if (typeof window !== "undefined") {
3116
- sessionStorage.setItem("oauth_state", response.state);
3117
- sessionStorage.setItem("oauth_provider", "github");
3118
- sessionStorage.setItem("cfg.oauth.remember_me", String(rememberMe));
3308
+ sessionStorage.setItem(OAUTH_STATE_KEY, response.state);
3309
+ sessionStorage.setItem(OAUTH_PROVIDER_KEY, "github");
3310
+ sessionStorage.setItem(OAUTH_REMEMBER_KEY, String(rememberMe));
3119
3311
  }
3120
3312
  window.location.href = response.authorization_url;
3121
3313
  } catch (err) {
@@ -3138,14 +3330,14 @@ var useGithubAuth = /* @__PURE__ */ __name((options = {}) => {
3138
3330
  authLogger.info("Processing GitHub OAuth callback...");
3139
3331
  let rememberMeForSession = false;
3140
3332
  if (typeof window !== "undefined") {
3141
- const storedState = sessionStorage.getItem("oauth_state");
3333
+ const storedState = sessionStorage.getItem(OAUTH_STATE_KEY);
3142
3334
  if (storedState && storedState !== state) {
3143
3335
  throw new Error("Invalid OAuth state - possible CSRF attack");
3144
3336
  }
3145
- rememberMeForSession = sessionStorage.getItem("cfg.oauth.remember_me") === "true";
3146
- sessionStorage.removeItem("oauth_state");
3147
- sessionStorage.removeItem("oauth_provider");
3148
- sessionStorage.removeItem("cfg.oauth.remember_me");
3337
+ rememberMeForSession = sessionStorage.getItem(OAUTH_REMEMBER_KEY) === "true";
3338
+ sessionStorage.removeItem(OAUTH_STATE_KEY);
3339
+ sessionStorage.removeItem(OAUTH_PROVIDER_KEY);
3340
+ sessionStorage.removeItem(OAUTH_REMEMBER_KEY);
3149
3341
  }
3150
3342
  const result = await CfgAccountsOauth.cfgAccountsOauthGithubCallbackCreate({
3151
3343
  body: { code, state, remember_me: rememberMeForSession },
@@ -3257,7 +3449,7 @@ function useSessionStorage(key, initialValue) {
3257
3449
  const key2 = keys[i];
3258
3450
  if (key2) {
3259
3451
  sessionStorage.removeItem(key2);
3260
- sessionStorage.removeItem(`${key2}_timestamp`);
3452
+ sessionStorage.removeItem(`${key2}_ts`);
3261
3453
  }
3262
3454
  } catch {
3263
3455
  }
@@ -3287,7 +3479,7 @@ function useSessionStorage(key, initialValue) {
3287
3479
  authLogger.warn(`Data size too large for key "${key}", removing key`);
3288
3480
  try {
3289
3481
  window.sessionStorage.removeItem(key);
3290
- window.sessionStorage.removeItem(`${key}_timestamp`);
3482
+ window.sessionStorage.removeItem(`${key}_ts`);
3291
3483
  } catch {
3292
3484
  }
3293
3485
  setStoredValue(valueToStore);
@@ -3297,20 +3489,20 @@ function useSessionStorage(key, initialValue) {
3297
3489
  if (typeof window !== "undefined") {
3298
3490
  try {
3299
3491
  window.sessionStorage.setItem(key, JSON.stringify(valueToStore));
3300
- window.sessionStorage.setItem(`${key}_timestamp`, Date.now().toString());
3492
+ window.sessionStorage.setItem(`${key}_ts`, Date.now().toString());
3301
3493
  } catch (storageError) {
3302
3494
  if (isQuotaExceededError(storageError)) {
3303
3495
  authLogger.warn("sessionStorage quota exceeded, clearing old data...");
3304
3496
  clearOldData();
3305
3497
  try {
3306
3498
  window.sessionStorage.setItem(key, JSON.stringify(valueToStore));
3307
- window.sessionStorage.setItem(`${key}_timestamp`, Date.now().toString());
3499
+ window.sessionStorage.setItem(`${key}_ts`, Date.now().toString());
3308
3500
  } catch (retryError) {
3309
3501
  authLogger.error(`Failed to set sessionStorage key "${key}" after clearing old data:`, retryError);
3310
3502
  try {
3311
3503
  forceClearAll();
3312
3504
  window.sessionStorage.setItem(key, JSON.stringify(valueToStore));
3313
- window.sessionStorage.setItem(`${key}_timestamp`, Date.now().toString());
3505
+ window.sessionStorage.setItem(`${key}_ts`, Date.now().toString());
3314
3506
  } catch (finalError) {
3315
3507
  authLogger.error(`Failed to set sessionStorage key "${key}" after force clearing:`, finalError);
3316
3508
  setStoredValue(valueToStore);
@@ -3333,14 +3525,14 @@ function useSessionStorage(key, initialValue) {
3333
3525
  if (typeof window !== "undefined") {
3334
3526
  try {
3335
3527
  window.sessionStorage.removeItem(key);
3336
- window.sessionStorage.removeItem(`${key}_timestamp`);
3528
+ window.sessionStorage.removeItem(`${key}_ts`);
3337
3529
  } catch (removeError) {
3338
3530
  if (isQuotaExceededError(removeError)) {
3339
3531
  authLogger.warn("sessionStorage quota exceeded during removal, clearing old data...");
3340
3532
  clearOldData();
3341
3533
  try {
3342
3534
  window.sessionStorage.removeItem(key);
3343
- window.sessionStorage.removeItem(`${key}_timestamp`);
3535
+ window.sessionStorage.removeItem(`${key}_ts`);
3344
3536
  } catch (retryError) {
3345
3537
  authLogger.error(`Failed to remove sessionStorage key "${key}" after clearing:`, retryError);
3346
3538
  forceClearAll();
@@ -3359,7 +3551,7 @@ function useSessionStorage(key, initialValue) {
3359
3551
  __name(useSessionStorage, "useSessionStorage");
3360
3552
 
3361
3553
  // src/auth/hooks/useAuthRedirect.ts
3362
- var AUTH_REDIRECT_KEY = "auth_redirect_url";
3554
+ var AUTH_REDIRECT_KEY = CFG_KEYS.redirectUrl.key;
3363
3555
  var getRedirectFromStorage = /* @__PURE__ */ __name(() => {
3364
3556
  if (typeof window === "undefined") return "";
3365
3557
  try {
@@ -3373,7 +3565,7 @@ var clearRedirectFromStorage = /* @__PURE__ */ __name(() => {
3373
3565
  if (typeof window === "undefined") return;
3374
3566
  try {
3375
3567
  window.sessionStorage.removeItem(AUTH_REDIRECT_KEY);
3376
- window.sessionStorage.removeItem(`${AUTH_REDIRECT_KEY}_timestamp`);
3568
+ window.sessionStorage.removeItem(`${AUTH_REDIRECT_KEY}_ts`);
3377
3569
  } catch {
3378
3570
  }
3379
3571
  }, "clearRedirectFromStorage");
@@ -3789,7 +3981,7 @@ function useLocalStorage(key, initialValue) {
3789
3981
  const key2 = keys[i];
3790
3982
  if (key2) {
3791
3983
  localStorage.removeItem(key2);
3792
- localStorage.removeItem(`${key2}_timestamp`);
3984
+ localStorage.removeItem(`${key2}_ts`);
3793
3985
  }
3794
3986
  } catch {
3795
3987
  }
@@ -3819,7 +4011,7 @@ function useLocalStorage(key, initialValue) {
3819
4011
  authLogger.warn(`Data size too large for key "${key}", removing key`);
3820
4012
  try {
3821
4013
  window.localStorage.removeItem(key);
3822
- window.localStorage.removeItem(`${key}_timestamp`);
4014
+ window.localStorage.removeItem(`${key}_ts`);
3823
4015
  } catch {
3824
4016
  }
3825
4017
  setStoredValue(valueToStore);
@@ -3833,7 +4025,7 @@ function useLocalStorage(key, initialValue) {
3833
4025
  } else {
3834
4026
  window.localStorage.setItem(key, JSON.stringify(valueToStore));
3835
4027
  }
3836
- window.localStorage.setItem(`${key}_timestamp`, Date.now().toString());
4028
+ window.localStorage.setItem(`${key}_ts`, Date.now().toString());
3837
4029
  } catch (storageError) {
3838
4030
  if (isQuotaExceededError(storageError)) {
3839
4031
  authLogger.warn("localStorage quota exceeded, clearing old data...");
@@ -3844,7 +4036,7 @@ function useLocalStorage(key, initialValue) {
3844
4036
  } else {
3845
4037
  window.localStorage.setItem(key, JSON.stringify(valueToStore));
3846
4038
  }
3847
- window.localStorage.setItem(`${key}_timestamp`, Date.now().toString());
4039
+ window.localStorage.setItem(`${key}_ts`, Date.now().toString());
3848
4040
  } catch (retryError) {
3849
4041
  authLogger.error(`Failed to set localStorage key "${key}" after clearing old data:`, retryError);
3850
4042
  try {
@@ -3854,7 +4046,7 @@ function useLocalStorage(key, initialValue) {
3854
4046
  } else {
3855
4047
  window.localStorage.setItem(key, JSON.stringify(valueToStore));
3856
4048
  }
3857
- window.localStorage.setItem(`${key}_timestamp`, Date.now().toString());
4049
+ window.localStorage.setItem(`${key}_ts`, Date.now().toString());
3858
4050
  } catch (finalError) {
3859
4051
  authLogger.error(`Failed to set localStorage key "${key}" after force clearing:`, finalError);
3860
4052
  setStoredValue(valueToStore);
@@ -3877,14 +4069,14 @@ function useLocalStorage(key, initialValue) {
3877
4069
  if (typeof window !== "undefined") {
3878
4070
  try {
3879
4071
  window.localStorage.removeItem(key);
3880
- window.localStorage.removeItem(`${key}_timestamp`);
4072
+ window.localStorage.removeItem(`${key}_ts`);
3881
4073
  } catch (removeError) {
3882
4074
  if (isQuotaExceededError(removeError)) {
3883
4075
  authLogger.warn("localStorage quota exceeded during removal, clearing old data...");
3884
4076
  clearOldData();
3885
4077
  try {
3886
4078
  window.localStorage.removeItem(key);
3887
- window.localStorage.removeItem(`${key}_timestamp`);
4079
+ window.localStorage.removeItem(`${key}_ts`);
3888
4080
  } catch (retryError) {
3889
4081
  authLogger.error(`Failed to remove localStorage key "${key}" after clearing:`, retryError);
3890
4082
  forceClearAll();
@@ -3952,7 +4144,7 @@ function useBase64() {
3952
4144
  __name(useBase64, "useBase64");
3953
4145
 
3954
4146
  // src/auth/hooks/useProfileCache.ts
3955
- var CACHE_KEY = "user_profile_cache";
4147
+ var CACHE_KEY = CFG_KEYS.profileCache.key;
3956
4148
  var CACHE_VERSION = 1;
3957
4149
  var DEFAULT_TTL = 144e5;
3958
4150
  function getCachedProfile() {
@@ -4597,7 +4789,7 @@ var resolveAuthRoutes = /* @__PURE__ */ __name((routes) => ({
4597
4789
  defaultCallback: routes?.defaultCallback || defaultRoutes.defaultCallback,
4598
4790
  defaultAuthCallback: routes?.defaultAuthCallback || routes?.auth || defaultRoutes.defaultAuthCallback
4599
4791
  }), "resolveAuthRoutes");
4600
- var EMAIL_STORAGE_KEY = "auth_email";
4792
+ var EMAIL_STORAGE_KEY = CFG_KEYS.email.key;
4601
4793
  var AuthContext = (0, import_react17.createContext)(void 0);
4602
4794
  var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4603
4795
  const accounts = useAccountsContext();