@djangocfg/api 2.1.603 → 2.1.605

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.cjs CHANGED
@@ -97,8 +97,8 @@ var APIError = class extends Error {
97
97
  var k = /* @__PURE__ */ __name((key, store, personal) => ({ key, store, personal }), "k");
98
98
  var f = /* @__PURE__ */ __name((prefix, store, personal) => ({ prefix, store, personal }), "f");
99
99
  var CFG_KEYS = {
100
- accessToken: k("cfg.auth.access_token", "local", true),
101
- refreshToken: k("cfg.auth.refresh_token", "local", true),
100
+ accessToken: k("cfg.auth.access_token", "cookie", true),
101
+ refreshToken: k("cfg.auth.refresh_token", "cookie", true),
102
102
  apiKey: k("cfg.auth.api_key", "local", true),
103
103
  email: k("cfg.auth.email", "local", false),
104
104
  emailTs: k("cfg.auth.email_ts", "local", false),
@@ -133,6 +133,31 @@ function normalizeSegment(raw) {
133
133
  }
134
134
  __name(normalizeSegment, "normalizeSegment");
135
135
  var hasWindow = /* @__PURE__ */ __name(() => typeof window !== "undefined", "hasWindow");
136
+ var domainByHost = /* @__PURE__ */ new Map();
137
+ function detectCookieDomain() {
138
+ if (!hasWindow() || typeof document === "undefined") return null;
139
+ const host = window.location.hostname.toLowerCase();
140
+ if (!host || !host.includes(".") || host.includes(":") || /^[0-9.]+$/.test(host)) return null;
141
+ const cached = domainByHost.get(host);
142
+ if (cached !== void 0) return cached;
143
+ const labels = host.split(".");
144
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
145
+ let found = null;
146
+ try {
147
+ for (let i = labels.length - 2; i >= 0 && found === null; i -= 1) {
148
+ const candidate = labels.slice(i).join(".");
149
+ const probe = "cfg_probe_" + Math.random().toString(36).slice(2);
150
+ document.cookie = probe + "=1; Domain=" + candidate + "; Path=/; Max-Age=30; SameSite=Lax" + secure;
151
+ if (document.cookie.includes(probe + "=1")) found = candidate;
152
+ document.cookie = probe + "=; Domain=" + candidate + "; Path=/; Max-Age=0; SameSite=Lax" + secure;
153
+ }
154
+ } catch {
155
+ found = null;
156
+ }
157
+ domainByHost.set(host, found);
158
+ return found;
159
+ }
160
+ __name(detectCookieDomain, "detectCookieDomain");
136
161
  function nativeStorage(store) {
137
162
  if (!hasWindow()) return null;
138
163
  try {
@@ -158,6 +183,12 @@ function createStorage(owner, options = {}) {
158
183
  const prefix = `${owner}.`;
159
184
  const pattern = owner === "cfg" ? /^cfg(\.[a-z0-9_]+)+$/ : new RegExp(`^(cfg|${owner})(\\.[a-z0-9_]+)+$`);
160
185
  const cookieMaxAge = options.cookieMaxAgeSeconds ?? 60 * 60 * 24 * 30;
186
+ let cookiePolicy = options.cookieDomain ?? "auto";
187
+ const resolveCookieDomain = /* @__PURE__ */ __name(() => cookiePolicy === false ? null : cookiePolicy === "auto" ? detectCookieDomain() : cookiePolicy, "resolveCookieDomain");
188
+ const expireCookie = /* @__PURE__ */ __name((key, domain) => {
189
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
190
+ document.cookie = encodeURIComponent(key) + "=; Path=/; Max-Age=0; SameSite=Lax" + (domain ? "; Domain=" + domain : "") + secure;
191
+ }, "expireCookie");
161
192
  const specs = Object.values(options.keys ?? {});
162
193
  const families = Object.values(options.families ?? {});
163
194
  const specByKey = /* @__PURE__ */ new Map();
@@ -194,12 +225,15 @@ function createStorage(owner, options = {}) {
194
225
  return memory[store].get(key) ?? null;
195
226
  }
196
227
  __name(rawGet, "rawGet");
197
- function rawSet(store, key, value) {
228
+ function rawSet(store, key, value, maxAgeSeconds) {
198
229
  if (!hasWindow()) return false;
199
230
  try {
200
231
  if (store === "cookie") {
201
232
  const secure = window.location.protocol === "https:" ? "; Secure" : "";
202
- document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${cookieMaxAge}; SameSite=Lax${secure}`;
233
+ const domain = resolveCookieDomain();
234
+ const domainPart = domain ? `; Domain=${domain}` : "";
235
+ document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${Math.max(1, Math.floor(maxAgeSeconds ?? cookieMaxAge))}; SameSite=Lax${domainPart}${secure}`;
236
+ if (domain) expireCookie(key, null);
203
237
  if (rawGet("cookie", key) === value && !memory.cookie.has(key)) return true;
204
238
  memory.cookie.set(key, value);
205
239
  return false;
@@ -220,8 +254,9 @@ function createStorage(owner, options = {}) {
220
254
  if (!hasWindow()) return;
221
255
  try {
222
256
  if (store === "cookie") {
223
- const secure = window.location.protocol === "https:" ? "; Secure" : "";
224
- document.cookie = `${encodeURIComponent(key)}=; Path=/; Max-Age=0; SameSite=Lax${secure}`;
257
+ expireCookie(key, null);
258
+ const domain = resolveCookieDomain();
259
+ if (domain) expireCookie(key, domain);
225
260
  } else {
226
261
  nativeStorage(store)?.removeItem(key);
227
262
  }
@@ -270,10 +305,10 @@ function createStorage(owner, options = {}) {
270
305
  const target = resolveStore(key, store);
271
306
  return rawGet(target, key);
272
307
  },
273
- write(key, value, store) {
308
+ write(key, value, store, writeOptions) {
274
309
  assertOwned(key);
275
310
  const target = resolveStore(key, store);
276
- return rawSet(target, key, value);
311
+ return rawSet(target, key, value, writeOptions?.maxAgeSeconds);
277
312
  },
278
313
  remove(key, store) {
279
314
  assertOwned(key);
@@ -311,6 +346,10 @@ function createStorage(owner, options = {}) {
311
346
  for (const name of cookieNames()) if (name.startsWith(prefix)) rawRemove("cookie", name);
312
347
  }
313
348
  },
349
+ setCookieDomain(domain) {
350
+ cookiePolicy = domain;
351
+ },
352
+ cookieDomain: resolveCookieDomain,
314
353
  onChange(key, listener, store = "local") {
315
354
  assertValid(key);
316
355
  if (!hasWindow()) return () => {
@@ -337,6 +376,11 @@ var REFRESH_KEY = "cfg.auth.refresh_token";
337
376
  var API_KEY_KEY = "cfg.auth.api_key";
338
377
  var storage = true ? cfgStorage : createStorage2("cfg");
339
378
  var isBrowser = typeof window !== "undefined";
379
+ function secondsUntilExp(token) {
380
+ const exp = jwtExpMs(token);
381
+ return exp === null ? void 0 : Math.max(1, Math.floor((exp - Date.now()) / 1e3));
382
+ }
383
+ __name(secondsUntilExp, "secondsUntilExp");
340
384
  var STORE_OF = {
341
385
  localStorage: "local",
342
386
  sessionStorage: "session",
@@ -348,13 +392,31 @@ function backendFor(mode) {
348
392
  get: /* @__PURE__ */ __name((key) => storage.read(key, store), "get"),
349
393
  set(key, value) {
350
394
  if (value === null) storage.remove(key, store);
351
- else storage.write(key, value, store);
395
+ else storage.write(key, value, store, store === "cookie" && key === REFRESH_KEY ? { maxAgeSeconds: secondsUntilExp(value) } : void 0);
352
396
  }
353
397
  };
354
398
  }
355
399
  __name(backendFor, "backendFor");
356
- var _storageMode = "localStorage";
400
+ var _storageMode = "cookie";
357
401
  var _storage = backendFor(_storageMode);
402
+ var _apiKeyStore = backendFor("localStorage");
403
+ function adoptLegacySession() {
404
+ if (!isBrowser || _storageMode !== "cookie") return;
405
+ try {
406
+ if (_storage.get(ACCESS_KEY) !== null || _storage.get(REFRESH_KEY) !== null) return;
407
+ const legacy = backendFor("localStorage");
408
+ const access = legacy.get(ACCESS_KEY);
409
+ const refresh = legacy.get(REFRESH_KEY);
410
+ if (access === null && refresh === null) return;
411
+ if (access !== null) _storage.set(ACCESS_KEY, access);
412
+ if (refresh !== null) _storage.set(REFRESH_KEY, refresh);
413
+ legacy.set(ACCESS_KEY, null);
414
+ legacy.set(REFRESH_KEY, null);
415
+ } catch {
416
+ }
417
+ }
418
+ __name(adoptLegacySession, "adoptLegacySession");
419
+ adoptLegacySession();
358
420
  function detectLocale() {
359
421
  try {
360
422
  if (typeof document === "undefined") return null;
@@ -499,6 +561,14 @@ function ensureStorageSync() {
499
561
  }
500
562
  });
501
563
  window.addEventListener(SESSION_SYNC_EVENT, () => notifySessionChanged());
564
+ window.addEventListener("focus", () => notifySessionChanged());
565
+ document.addEventListener("visibilitychange", () => {
566
+ if (document.visibilityState === "visible") notifySessionChanged();
567
+ });
568
+ try {
569
+ window.cookieStore?.addEventListener("change", () => notifySessionChanged());
570
+ } catch {
571
+ }
502
572
  }
503
573
  __name(ensureStorageSync, "ensureStorageSync");
504
574
  var SESSION_EXPIRED_REGISTRY = `cfg-auth:expired-handlers:${ACCESS_KEY}`;
@@ -532,6 +602,17 @@ var auth = {
532
602
  _storage = backendFor(mode);
533
603
  notifySessionChanged();
534
604
  },
605
+ // ── Shared cookie domain ──────────────────────────────────────────
606
+ /** `'auto'` (default): the registrable domain of the page. A domain forces it; `null` keeps
607
+ * cookies host-only (no sign-in sharing between subdomains). Call before sign-in. */
608
+ setCookieDomain(domain) {
609
+ storage.setCookieDomain(domain === null ? false : domain);
610
+ notifySessionChanged();
611
+ },
612
+ /** The `Domain` the session cookie is written with; `null` = host-only. */
613
+ getCookieDomain() {
614
+ return storage.cookieDomain();
615
+ },
535
616
  // ── Bearer token ──────────────────────────────────────────────────
536
617
  getToken() {
537
618
  return _storage.get(ACCESS_KEY);
@@ -618,18 +699,18 @@ var auth = {
618
699
  },
619
700
  // ── API key ───────────────────────────────────────────────────────
620
701
  getApiKey() {
621
- return _apiKeyOverride ?? _storage.get(API_KEY_KEY) ?? defaultApiKey();
702
+ return _apiKeyOverride ?? _apiKeyStore.get(API_KEY_KEY) ?? defaultApiKey();
622
703
  },
623
704
  setApiKey(key) {
624
705
  _apiKeyOverride = key;
625
706
  },
626
707
  setApiKeyPersist(key) {
627
708
  _apiKeyOverride = key;
628
- _storage.set(API_KEY_KEY, key);
709
+ _apiKeyStore.set(API_KEY_KEY, key);
629
710
  },
630
711
  clearApiKey() {
631
712
  _apiKeyOverride = null;
632
- _storage.set(API_KEY_KEY, null);
713
+ _apiKeyStore.set(API_KEY_KEY, null);
633
714
  },
634
715
  // ── Locale ────────────────────────────────────────────────────────
635
716
  getLocale() {