@djangocfg/api 2.1.602 → 2.1.604

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/clients.mjs CHANGED
@@ -70,8 +70,8 @@ var APIError = class extends Error {
70
70
  var k = /* @__PURE__ */ __name((key, store, personal) => ({ key, store, personal }), "k");
71
71
  var f = /* @__PURE__ */ __name((prefix, store, personal) => ({ prefix, store, personal }), "f");
72
72
  var CFG_KEYS = {
73
- accessToken: k("cfg.auth.access_token", "local", true),
74
- refreshToken: k("cfg.auth.refresh_token", "local", true),
73
+ accessToken: k("cfg.auth.access_token", "cookie", true),
74
+ refreshToken: k("cfg.auth.refresh_token", "cookie", true),
75
75
  apiKey: k("cfg.auth.api_key", "local", true),
76
76
  email: k("cfg.auth.email", "local", false),
77
77
  emailTs: k("cfg.auth.email_ts", "local", false),
@@ -106,6 +106,31 @@ function normalizeSegment(raw) {
106
106
  }
107
107
  __name(normalizeSegment, "normalizeSegment");
108
108
  var hasWindow = /* @__PURE__ */ __name(() => typeof window !== "undefined", "hasWindow");
109
+ var domainByHost = /* @__PURE__ */ new Map();
110
+ function detectCookieDomain() {
111
+ if (!hasWindow() || typeof document === "undefined") return null;
112
+ const host = window.location.hostname.toLowerCase();
113
+ if (!host || !host.includes(".") || host.includes(":") || /^[0-9.]+$/.test(host)) return null;
114
+ const cached = domainByHost.get(host);
115
+ if (cached !== void 0) return cached;
116
+ const labels = host.split(".");
117
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
118
+ let found = null;
119
+ try {
120
+ for (let i = labels.length - 2; i >= 0 && found === null; i -= 1) {
121
+ const candidate = labels.slice(i).join(".");
122
+ const probe = "cfg_probe_" + Math.random().toString(36).slice(2);
123
+ document.cookie = probe + "=1; Domain=" + candidate + "; Path=/; Max-Age=30; SameSite=Lax" + secure;
124
+ if (document.cookie.includes(probe + "=1")) found = candidate;
125
+ document.cookie = probe + "=; Domain=" + candidate + "; Path=/; Max-Age=0; SameSite=Lax" + secure;
126
+ }
127
+ } catch {
128
+ found = null;
129
+ }
130
+ domainByHost.set(host, found);
131
+ return found;
132
+ }
133
+ __name(detectCookieDomain, "detectCookieDomain");
109
134
  function nativeStorage(store) {
110
135
  if (!hasWindow()) return null;
111
136
  try {
@@ -131,6 +156,12 @@ function createStorage(owner, options = {}) {
131
156
  const prefix = `${owner}.`;
132
157
  const pattern = owner === "cfg" ? /^cfg(\.[a-z0-9_]+)+$/ : new RegExp(`^(cfg|${owner})(\\.[a-z0-9_]+)+$`);
133
158
  const cookieMaxAge = options.cookieMaxAgeSeconds ?? 60 * 60 * 24 * 30;
159
+ let cookiePolicy = options.cookieDomain ?? "auto";
160
+ const resolveCookieDomain = /* @__PURE__ */ __name(() => cookiePolicy === false ? null : cookiePolicy === "auto" ? detectCookieDomain() : cookiePolicy, "resolveCookieDomain");
161
+ const expireCookie = /* @__PURE__ */ __name((key, domain) => {
162
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
163
+ document.cookie = encodeURIComponent(key) + "=; Path=/; Max-Age=0; SameSite=Lax" + (domain ? "; Domain=" + domain : "") + secure;
164
+ }, "expireCookie");
134
165
  const specs = Object.values(options.keys ?? {});
135
166
  const families = Object.values(options.families ?? {});
136
167
  const specByKey = /* @__PURE__ */ new Map();
@@ -167,12 +198,15 @@ function createStorage(owner, options = {}) {
167
198
  return memory[store].get(key) ?? null;
168
199
  }
169
200
  __name(rawGet, "rawGet");
170
- function rawSet(store, key, value) {
201
+ function rawSet(store, key, value, maxAgeSeconds) {
171
202
  if (!hasWindow()) return false;
172
203
  try {
173
204
  if (store === "cookie") {
174
205
  const secure = window.location.protocol === "https:" ? "; Secure" : "";
175
- document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${cookieMaxAge}; SameSite=Lax${secure}`;
206
+ const domain = resolveCookieDomain();
207
+ const domainPart = domain ? `; Domain=${domain}` : "";
208
+ document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${Math.max(1, Math.floor(maxAgeSeconds ?? cookieMaxAge))}; SameSite=Lax${domainPart}${secure}`;
209
+ if (domain) expireCookie(key, null);
176
210
  if (rawGet("cookie", key) === value && !memory.cookie.has(key)) return true;
177
211
  memory.cookie.set(key, value);
178
212
  return false;
@@ -193,8 +227,9 @@ function createStorage(owner, options = {}) {
193
227
  if (!hasWindow()) return;
194
228
  try {
195
229
  if (store === "cookie") {
196
- const secure = window.location.protocol === "https:" ? "; Secure" : "";
197
- document.cookie = `${encodeURIComponent(key)}=; Path=/; Max-Age=0; SameSite=Lax${secure}`;
230
+ expireCookie(key, null);
231
+ const domain = resolveCookieDomain();
232
+ if (domain) expireCookie(key, domain);
198
233
  } else {
199
234
  nativeStorage(store)?.removeItem(key);
200
235
  }
@@ -243,10 +278,10 @@ function createStorage(owner, options = {}) {
243
278
  const target = resolveStore(key, store);
244
279
  return rawGet(target, key);
245
280
  },
246
- write(key, value, store) {
281
+ write(key, value, store, writeOptions) {
247
282
  assertOwned(key);
248
283
  const target = resolveStore(key, store);
249
- return rawSet(target, key, value);
284
+ return rawSet(target, key, value, writeOptions?.maxAgeSeconds);
250
285
  },
251
286
  remove(key, store) {
252
287
  assertOwned(key);
@@ -284,6 +319,10 @@ function createStorage(owner, options = {}) {
284
319
  for (const name of cookieNames()) if (name.startsWith(prefix)) rawRemove("cookie", name);
285
320
  }
286
321
  },
322
+ setCookieDomain(domain) {
323
+ cookiePolicy = domain;
324
+ },
325
+ cookieDomain: resolveCookieDomain,
287
326
  onChange(key, listener, store = "local") {
288
327
  assertValid(key);
289
328
  if (!hasWindow()) return () => {
@@ -310,6 +349,11 @@ var REFRESH_KEY = "cfg.auth.refresh_token";
310
349
  var API_KEY_KEY = "cfg.auth.api_key";
311
350
  var storage = true ? cfgStorage : createStorage2("cfg");
312
351
  var isBrowser = typeof window !== "undefined";
352
+ function secondsUntilExp(token) {
353
+ const exp = jwtExpMs(token);
354
+ return exp === null ? void 0 : Math.max(1, Math.floor((exp - Date.now()) / 1e3));
355
+ }
356
+ __name(secondsUntilExp, "secondsUntilExp");
313
357
  var STORE_OF = {
314
358
  localStorage: "local",
315
359
  sessionStorage: "session",
@@ -321,13 +365,31 @@ function backendFor(mode) {
321
365
  get: /* @__PURE__ */ __name((key) => storage.read(key, store), "get"),
322
366
  set(key, value) {
323
367
  if (value === null) storage.remove(key, store);
324
- else storage.write(key, value, store);
368
+ else storage.write(key, value, store, store === "cookie" && key === REFRESH_KEY ? { maxAgeSeconds: secondsUntilExp(value) } : void 0);
325
369
  }
326
370
  };
327
371
  }
328
372
  __name(backendFor, "backendFor");
329
- var _storageMode = "localStorage";
373
+ var _storageMode = "cookie";
330
374
  var _storage = backendFor(_storageMode);
375
+ var _apiKeyStore = backendFor("localStorage");
376
+ function adoptLegacySession() {
377
+ if (!isBrowser || _storageMode !== "cookie") return;
378
+ try {
379
+ if (_storage.get(ACCESS_KEY) !== null || _storage.get(REFRESH_KEY) !== null) return;
380
+ const legacy = backendFor("localStorage");
381
+ const access = legacy.get(ACCESS_KEY);
382
+ const refresh = legacy.get(REFRESH_KEY);
383
+ if (access === null && refresh === null) return;
384
+ if (access !== null) _storage.set(ACCESS_KEY, access);
385
+ if (refresh !== null) _storage.set(REFRESH_KEY, refresh);
386
+ legacy.set(ACCESS_KEY, null);
387
+ legacy.set(REFRESH_KEY, null);
388
+ } catch {
389
+ }
390
+ }
391
+ __name(adoptLegacySession, "adoptLegacySession");
392
+ adoptLegacySession();
331
393
  function detectLocale() {
332
394
  try {
333
395
  if (typeof document === "undefined") return null;
@@ -472,6 +534,14 @@ function ensureStorageSync() {
472
534
  }
473
535
  });
474
536
  window.addEventListener(SESSION_SYNC_EVENT, () => notifySessionChanged());
537
+ window.addEventListener("focus", () => notifySessionChanged());
538
+ document.addEventListener("visibilitychange", () => {
539
+ if (document.visibilityState === "visible") notifySessionChanged();
540
+ });
541
+ try {
542
+ window.cookieStore?.addEventListener("change", () => notifySessionChanged());
543
+ } catch {
544
+ }
475
545
  }
476
546
  __name(ensureStorageSync, "ensureStorageSync");
477
547
  var SESSION_EXPIRED_REGISTRY = `cfg-auth:expired-handlers:${ACCESS_KEY}`;
@@ -505,6 +575,17 @@ var auth = {
505
575
  _storage = backendFor(mode);
506
576
  notifySessionChanged();
507
577
  },
578
+ // ── Shared cookie domain ──────────────────────────────────────────
579
+ /** `'auto'` (default): the registrable domain of the page. A domain forces it; `null` keeps
580
+ * cookies host-only (no sign-in sharing between subdomains). Call before sign-in. */
581
+ setCookieDomain(domain) {
582
+ storage.setCookieDomain(domain === null ? false : domain);
583
+ notifySessionChanged();
584
+ },
585
+ /** The `Domain` the session cookie is written with; `null` = host-only. */
586
+ getCookieDomain() {
587
+ return storage.cookieDomain();
588
+ },
508
589
  // ── Bearer token ──────────────────────────────────────────────────
509
590
  getToken() {
510
591
  return _storage.get(ACCESS_KEY);
@@ -591,18 +672,18 @@ var auth = {
591
672
  },
592
673
  // ── API key ───────────────────────────────────────────────────────
593
674
  getApiKey() {
594
- return _apiKeyOverride ?? _storage.get(API_KEY_KEY) ?? defaultApiKey();
675
+ return _apiKeyOverride ?? _apiKeyStore.get(API_KEY_KEY) ?? defaultApiKey();
595
676
  },
596
677
  setApiKey(key) {
597
678
  _apiKeyOverride = key;
598
679
  },
599
680
  setApiKeyPersist(key) {
600
681
  _apiKeyOverride = key;
601
- _storage.set(API_KEY_KEY, key);
682
+ _apiKeyStore.set(API_KEY_KEY, key);
602
683
  },
603
684
  clearApiKey() {
604
685
  _apiKeyOverride = null;
605
- _storage.set(API_KEY_KEY, null);
686
+ _apiKeyStore.set(API_KEY_KEY, null);
606
687
  },
607
688
  // ── Locale ────────────────────────────────────────────────────────
608
689
  getLocale() {