@djangocfg/api 2.1.618 → 2.1.621

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/index.mjs CHANGED
@@ -1,6 +1,141 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
 
4
+ // src/auth/trace.ts
5
+ var KEY = "cfg.auth.trace";
6
+ var MAX = 200;
7
+ var MAX_STRING = 120;
8
+ var SENSITIVE = /token|otp|code|email|password|secret|cookie|authorization|key|identifier/i;
9
+ var TAB = Math.random().toString(36).slice(2, 6);
10
+ var hasWindow = typeof window !== "undefined";
11
+ var memory = [];
12
+ var loaded = false;
13
+ function backend() {
14
+ if (!hasWindow) return null;
15
+ for (const name of ["localStorage", "sessionStorage"]) {
16
+ try {
17
+ const s = window[name];
18
+ s.setItem("__cfg_probe", "1");
19
+ s.removeItem("__cfg_probe");
20
+ return s;
21
+ } catch {
22
+ }
23
+ }
24
+ return null;
25
+ }
26
+ __name(backend, "backend");
27
+ function load() {
28
+ if (loaded) return memory;
29
+ loaded = true;
30
+ try {
31
+ const raw = backend()?.getItem(KEY);
32
+ const parsed = raw ? JSON.parse(raw) : [];
33
+ if (Array.isArray(parsed)) memory = parsed.filter((e) => typeof e === "object" && e !== null);
34
+ } catch {
35
+ memory = [];
36
+ }
37
+ return memory;
38
+ }
39
+ __name(load, "load");
40
+ function persist() {
41
+ try {
42
+ backend()?.setItem(KEY, JSON.stringify(memory));
43
+ } catch {
44
+ }
45
+ }
46
+ __name(persist, "persist");
47
+ function clean(fields) {
48
+ if (!fields) return void 0;
49
+ const out = {};
50
+ for (const [k2, v] of Object.entries(fields)) {
51
+ if (SENSITIVE.test(k2)) continue;
52
+ if (typeof v === "string") out[k2] = v.length > MAX_STRING ? `${v.slice(0, MAX_STRING)}\u2026` : v;
53
+ else if (typeof v === "number" || typeof v === "boolean" || v === null) out[k2] = v;
54
+ }
55
+ return Object.keys(out).length ? out : void 0;
56
+ }
57
+ __name(clean, "clean");
58
+ function record(at, ev, fields) {
59
+ const entries = load();
60
+ const p = hasWindow && typeof performance !== "undefined" ? Math.round(performance.now()) : 0;
61
+ entries.push({ t: at, p, tab: TAB, ev, f: clean(fields) });
62
+ if (entries.length > MAX) entries.splice(0, entries.length - MAX);
63
+ persist();
64
+ }
65
+ __name(record, "record");
66
+ function authTrace(ev, fields) {
67
+ if (!hasWindow) return;
68
+ try {
69
+ record(Date.now(), ev, fields);
70
+ } catch {
71
+ }
72
+ }
73
+ __name(authTrace, "authTrace");
74
+ function readAuthTrace() {
75
+ return load().slice();
76
+ }
77
+ __name(readAuthTrace, "readAuthTrace");
78
+ function clearAuthTrace() {
79
+ memory = [];
80
+ loaded = true;
81
+ try {
82
+ backend()?.removeItem(KEY);
83
+ } catch {
84
+ }
85
+ }
86
+ __name(clearAuthTrace, "clearAuthTrace");
87
+ function context() {
88
+ if (!hasWindow) return [];
89
+ const lines = [`url: ${window.location.href.split("?")[0]}`, `online: ${navigator.onLine}`, `ua: ${navigator.userAgent}`];
90
+ try {
91
+ const auth2 = globalThis.__cfgAuthNow;
92
+ const now = auth2?.();
93
+ if (now) lines.push(`now: ${Object.entries(now).map(([k2, v]) => `${k2}=${String(v)}`).join(" ")}`);
94
+ } catch {
95
+ }
96
+ return lines;
97
+ }
98
+ __name(context, "context");
99
+ function dumpAuthTrace() {
100
+ const entries = load();
101
+ const first = entries[0]?.t ?? Date.now();
102
+ const rows = entries.map((e) => {
103
+ const fields = e.f ? ` ${Object.entries(e.f).map(([k2, v]) => `${k2}=${String(v)}`).join(" ")}` : "";
104
+ const at = new Date(e.t).toISOString().slice(11, 23);
105
+ return `${at} +${String(e.t - first).padStart(6)}ms [${e.tab} p${e.p}] ${e.ev}${fields}`;
106
+ });
107
+ return [`# cfg auth trace, ${entries.length} events`, ...context(), "", ...rows].join("\n");
108
+ }
109
+ __name(dumpAuthTrace, "dumpAuthTrace");
110
+ function installAuthTrace() {
111
+ if (!hasWindow) return;
112
+ const g = globalThis;
113
+ g.__cfgAuthTrace = authTrace;
114
+ g.__cfgAuth = {
115
+ trace: readAuthTrace,
116
+ dump: /* @__PURE__ */ __name(() => {
117
+ const text = dumpAuthTrace();
118
+ console.log(text);
119
+ return text;
120
+ }, "dump"),
121
+ clear: clearAuthTrace
122
+ };
123
+ const queued = g.__cfgAuthTraceQ;
124
+ if (Array.isArray(queued)) {
125
+ g.__cfgAuthTraceQ = [];
126
+ for (const item of queued) {
127
+ if (Array.isArray(item) && typeof item[1] === "string") {
128
+ try {
129
+ record(Number(item[0]) || Date.now(), item[1], item[2]);
130
+ } catch {
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ __name(installAuthTrace, "installAuthTrace");
137
+ installAuthTrace();
138
+
4
139
  // src/_api/generated/helpers/errors.ts
5
140
  var APIError = class extends Error {
6
141
  constructor(statusCode, statusText, response, url, message) {
@@ -117,10 +252,10 @@ function normalizeSegment(raw) {
117
252
  return raw.trim().toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/^_+|_+$/g, "");
118
253
  }
119
254
  __name(normalizeSegment, "normalizeSegment");
120
- var hasWindow = /* @__PURE__ */ __name(() => typeof window !== "undefined", "hasWindow");
255
+ var hasWindow2 = /* @__PURE__ */ __name(() => typeof window !== "undefined", "hasWindow");
121
256
  var domainByHost = /* @__PURE__ */ new Map();
122
257
  function detectCookieDomain() {
123
- if (!hasWindow() || typeof document === "undefined") return null;
258
+ if (!hasWindow2() || typeof document === "undefined") return null;
124
259
  const host = window.location.hostname.toLowerCase();
125
260
  if (!host || !host.includes(".") || host.includes(":") || /^[0-9.]+$/.test(host)) return null;
126
261
  const cached = domainByHost.get(host);
@@ -144,7 +279,7 @@ function detectCookieDomain() {
144
279
  }
145
280
  __name(detectCookieDomain, "detectCookieDomain");
146
281
  function nativeStorage(store) {
147
- if (!hasWindow()) return null;
282
+ if (!hasWindow2()) return null;
148
283
  try {
149
284
  return store === "session" ? window.sessionStorage : window.localStorage;
150
285
  } catch {
@@ -153,7 +288,7 @@ function nativeStorage(store) {
153
288
  }
154
289
  __name(nativeStorage, "nativeStorage");
155
290
  function cookieNames() {
156
- if (!hasWindow()) return [];
291
+ if (!hasWindow2()) return [];
157
292
  try {
158
293
  return document.cookie.split("; ").map((part) => decodeURIComponent(part.split("=")[0] ?? "")).filter(Boolean);
159
294
  } catch {
@@ -178,7 +313,7 @@ function createStorage(owner, options = {}) {
178
313
  const families = Object.values(options.families ?? {});
179
314
  const specByKey = /* @__PURE__ */ new Map();
180
315
  for (const spec of specs) specByKey.set(spec.key, [...specByKey.get(spec.key) ?? [], spec]);
181
- const memory = {
316
+ const memory2 = {
182
317
  local: /* @__PURE__ */ new Map(),
183
318
  session: /* @__PURE__ */ new Map(),
184
319
  cookie: /* @__PURE__ */ new Map()
@@ -192,7 +327,7 @@ function createStorage(owner, options = {}) {
192
327
  if (!key.startsWith(prefix)) throw new TypeError(`storage key "${key}" is not owned by "${owner}"`);
193
328
  }, "assertOwned");
194
329
  function rawGet(store, key) {
195
- if (!hasWindow()) return null;
330
+ if (!hasWindow2()) return null;
196
331
  if (store === "cookie") {
197
332
  try {
198
333
  const escaped = encodeURIComponent(key).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -200,18 +335,18 @@ function createStorage(owner, options = {}) {
200
335
  if (match?.[1] !== void 0) return decodeURIComponent(match[1]);
201
336
  } catch {
202
337
  }
203
- return memory.cookie.get(key) ?? null;
338
+ return memory2.cookie.get(key) ?? null;
204
339
  }
205
340
  try {
206
341
  const value = nativeStorage(store)?.getItem(key) ?? null;
207
342
  if (value !== null) return value;
208
343
  } catch {
209
344
  }
210
- return memory[store].get(key) ?? null;
345
+ return memory2[store].get(key) ?? null;
211
346
  }
212
347
  __name(rawGet, "rawGet");
213
348
  function rawSet(store, key, value, maxAgeSeconds) {
214
- if (!hasWindow()) return false;
349
+ if (!hasWindow2()) return false;
215
350
  try {
216
351
  if (store === "cookie") {
217
352
  const secure = window.location.protocol === "https:" ? "; Secure" : "";
@@ -219,24 +354,24 @@ function createStorage(owner, options = {}) {
219
354
  const domainPart = domain ? `; Domain=${domain}` : "";
220
355
  document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${Math.max(1, Math.floor(maxAgeSeconds ?? cookieMaxAge))}; SameSite=Lax${domainPart}${secure}`;
221
356
  if (domain) expireCookie(key, null);
222
- if (rawGet("cookie", key) === value && !memory.cookie.has(key)) return true;
223
- memory.cookie.set(key, value);
357
+ if (rawGet("cookie", key) === value && !memory2.cookie.has(key)) return true;
358
+ memory2.cookie.set(key, value);
224
359
  return false;
225
360
  }
226
361
  const native = nativeStorage(store);
227
362
  if (!native) throw new Error("storage unavailable");
228
363
  native.setItem(key, value);
229
- memory[store].delete(key);
364
+ memory2[store].delete(key);
230
365
  return true;
231
366
  } catch {
232
- memory[store].set(key, value);
367
+ memory2[store].set(key, value);
233
368
  return false;
234
369
  }
235
370
  }
236
371
  __name(rawSet, "rawSet");
237
372
  function rawRemove(store, key) {
238
- memory[store].delete(key);
239
- if (!hasWindow()) return;
373
+ memory2[store].delete(key);
374
+ if (!hasWindow2()) return;
240
375
  try {
241
376
  if (store === "cookie") {
242
377
  expireCookie(key, null);
@@ -265,7 +400,7 @@ function createStorage(owner, options = {}) {
265
400
  }
266
401
  } catch {
267
402
  }
268
- for (const name of memory[store].keys()) if (name.startsWith(startsWith) && !out.includes(name)) out.push(name);
403
+ for (const name of memory2[store].keys()) if (name.startsWith(startsWith) && !out.includes(name)) out.push(name);
269
404
  return out;
270
405
  }
271
406
  __name(listKeys, "listKeys");
@@ -337,7 +472,7 @@ function createStorage(owner, options = {}) {
337
472
  cookieDomain: resolveCookieDomain,
338
473
  onChange(key, listener, store = "local") {
339
474
  assertValid(key);
340
- if (!hasWindow()) return () => {
475
+ if (!hasWindow2()) return () => {
341
476
  };
342
477
  const handler = /* @__PURE__ */ __name((event) => {
343
478
  if (event.storageArea !== nativeStorage(store)) return;
@@ -361,6 +496,29 @@ var REFRESH_KEY = "cfg.auth.refresh_token";
361
496
  var API_KEY_KEY = "cfg.auth.api_key";
362
497
  var storage = true ? cfgStorage : createStorage2("cfg");
363
498
  var isBrowser = typeof window !== "undefined";
499
+ function trace(ev, fields) {
500
+ try {
501
+ const g = globalThis;
502
+ const sink = g.__cfgAuthTrace;
503
+ if (sink) {
504
+ sink(ev, fields);
505
+ return;
506
+ }
507
+ const queue = g.__cfgAuthTraceQ ?? [];
508
+ g.__cfgAuthTraceQ = queue;
509
+ if (queue.length < 100) queue.push([Date.now(), ev, fields]);
510
+ } catch {
511
+ }
512
+ }
513
+ __name(trace, "trace");
514
+ function pathOf(url) {
515
+ try {
516
+ return new URL(url, "http://x").pathname;
517
+ } catch {
518
+ return "";
519
+ }
520
+ }
521
+ __name(pathOf, "pathOf");
364
522
  function secondsUntilExp(token) {
365
523
  const exp = jwtExpMs(token);
366
524
  return exp === null ? void 0 : Math.max(1, Math.floor((exp - Date.now()) / 1e3));
@@ -520,7 +678,10 @@ __name(scheduleExpiryFlip, "scheduleExpiryFlip");
520
678
  function notifySessionChanged() {
521
679
  const next = computeSnapshot();
522
680
  const changed = next.status !== _snapshot.status || next.accessExpiresAt !== _snapshot.accessExpiresAt;
523
- if (changed) _snapshot = next;
681
+ if (changed) {
682
+ _snapshot = next;
683
+ trace("store.snapshot", { status: next.status });
684
+ }
524
685
  scheduleExpiryFlip();
525
686
  if (!changed) return;
526
687
  for (const listener of Array.from(_sessionListeners)) {
@@ -603,6 +764,7 @@ var auth = {
603
764
  return _storage.get(ACCESS_KEY);
604
765
  },
605
766
  setToken(token) {
767
+ trace("store.setToken", { present: token !== null });
606
768
  _storage.set(ACCESS_KEY, token);
607
769
  notifySessionChanged();
608
770
  },
@@ -610,14 +772,16 @@ var auth = {
610
772
  return _storage.get(REFRESH_KEY);
611
773
  },
612
774
  setRefreshToken(token) {
775
+ trace("store.setRefreshToken", { present: token !== null });
613
776
  _storage.set(REFRESH_KEY, token);
614
777
  notifySessionChanged();
615
778
  },
616
779
  clearTokens() {
780
+ trace("store.clearTokens");
617
781
  for (const mode of ["localStorage", "sessionStorage", "cookie"]) {
618
- const backend = backendFor(mode);
619
- backend.set(ACCESS_KEY, null);
620
- backend.set(REFRESH_KEY, null);
782
+ const backend2 = backendFor(mode);
783
+ backend2.set(ACCESS_KEY, null);
784
+ backend2.set(REFRESH_KEY, null);
621
785
  }
622
786
  storage.clearAll();
623
787
  notifySessionChanged();
@@ -636,6 +800,7 @@ var auth = {
636
800
  * rotation); `refresh: null` explicitly drops it.
637
801
  */
638
802
  setSession(tokens) {
803
+ trace("store.setSession", { refresh: tokens.refresh === void 0 ? "kept" : tokens.refresh === null ? "dropped" : "set" });
639
804
  _storage.set(ACCESS_KEY, tokens.access);
640
805
  if (tokens.refresh !== void 0) _storage.set(REFRESH_KEY, tokens.refresh);
641
806
  notifySessionChanged();
@@ -774,7 +939,11 @@ async function tryRefresh() {
774
939
  const refresh = auth.getRefreshToken();
775
940
  if (!refresh) return null;
776
941
  const result = await _refreshHandler(refresh);
777
- if (!result?.access) return null;
942
+ if (!result?.access) {
943
+ trace("refresh", { ok: false, why: "no-access" });
944
+ return null;
945
+ }
946
+ trace("refresh", { ok: true, rotated: Boolean(result.refresh) });
778
947
  auth.setToken(result.access);
779
948
  if (result.refresh) auth.setRefreshToken(result.refresh);
780
949
  return result.access;
@@ -787,6 +956,7 @@ async function tryRefresh() {
787
956
  }
788
957
  return await runRefresh();
789
958
  } catch {
959
+ trace("refresh", { ok: false, why: "threw" });
790
960
  return null;
791
961
  } finally {
792
962
  _refreshInflight = null;
@@ -795,7 +965,8 @@ async function tryRefresh() {
795
965
  return _refreshInflight;
796
966
  }
797
967
  __name(tryRefresh, "tryRefresh");
798
- function expireSession(response) {
968
+ function expireSession(response, why) {
969
+ trace("store.expire", { why, status: response.status, path: pathOf(response.url), handlers: _sessionExpiredHandlers.size });
799
970
  auth.clearTokens();
800
971
  for (const cb of Array.from(_sessionExpiredHandlers)) {
801
972
  try {
@@ -937,13 +1108,17 @@ function installAuthOnClient(client2) {
937
1108
  });
938
1109
  client2.interceptors.response.use(async (response, request) => {
939
1110
  if (response.status !== 401) return response;
1111
+ if (/\/accounts\/(otp|oauth|login|register|token)\b/.test(request.url)) {
1112
+ trace("401.passthrough", { path: pathOf(request.url) });
1113
+ return response;
1114
+ }
940
1115
  if (request.headers.get(RETRY_MARKER)) {
941
- expireSession(response);
1116
+ expireSession(response, "retry-marker");
942
1117
  return response;
943
1118
  }
944
1119
  const newToken = await tryRefresh();
945
1120
  if (!newToken) {
946
- expireSession(response);
1121
+ expireSession(response, "refresh-failed");
947
1122
  return response;
948
1123
  }
949
1124
  const retry = request.clone();
@@ -955,7 +1130,7 @@ function installAuthOnClient(client2) {
955
1130
  }
956
1131
  try {
957
1132
  const retried = await fetch(retry);
958
- if (retried.status === 401) expireSession(retried);
1133
+ if (retried.status === 401) expireSession(retried, "retry-401");
959
1134
  return retried;
960
1135
  } catch {
961
1136
  return response;