@djangocfg/api 2.1.603 → 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/storage.cjs CHANGED
@@ -25,16 +25,35 @@ __export(storage_exports, {
25
25
  CFG_KEYS: () => CFG_KEYS,
26
26
  cfgStorage: () => cfgStorage,
27
27
  createStorage: () => createStorage,
28
- normalizeSegment: () => normalizeSegment
28
+ normalizeSegment: () => normalizeSegment,
29
+ readCookie: () => readCookie
29
30
  });
30
31
  module.exports = __toCommonJS(storage_exports);
31
32
 
33
+ // src/cookies.ts
34
+ function readCookie(cookieHeader, name) {
35
+ if (!cookieHeader) return null;
36
+ const wanted = encodeURIComponent(name);
37
+ for (const part of cookieHeader.split(";")) {
38
+ const eq = part.indexOf("=");
39
+ if (eq < 0) continue;
40
+ if (part.slice(0, eq).trim() !== wanted) continue;
41
+ try {
42
+ return decodeURIComponent(part.slice(eq + 1).trim());
43
+ } catch {
44
+ return null;
45
+ }
46
+ }
47
+ return null;
48
+ }
49
+ __name(readCookie, "readCookie");
50
+
32
51
  // src/_api/generated/helpers/keys.ts
33
52
  var k = /* @__PURE__ */ __name((key, store, personal) => ({ key, store, personal }), "k");
34
53
  var f = /* @__PURE__ */ __name((prefix, store, personal) => ({ prefix, store, personal }), "f");
35
54
  var CFG_KEYS = {
36
- accessToken: k("cfg.auth.access_token", "local", true),
37
- refreshToken: k("cfg.auth.refresh_token", "local", true),
55
+ accessToken: k("cfg.auth.access_token", "cookie", true),
56
+ refreshToken: k("cfg.auth.refresh_token", "cookie", true),
38
57
  apiKey: k("cfg.auth.api_key", "local", true),
39
58
  email: k("cfg.auth.email", "local", false),
40
59
  emailTs: k("cfg.auth.email_ts", "local", false),
@@ -69,6 +88,31 @@ function normalizeSegment(raw) {
69
88
  }
70
89
  __name(normalizeSegment, "normalizeSegment");
71
90
  var hasWindow = /* @__PURE__ */ __name(() => typeof window !== "undefined", "hasWindow");
91
+ var domainByHost = /* @__PURE__ */ new Map();
92
+ function detectCookieDomain() {
93
+ if (!hasWindow() || typeof document === "undefined") return null;
94
+ const host = window.location.hostname.toLowerCase();
95
+ if (!host || !host.includes(".") || host.includes(":") || /^[0-9.]+$/.test(host)) return null;
96
+ const cached = domainByHost.get(host);
97
+ if (cached !== void 0) return cached;
98
+ const labels = host.split(".");
99
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
100
+ let found = null;
101
+ try {
102
+ for (let i = labels.length - 2; i >= 0 && found === null; i -= 1) {
103
+ const candidate = labels.slice(i).join(".");
104
+ const probe = "cfg_probe_" + Math.random().toString(36).slice(2);
105
+ document.cookie = probe + "=1; Domain=" + candidate + "; Path=/; Max-Age=30; SameSite=Lax" + secure;
106
+ if (document.cookie.includes(probe + "=1")) found = candidate;
107
+ document.cookie = probe + "=; Domain=" + candidate + "; Path=/; Max-Age=0; SameSite=Lax" + secure;
108
+ }
109
+ } catch {
110
+ found = null;
111
+ }
112
+ domainByHost.set(host, found);
113
+ return found;
114
+ }
115
+ __name(detectCookieDomain, "detectCookieDomain");
72
116
  function nativeStorage(store) {
73
117
  if (!hasWindow()) return null;
74
118
  try {
@@ -94,6 +138,12 @@ function createStorage(owner, options = {}) {
94
138
  const prefix = `${owner}.`;
95
139
  const pattern = owner === "cfg" ? /^cfg(\.[a-z0-9_]+)+$/ : new RegExp(`^(cfg|${owner})(\\.[a-z0-9_]+)+$`);
96
140
  const cookieMaxAge = options.cookieMaxAgeSeconds ?? 60 * 60 * 24 * 30;
141
+ let cookiePolicy = options.cookieDomain ?? "auto";
142
+ const resolveCookieDomain = /* @__PURE__ */ __name(() => cookiePolicy === false ? null : cookiePolicy === "auto" ? detectCookieDomain() : cookiePolicy, "resolveCookieDomain");
143
+ const expireCookie = /* @__PURE__ */ __name((key, domain) => {
144
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
145
+ document.cookie = encodeURIComponent(key) + "=; Path=/; Max-Age=0; SameSite=Lax" + (domain ? "; Domain=" + domain : "") + secure;
146
+ }, "expireCookie");
97
147
  const specs = Object.values(options.keys ?? {});
98
148
  const families = Object.values(options.families ?? {});
99
149
  const specByKey = /* @__PURE__ */ new Map();
@@ -130,12 +180,15 @@ function createStorage(owner, options = {}) {
130
180
  return memory[store].get(key) ?? null;
131
181
  }
132
182
  __name(rawGet, "rawGet");
133
- function rawSet(store, key, value) {
183
+ function rawSet(store, key, value, maxAgeSeconds) {
134
184
  if (!hasWindow()) return false;
135
185
  try {
136
186
  if (store === "cookie") {
137
187
  const secure = window.location.protocol === "https:" ? "; Secure" : "";
138
- document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${cookieMaxAge}; SameSite=Lax${secure}`;
188
+ const domain = resolveCookieDomain();
189
+ const domainPart = domain ? `; Domain=${domain}` : "";
190
+ document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${Math.max(1, Math.floor(maxAgeSeconds ?? cookieMaxAge))}; SameSite=Lax${domainPart}${secure}`;
191
+ if (domain) expireCookie(key, null);
139
192
  if (rawGet("cookie", key) === value && !memory.cookie.has(key)) return true;
140
193
  memory.cookie.set(key, value);
141
194
  return false;
@@ -156,8 +209,9 @@ function createStorage(owner, options = {}) {
156
209
  if (!hasWindow()) return;
157
210
  try {
158
211
  if (store === "cookie") {
159
- const secure = window.location.protocol === "https:" ? "; Secure" : "";
160
- document.cookie = `${encodeURIComponent(key)}=; Path=/; Max-Age=0; SameSite=Lax${secure}`;
212
+ expireCookie(key, null);
213
+ const domain = resolveCookieDomain();
214
+ if (domain) expireCookie(key, domain);
161
215
  } else {
162
216
  nativeStorage(store)?.removeItem(key);
163
217
  }
@@ -206,10 +260,10 @@ function createStorage(owner, options = {}) {
206
260
  const target = resolveStore(key, store);
207
261
  return rawGet(target, key);
208
262
  },
209
- write(key, value, store) {
263
+ write(key, value, store, writeOptions) {
210
264
  assertOwned(key);
211
265
  const target = resolveStore(key, store);
212
- return rawSet(target, key, value);
266
+ return rawSet(target, key, value, writeOptions?.maxAgeSeconds);
213
267
  },
214
268
  remove(key, store) {
215
269
  assertOwned(key);
@@ -247,6 +301,10 @@ function createStorage(owner, options = {}) {
247
301
  for (const name of cookieNames()) if (name.startsWith(prefix)) rawRemove("cookie", name);
248
302
  }
249
303
  },
304
+ setCookieDomain(domain) {
305
+ cookiePolicy = domain;
306
+ },
307
+ cookieDomain: resolveCookieDomain,
250
308
  onChange(key, listener, store = "local") {
251
309
  assertValid(key);
252
310
  if (!hasWindow()) return () => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/storage.ts","../src/_api/generated/helpers/keys.ts"],"sourcesContent":["/**\n * `@djangocfg/api/storage` — the browser-storage key registry on its own.\n *\n * Zero dependencies and no client: packages that only need a key, a guarded\n * read/write or `createStorage('<owner>')` import this, not the generated SDK.\n * The source is the generated `helpers/keys.ts`.\n */\nexport {\n CFG_FAMILIES,\n CFG_KEYS,\n cfgStorage,\n createStorage,\n normalizeSegment,\n} from './_api/generated/helpers/keys';\nexport type {\n FamilySpec,\n GuardedStorage,\n KeySpec,\n KeyStore,\n StorageOptions,\n} from './_api/generated/helpers/keys';\n","// AUTO-GENERATED by django_generator / ts_extras.wrapper\n// Browser-storage key registry: one scheme, guarded access.\n// DO NOT EDIT — re-run `make gen`.\n//\n// Rules for agents and apps: @docs/STORAGE_KEYS.md in @djangocfg/api.\n//\n// Scheme: `<owner>.<area>.<name>` — lower case, dots between levels,\n// `snake_case` inside a level. The framework's owner is `cfg`; an app picks its\n// own with `createStorage('<owner>')`. Third-party keys (a library's own\n// prefix, `NEXT_LOCALE`) are not ours to rename and stay as they are.\n\nexport type KeyStore = 'local' | 'session' | 'cookie';\n\nexport interface KeySpec {\n /** The canonical key. */\n readonly key: string;\n readonly store: KeyStore;\n /** Removed by `clearAll()` (sign-out). Preferences are kept. */\n readonly personal: boolean;\n}\n\nexport interface FamilySpec {\n /** Canonical prefix ending in a dot; the id is appended in normalised form. */\n readonly prefix: string;\n readonly store: 'local' | 'session';\n readonly personal: boolean;\n}\n\nconst k = (\n key: string,\n store: KeyStore,\n personal: boolean,\n): KeySpec => ({ key, store, personal });\n\nconst f = (\n prefix: string,\n store: 'local' | 'session',\n personal: boolean,\n): FamilySpec => ({ prefix, store, personal });\n\n/** Every key the framework writes. No legacy spellings are read: old keys are simply ignored. */\nexport const CFG_KEYS = {\n accessToken: k('cfg.auth.access_token', 'local', true),\n refreshToken: k('cfg.auth.refresh_token', 'local', true),\n apiKey: k('cfg.auth.api_key', 'local', true),\n email: k('cfg.auth.email', 'local', false),\n emailTs: k('cfg.auth.email_ts', 'local', false),\n redirectUrl: k('cfg.auth.redirect_url', 'session', true),\n redirectUrlTs: k('cfg.auth.redirect_url_ts', 'session', true),\n oauthState: k('cfg.auth.oauth_state', 'session', true),\n oauthProvider: k('cfg.auth.oauth_provider', 'session', true),\n oauthProviders: k('cfg.auth.oauth_providers', 'session', false),\n profileCache: k('cfg.profile.cache', 'local', true),\n monitorSessionId: k('cfg.monitor.session_id', 'local', false),\n monitorSessionCookie: k('cfg.monitor.session_id', 'cookie', false),\n monitorDebug: k('cfg.monitor.debug', 'local', false),\n uiTabId: k('cfg.ui.tab_id', 'session', false),\n uiRouterSerial: k('cfg.ui.router_serial', 'session', false),\n uiState: k('cfg.ui.state', 'local', false),\n chatSpeechLanguage: k('cfg.chat.speech_language', 'local', false),\n chatRecentTools: k('cfg.chat.recent_tools', 'local', false),\n formsSpeechDebug: k('cfg.forms.speech_debug', 'local', false),\n formsSpeechPrefs: k('cfg.forms.speech_prefs', 'local', false),\n agentPlaygroundApiKeyId: k('cfg.agent.playground_api_key_id', 'session', true),\n agentPlaygroundBearer: k('cfg.agent.playground_bearer', 'session', true),\n agentEndpointDoc: k('cfg.agent.endpoint_doc', 'session', false),\n} as const satisfies Record<string, KeySpec>;\n\n/** Keys with a caller-supplied id part: one per room, tree, endpoint. */\nexport const CFG_FAMILIES = {\n chatDraft: f('cfg.chat.draft.', 'session', true),\n dataTree: f('cfg.data.tree.', 'local', false),\n agentEndpointDraft: f('cfg.agent.endpoint_draft.', 'local', false),\n} as const satisfies Record<string, FamilySpec>;\n\nconst OWNER_RE = /^[a-z][a-z0-9_]*$/;\n\n/** One segment of a key: lower case, `[a-z0-9_]`, anything else folded to `_`. */\nexport function normalizeSegment(raw: string): string {\n return raw\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9_]+/g, '_')\n .replace(/^_+|_+$/g, '');\n}\n\nexport interface StorageOptions {\n /** Named keys of this owner. */\n readonly keys?: Readonly<Record<string, KeySpec>>;\n readonly families?: Readonly<Record<string, FamilySpec>>;\n /** Cookie lifetime for the `cookie` store. Default 30 days. */\n readonly cookieMaxAgeSeconds?: number;\n}\n\nexport interface GuardedStorage {\n readonly owner: string;\n /** Builds `<owner>.<part>.<part>` from free-form parts; throws if a part is empty. */\n key(...parts: string[]): string;\n /** Builds a family member key: the prefix plus the normalised id. */\n familyKey(family: FamilySpec, id: string): string;\n /** `^(cfg|<owner>)(\\.[a-z0-9_]+)+$`. */\n isValid(key: string): boolean;\n read(key: string, store?: KeyStore): string | null;\n /** True when the value reached the browser's storage; false means it is held in memory for this page only. */\n write(key: string, value: string, store?: KeyStore): boolean;\n /** Removes the key. */\n remove(key: string, store?: KeyStore): void;\n readJSON<T>(key: string, store?: KeyStore): T | null;\n writeJSON(key: string, value: unknown, store?: KeyStore): boolean;\n /** Keys this owner holds in `store`. */\n keys(store?: Exclude<KeyStore, 'cookie'>): string[];\n /** Sign-out: removes the `personal` keys. `{ all: true }` removes everything under this owner. */\n clearAll(options?: { all?: boolean }): void;\n /** Cross-tab: calls `listener` with the new value when ANOTHER tab changes `key`. Cookies fire no events. */\n onChange(key: string, listener: (value: string | null) => void, store?: Exclude<KeyStore, 'cookie'>): () => void;\n}\n\nconst hasWindow = () => typeof window !== 'undefined';\n\nfunction nativeStorage(store: 'local' | 'session'): Storage | null {\n if (!hasWindow()) return null;\n try {\n return store === 'session' ? window.sessionStorage : window.localStorage;\n } catch {\n return null;\n }\n}\n\nfunction cookieNames(): string[] {\n if (!hasWindow()) return [];\n try {\n return document.cookie\n .split('; ')\n .map((part) => decodeURIComponent(part.split('=')[0] ?? ''))\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\nexport function createStorage(owner: string, options: StorageOptions = {}): GuardedStorage {\n if (!OWNER_RE.test(owner)) {\n throw new TypeError(`createStorage: owner \"${owner}\" must match ${OWNER_RE}`);\n }\n const prefix = `${owner}.`;\n const pattern = owner === 'cfg' ? /^cfg(\\.[a-z0-9_]+)+$/ : new RegExp(`^(cfg|${owner})(\\\\.[a-z0-9_]+)+$`);\n const cookieMaxAge = options.cookieMaxAgeSeconds ?? 60 * 60 * 24 * 30;\n const specs = Object.values(options.keys ?? {});\n const families = Object.values(options.families ?? {});\n const specByKey = new Map<string, KeySpec[]>();\n for (const spec of specs) specByKey.set(spec.key, [...(specByKey.get(spec.key) ?? []), spec]);\n // Held in memory when the browser refuses a write (quota, private mode), so the page still works until reload.\n const memory: Record<KeyStore, Map<string, string>> = {\n local: new Map(),\n session: new Map(),\n cookie: new Map(),\n };\n\n const isValid = (key: string) => pattern.test(key);\n const assertValid = (key: string) => {\n if (!isValid(key)) throw new TypeError(`storage key \"${key}\" must match ${pattern}`);\n };\n const assertOwned = (key: string) => {\n assertValid(key);\n if (!key.startsWith(prefix)) throw new TypeError(`storage key \"${key}\" is not owned by \"${owner}\"`);\n };\n\n function rawGet(store: KeyStore, key: string): string | null {\n if (!hasWindow()) return null;\n if (store === 'cookie') {\n try {\n const escaped = encodeURIComponent(key).replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${escaped}=([^;]*)`));\n if (match?.[1] !== undefined) return decodeURIComponent(match[1]);\n } catch {\n /* fall through to memory */\n }\n return memory.cookie.get(key) ?? null;\n }\n try {\n const value = nativeStorage(store)?.getItem(key) ?? null;\n if (value !== null) return value;\n } catch {\n /* fall through to memory */\n }\n return memory[store].get(key) ?? null;\n }\n\n function rawSet(store: KeyStore, key: string, value: string): boolean {\n if (!hasWindow()) return false;\n try {\n if (store === 'cookie') {\n const secure = window.location.protocol === 'https:' ? '; Secure' : '';\n document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${cookieMaxAge}; SameSite=Lax${secure}`;\n if (rawGet('cookie', key) === value && !memory.cookie.has(key)) return true;\n memory.cookie.set(key, value);\n return false;\n }\n const native = nativeStorage(store);\n if (!native) throw new Error('storage unavailable');\n native.setItem(key, value);\n memory[store].delete(key);\n return true;\n } catch {\n memory[store].set(key, value);\n return false;\n }\n }\n\n function rawRemove(store: KeyStore, key: string): void {\n memory[store].delete(key);\n if (!hasWindow()) return;\n try {\n if (store === 'cookie') {\n const secure = window.location.protocol === 'https:' ? '; Secure' : '';\n document.cookie = `${encodeURIComponent(key)}=; Path=/; Max-Age=0; SameSite=Lax${secure}`;\n } else {\n nativeStorage(store)?.removeItem(key);\n }\n } catch {\n /* ignore */\n }\n }\n\n function resolveStore(key: string, store?: KeyStore): KeyStore {\n return store ?? specByKey.get(key)?.[0]?.store ?? 'local';\n }\n\n function listKeys(store: 'local' | 'session', startsWith: string): string[] {\n const out: string[] = [];\n try {\n const native = nativeStorage(store);\n if (native) {\n for (let i = 0; i < native.length; i += 1) {\n const name = native.key(i);\n if (name?.startsWith(startsWith)) out.push(name);\n }\n }\n } catch {\n /* ignore */\n }\n for (const name of memory[store].keys()) if (name.startsWith(startsWith) && !out.includes(name)) out.push(name);\n return out;\n }\n\n const familyKey = (family: FamilySpec, id: string) => {\n const part = normalizeSegment(id);\n if (!part) throw new TypeError('storage family id is empty after normalisation');\n return family.prefix + part;\n };\n\n const api: GuardedStorage = {\n owner,\n key(...parts) {\n const segments = parts.map(normalizeSegment);\n if (segments.length === 0 || segments.some((segment) => !segment)) {\n throw new TypeError(`storage key parts must be non-empty: ${JSON.stringify(parts)}`);\n }\n return `${prefix}${segments.join('.')}`;\n },\n familyKey,\n isValid,\n read(key, store) {\n assertValid(key);\n const target = resolveStore(key, store);\n return rawGet(target, key);\n },\n write(key, value, store) {\n assertOwned(key);\n const target = resolveStore(key, store);\n return rawSet(target, key, value);\n },\n remove(key, store) {\n assertOwned(key);\n const target = resolveStore(key, store);\n rawRemove(target, key);\n },\n readJSON<T>(key: string, store?: KeyStore): T | null {\n const raw = api.read(key, store);\n if (raw === null) return null;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n },\n writeJSON(key, value, store) {\n return api.write(key, JSON.stringify(value), store);\n },\n keys(store = 'local') {\n return listKeys(store, prefix);\n },\n clearAll({ all = false } = {}) {\n for (const spec of specs) {\n if (!all && !spec.personal) continue;\n rawRemove(spec.store, spec.key);\n }\n for (const family of families) {\n if (!all && !family.personal) continue;\n for (const name of listKeys(family.store, family.prefix)) rawRemove(family.store, name);\n }\n if (all) {\n for (const store of ['local', 'session'] as const) {\n for (const name of listKeys(store, prefix)) rawRemove(store, name);\n }\n for (const name of cookieNames()) if (name.startsWith(prefix)) rawRemove('cookie', name);\n }\n },\n onChange(key, listener, store = 'local') {\n assertValid(key);\n if (!hasWindow()) return () => {};\n const handler = (event: StorageEvent) => {\n if (event.storageArea !== nativeStorage(store)) return;\n if (event.key === null || event.key === key) listener(event.key === null ? null : event.newValue);\n };\n window.addEventListener('storage', handler);\n return () => window.removeEventListener('storage', handler);\n },\n };\n return api;\n}\n\n/** The framework's own storage: every `cfg.*` key. */\nexport const cfgStorage: GuardedStorage = createStorage('cfg', {\n keys: CFG_KEYS,\n families: CFG_FAMILIES,\n});\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC4BA,IAAM,IAAI,wBACR,KACA,OACA,cACa,EAAE,KAAK,OAAO,SAAS,IAJ5B;AAMV,IAAM,IAAI,wBACR,QACA,OACA,cACgB,EAAE,QAAQ,OAAO,SAAS,IAJlC;AAOH,IAAM,WAAW;AAAA,EACtB,aAAa,EAAE,yBAAyB,SAAS,IAAI;AAAA,EACrD,cAAc,EAAE,0BAA0B,SAAS,IAAI;AAAA,EACvD,QAAQ,EAAE,oBAAoB,SAAS,IAAI;AAAA,EAC3C,OAAO,EAAE,kBAAkB,SAAS,KAAK;AAAA,EACzC,SAAS,EAAE,qBAAqB,SAAS,KAAK;AAAA,EAC9C,aAAa,EAAE,yBAAyB,WAAW,IAAI;AAAA,EACvD,eAAe,EAAE,4BAA4B,WAAW,IAAI;AAAA,EAC5D,YAAY,EAAE,wBAAwB,WAAW,IAAI;AAAA,EACrD,eAAe,EAAE,2BAA2B,WAAW,IAAI;AAAA,EAC3D,gBAAgB,EAAE,4BAA4B,WAAW,KAAK;AAAA,EAC9D,cAAc,EAAE,qBAAqB,SAAS,IAAI;AAAA,EAClD,kBAAkB,EAAE,0BAA0B,SAAS,KAAK;AAAA,EAC5D,sBAAsB,EAAE,0BAA0B,UAAU,KAAK;AAAA,EACjE,cAAc,EAAE,qBAAqB,SAAS,KAAK;AAAA,EACnD,SAAS,EAAE,iBAAiB,WAAW,KAAK;AAAA,EAC5C,gBAAgB,EAAE,wBAAwB,WAAW,KAAK;AAAA,EAC1D,SAAS,EAAE,gBAAgB,SAAS,KAAK;AAAA,EACzC,oBAAoB,EAAE,4BAA4B,SAAS,KAAK;AAAA,EAChE,iBAAiB,EAAE,yBAAyB,SAAS,KAAK;AAAA,EAC1D,kBAAkB,EAAE,0BAA0B,SAAS,KAAK;AAAA,EAC5D,kBAAkB,EAAE,0BAA0B,SAAS,KAAK;AAAA,EAC5D,yBAAyB,EAAE,mCAAmC,WAAW,IAAI;AAAA,EAC7E,uBAAuB,EAAE,+BAA+B,WAAW,IAAI;AAAA,EACvE,kBAAkB,EAAE,0BAA0B,WAAW,KAAK;AAChE;AAGO,IAAM,eAAe;AAAA,EAC1B,WAAW,EAAE,mBAAmB,WAAW,IAAI;AAAA,EAC/C,UAAU,EAAE,kBAAkB,SAAS,KAAK;AAAA,EAC5C,oBAAoB,EAAE,6BAA6B,SAAS,KAAK;AACnE;AAEA,IAAM,WAAW;AAGV,SAAS,iBAAiB,KAAqB;AACpD,SAAO,IACJ,KAAK,EACL,YAAY,EACZ,QAAQ,gBAAgB,GAAG,EAC3B,QAAQ,YAAY,EAAE;AAC3B;AANgB;AAuChB,IAAM,YAAY,6BAAM,OAAO,WAAW,aAAxB;AAElB,SAAS,cAAc,OAA4C;AACjE,MAAI,CAAC,UAAU,EAAG,QAAO;AACzB,MAAI;AACF,WAAO,UAAU,YAAY,OAAO,iBAAiB,OAAO;AAAA,EAC9D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAPS;AAST,SAAS,cAAwB;AAC/B,MAAI,CAAC,UAAU,EAAG,QAAO,CAAC;AAC1B,MAAI;AACF,WAAO,SAAS,OACb,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,mBAAmB,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,EAC1D,OAAO,OAAO;AAAA,EACnB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAVS;AAYF,SAAS,cAAc,OAAe,UAA0B,CAAC,GAAmB;AACzF,MAAI,CAAC,SAAS,KAAK,KAAK,GAAG;AACzB,UAAM,IAAI,UAAU,yBAAyB,KAAK,gBAAgB,QAAQ,EAAE;AAAA,EAC9E;AACA,QAAM,SAAS,GAAG,KAAK;AACvB,QAAM,UAAU,UAAU,QAAQ,yBAAyB,IAAI,OAAO,SAAS,KAAK,oBAAoB;AACxG,QAAM,eAAe,QAAQ,uBAAuB,KAAK,KAAK,KAAK;AACnE,QAAM,QAAQ,OAAO,OAAO,QAAQ,QAAQ,CAAC,CAAC;AAC9C,QAAM,WAAW,OAAO,OAAO,QAAQ,YAAY,CAAC,CAAC;AACrD,QAAM,YAAY,oBAAI,IAAuB;AAC7C,aAAW,QAAQ,MAAO,WAAU,IAAI,KAAK,KAAK,CAAC,GAAI,UAAU,IAAI,KAAK,GAAG,KAAK,CAAC,GAAI,IAAI,CAAC;AAE5F,QAAM,SAAgD;AAAA,IACpD,OAAO,oBAAI,IAAI;AAAA,IACf,SAAS,oBAAI,IAAI;AAAA,IACjB,QAAQ,oBAAI,IAAI;AAAA,EAClB;AAEA,QAAM,UAAU,wBAAC,QAAgB,QAAQ,KAAK,GAAG,GAAjC;AAChB,QAAM,cAAc,wBAAC,QAAgB;AACnC,QAAI,CAAC,QAAQ,GAAG,EAAG,OAAM,IAAI,UAAU,gBAAgB,GAAG,gBAAgB,OAAO,EAAE;AAAA,EACrF,GAFoB;AAGpB,QAAM,cAAc,wBAAC,QAAgB;AACnC,gBAAY,GAAG;AACf,QAAI,CAAC,IAAI,WAAW,MAAM,EAAG,OAAM,IAAI,UAAU,gBAAgB,GAAG,sBAAsB,KAAK,GAAG;AAAA,EACpG,GAHoB;AAKpB,WAAS,OAAO,OAAiB,KAA4B;AAC3D,QAAI,CAAC,UAAU,EAAG,QAAO;AACzB,QAAI,UAAU,UAAU;AACtB,UAAI;AACF,cAAM,UAAU,mBAAmB,GAAG,EAAE,QAAQ,uBAAuB,MAAM;AAC7E,cAAM,QAAQ,SAAS,OAAO,MAAM,IAAI,OAAO,cAAc,OAAO,UAAU,CAAC;AAC/E,YAAI,QAAQ,CAAC,MAAM,OAAW,QAAO,mBAAmB,MAAM,CAAC,CAAC;AAAA,MAClE,QAAQ;AAAA,MAER;AACA,aAAO,OAAO,OAAO,IAAI,GAAG,KAAK;AAAA,IACnC;AACA,QAAI;AACF,YAAM,QAAQ,cAAc,KAAK,GAAG,QAAQ,GAAG,KAAK;AACpD,UAAI,UAAU,KAAM,QAAO;AAAA,IAC7B,QAAQ;AAAA,IAER;AACA,WAAO,OAAO,KAAK,EAAE,IAAI,GAAG,KAAK;AAAA,EACnC;AAnBS;AAqBT,WAAS,OAAO,OAAiB,KAAa,OAAwB;AACpE,QAAI,CAAC,UAAU,EAAG,QAAO;AACzB,QAAI;AACF,UAAI,UAAU,UAAU;AACtB,cAAM,SAAS,OAAO,SAAS,aAAa,WAAW,aAAa;AACpE,iBAAS,SAAS,GAAG,mBAAmB,GAAG,CAAC,IAAI,mBAAmB,KAAK,CAAC,qBAAqB,YAAY,iBAAiB,MAAM;AACjI,YAAI,OAAO,UAAU,GAAG,MAAM,SAAS,CAAC,OAAO,OAAO,IAAI,GAAG,EAAG,QAAO;AACvE,eAAO,OAAO,IAAI,KAAK,KAAK;AAC5B,eAAO;AAAA,MACT;AACA,YAAM,SAAS,cAAc,KAAK;AAClC,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,qBAAqB;AAClD,aAAO,QAAQ,KAAK,KAAK;AACzB,aAAO,KAAK,EAAE,OAAO,GAAG;AACxB,aAAO;AAAA,IACT,QAAQ;AACN,aAAO,KAAK,EAAE,IAAI,KAAK,KAAK;AAC5B,aAAO;AAAA,IACT;AAAA,EACF;AAnBS;AAqBT,WAAS,UAAU,OAAiB,KAAmB;AACrD,WAAO,KAAK,EAAE,OAAO,GAAG;AACxB,QAAI,CAAC,UAAU,EAAG;AAClB,QAAI;AACF,UAAI,UAAU,UAAU;AACtB,cAAM,SAAS,OAAO,SAAS,aAAa,WAAW,aAAa;AACpE,iBAAS,SAAS,GAAG,mBAAmB,GAAG,CAAC,qCAAqC,MAAM;AAAA,MACzF,OAAO;AACL,sBAAc,KAAK,GAAG,WAAW,GAAG;AAAA,MACtC;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAbS;AAeT,WAAS,aAAa,KAAa,OAA4B;AAC7D,WAAO,SAAS,UAAU,IAAI,GAAG,IAAI,CAAC,GAAG,SAAS;AAAA,EACpD;AAFS;AAIT,WAAS,SAAS,OAA4B,YAA8B;AAC1E,UAAM,MAAgB,CAAC;AACvB,QAAI;AACF,YAAM,SAAS,cAAc,KAAK;AAClC,UAAI,QAAQ;AACV,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,GAAG;AACzC,gBAAM,OAAO,OAAO,IAAI,CAAC;AACzB,cAAI,MAAM,WAAW,UAAU,EAAG,KAAI,KAAK,IAAI;AAAA,QACjD;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AACA,eAAW,QAAQ,OAAO,KAAK,EAAE,KAAK,EAAG,KAAI,KAAK,WAAW,UAAU,KAAK,CAAC,IAAI,SAAS,IAAI,EAAG,KAAI,KAAK,IAAI;AAC9G,WAAO;AAAA,EACT;AAfS;AAiBT,QAAM,YAAY,wBAAC,QAAoB,OAAe;AACpD,UAAM,OAAO,iBAAiB,EAAE;AAChC,QAAI,CAAC,KAAM,OAAM,IAAI,UAAU,gDAAgD;AAC/E,WAAO,OAAO,SAAS;AAAA,EACzB,GAJkB;AAMlB,QAAM,MAAsB;AAAA,IAC1B;AAAA,IACA,OAAO,OAAO;AACZ,YAAM,WAAW,MAAM,IAAI,gBAAgB;AAC3C,UAAI,SAAS,WAAW,KAAK,SAAS,KAAK,CAAC,YAAY,CAAC,OAAO,GAAG;AACjE,cAAM,IAAI,UAAU,wCAAwC,KAAK,UAAU,KAAK,CAAC,EAAE;AAAA,MACrF;AACA,aAAO,GAAG,MAAM,GAAG,SAAS,KAAK,GAAG,CAAC;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAK,KAAK,OAAO;AACf,kBAAY,GAAG;AACf,YAAM,SAAS,aAAa,KAAK,KAAK;AACtC,aAAO,OAAO,QAAQ,GAAG;AAAA,IAC3B;AAAA,IACA,MAAM,KAAK,OAAO,OAAO;AACvB,kBAAY,GAAG;AACf,YAAM,SAAS,aAAa,KAAK,KAAK;AACtC,aAAO,OAAO,QAAQ,KAAK,KAAK;AAAA,IAClC;AAAA,IACA,OAAO,KAAK,OAAO;AACjB,kBAAY,GAAG;AACf,YAAM,SAAS,aAAa,KAAK,KAAK;AACtC,gBAAU,QAAQ,GAAG;AAAA,IACvB;AAAA,IACA,SAAY,KAAa,OAA4B;AACnD,YAAM,MAAM,IAAI,KAAK,KAAK,KAAK;AAC/B,UAAI,QAAQ,KAAM,QAAO;AACzB,UAAI;AACF,eAAO,KAAK,MAAM,GAAG;AAAA,MACvB,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,UAAU,KAAK,OAAO,OAAO;AAC3B,aAAO,IAAI,MAAM,KAAK,KAAK,UAAU,KAAK,GAAG,KAAK;AAAA,IACpD;AAAA,IACA,KAAK,QAAQ,SAAS;AACpB,aAAO,SAAS,OAAO,MAAM;AAAA,IAC/B;AAAA,IACA,SAAS,EAAE,MAAM,MAAM,IAAI,CAAC,GAAG;AAC7B,iBAAW,QAAQ,OAAO;AACxB,YAAI,CAAC,OAAO,CAAC,KAAK,SAAU;AAC5B,kBAAU,KAAK,OAAO,KAAK,GAAG;AAAA,MAChC;AACA,iBAAW,UAAU,UAAU;AAC7B,YAAI,CAAC,OAAO,CAAC,OAAO,SAAU;AAC9B,mBAAW,QAAQ,SAAS,OAAO,OAAO,OAAO,MAAM,EAAG,WAAU,OAAO,OAAO,IAAI;AAAA,MACxF;AACA,UAAI,KAAK;AACP,mBAAW,SAAS,CAAC,SAAS,SAAS,GAAY;AACjD,qBAAW,QAAQ,SAAS,OAAO,MAAM,EAAG,WAAU,OAAO,IAAI;AAAA,QACnE;AACA,mBAAW,QAAQ,YAAY,EAAG,KAAI,KAAK,WAAW,MAAM,EAAG,WAAU,UAAU,IAAI;AAAA,MACzF;AAAA,IACF;AAAA,IACA,SAAS,KAAK,UAAU,QAAQ,SAAS;AACvC,kBAAY,GAAG;AACf,UAAI,CAAC,UAAU,EAAG,QAAO,MAAM;AAAA,MAAC;AAChC,YAAM,UAAU,wBAAC,UAAwB;AACvC,YAAI,MAAM,gBAAgB,cAAc,KAAK,EAAG;AAChD,YAAI,MAAM,QAAQ,QAAQ,MAAM,QAAQ,IAAK,UAAS,MAAM,QAAQ,OAAO,OAAO,MAAM,QAAQ;AAAA,MAClG,GAHgB;AAIhB,aAAO,iBAAiB,WAAW,OAAO;AAC1C,aAAO,MAAM,OAAO,oBAAoB,WAAW,OAAO;AAAA,IAC5D;AAAA,EACF;AACA,SAAO;AACT;AApLgB;AAuLT,IAAM,aAA6B,cAAc,OAAO;AAAA,EAC7D,MAAM;AAAA,EACN,UAAU;AACZ,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/storage.ts","../src/cookies.ts","../src/_api/generated/helpers/keys.ts"],"sourcesContent":["/**\n * `@djangocfg/api/storage` — the browser-storage key registry on its own.\n *\n * Zero dependencies and no client: packages that only need a key, a guarded\n * read/write or `createStorage('<owner>')` import this, not the generated SDK.\n * The source is the generated `helpers/keys.ts`.\n */\nexport { readCookie } from './cookies';\nexport {\n CFG_FAMILIES,\n CFG_KEYS,\n cfgStorage,\n createStorage,\n normalizeSegment,\n} from './_api/generated/helpers/keys';\nexport type {\n FamilySpec,\n GuardedStorage,\n KeySpec,\n KeyStore,\n StorageOptions,\n WriteOptions,\n} from './_api/generated/helpers/keys';\n","/**\n * Server-safe cookie header parsing, for SSR code that has the raw `Cookie` header\n * (Next.js `headers()`, a Node request) and wants the shared session cookie.\n * No DOM, no dependencies.\n */\n\n/** The value of cookie `name` in a `Cookie` request header, or `null`. */\nexport function readCookie(cookieHeader: string | null | undefined, name: string): string | null {\n if (!cookieHeader) return null;\n const wanted = encodeURIComponent(name);\n for (const part of cookieHeader.split(';')) {\n const eq = part.indexOf('=');\n if (eq < 0) continue;\n if (part.slice(0, eq).trim() !== wanted) continue;\n try {\n return decodeURIComponent(part.slice(eq + 1).trim());\n } catch {\n return null;\n }\n }\n return null;\n}\n","// AUTO-GENERATED by django_generator / ts_extras.wrapper\n// Browser-storage key registry: one scheme, guarded access.\n// DO NOT EDIT — re-run `make gen`.\n//\n// Rules for agents and apps: @docs/STORAGE_KEYS.md in @djangocfg/api.\n//\n// Scheme: `<owner>.<area>.<name>` — lower case, dots between levels,\n// `snake_case` inside a level. The framework's owner is `cfg`; an app picks its\n// own with `createStorage('<owner>')`. Third-party keys (a library's own\n// prefix, `NEXT_LOCALE`) are not ours to rename and stay as they are.\n\nexport type KeyStore = 'local' | 'session' | 'cookie';\n\nexport interface KeySpec {\n /** The canonical key. */\n readonly key: string;\n readonly store: KeyStore;\n /** Removed by `clearAll()` (sign-out). Preferences are kept. */\n readonly personal: boolean;\n}\n\nexport interface FamilySpec {\n /** Canonical prefix ending in a dot; the id is appended in normalised form. */\n readonly prefix: string;\n readonly store: 'local' | 'session';\n readonly personal: boolean;\n}\n\nconst k = (\n key: string,\n store: KeyStore,\n personal: boolean,\n): KeySpec => ({ key, store, personal });\n\nconst f = (\n prefix: string,\n store: 'local' | 'session',\n personal: boolean,\n): FamilySpec => ({ prefix, store, personal });\n\n/** Every key the framework writes. No legacy spellings are read: old keys are simply ignored. */\nexport const CFG_KEYS = {\n accessToken: k('cfg.auth.access_token', 'cookie', true),\n refreshToken: k('cfg.auth.refresh_token', 'cookie', true),\n apiKey: k('cfg.auth.api_key', 'local', true),\n email: k('cfg.auth.email', 'local', false),\n emailTs: k('cfg.auth.email_ts', 'local', false),\n redirectUrl: k('cfg.auth.redirect_url', 'session', true),\n redirectUrlTs: k('cfg.auth.redirect_url_ts', 'session', true),\n oauthState: k('cfg.auth.oauth_state', 'session', true),\n oauthProvider: k('cfg.auth.oauth_provider', 'session', true),\n oauthProviders: k('cfg.auth.oauth_providers', 'session', false),\n profileCache: k('cfg.profile.cache', 'local', true),\n monitorSessionId: k('cfg.monitor.session_id', 'local', false),\n monitorSessionCookie: k('cfg.monitor.session_id', 'cookie', false),\n monitorDebug: k('cfg.monitor.debug', 'local', false),\n uiTabId: k('cfg.ui.tab_id', 'session', false),\n uiRouterSerial: k('cfg.ui.router_serial', 'session', false),\n uiState: k('cfg.ui.state', 'local', false),\n chatSpeechLanguage: k('cfg.chat.speech_language', 'local', false),\n chatRecentTools: k('cfg.chat.recent_tools', 'local', false),\n formsSpeechDebug: k('cfg.forms.speech_debug', 'local', false),\n formsSpeechPrefs: k('cfg.forms.speech_prefs', 'local', false),\n agentPlaygroundApiKeyId: k('cfg.agent.playground_api_key_id', 'session', true),\n agentPlaygroundBearer: k('cfg.agent.playground_bearer', 'session', true),\n agentEndpointDoc: k('cfg.agent.endpoint_doc', 'session', false),\n} as const satisfies Record<string, KeySpec>;\n\n/** Keys with a caller-supplied id part: one per room, tree, endpoint. */\nexport const CFG_FAMILIES = {\n chatDraft: f('cfg.chat.draft.', 'session', true),\n dataTree: f('cfg.data.tree.', 'local', false),\n agentEndpointDraft: f('cfg.agent.endpoint_draft.', 'local', false),\n} as const satisfies Record<string, FamilySpec>;\n\nconst OWNER_RE = /^[a-z][a-z0-9_]*$/;\n\n/** One segment of a key: lower case, `[a-z0-9_]`, anything else folded to `_`. */\nexport function normalizeSegment(raw: string): string {\n return raw\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9_]+/g, '_')\n .replace(/^_+|_+$/g, '');\n}\n\nexport interface StorageOptions {\n /** Named keys of this owner. */\n readonly keys?: Readonly<Record<string, KeySpec>>;\n readonly families?: Readonly<Record<string, FamilySpec>>;\n /** Cookie lifetime for the `cookie` store. Default 30 days. */\n readonly cookieMaxAgeSeconds?: number;\n /**\n * Cookie `Domain`. `'auto'` (default): the registrable domain of the page, so every subdomain\n * shares the cookie (`example.com` for `my.example.com`). A string forces a domain; `false`\n * keeps cookies host-only.\n */\n readonly cookieDomain?: 'auto' | string | false;\n}\n\nexport interface WriteOptions {\n /** Cookie store: lifetime of this write. Default: the owner's `cookieMaxAgeSeconds`. */\n readonly maxAgeSeconds?: number;\n}\n\nexport interface GuardedStorage {\n readonly owner: string;\n /** Builds `<owner>.<part>.<part>` from free-form parts; throws if a part is empty. */\n key(...parts: string[]): string;\n /** Builds a family member key: the prefix plus the normalised id. */\n familyKey(family: FamilySpec, id: string): string;\n /** `^(cfg|<owner>)(\\.[a-z0-9_]+)+$`. */\n isValid(key: string): boolean;\n read(key: string, store?: KeyStore): string | null;\n /** True when the value reached the browser's storage; false means it is held in memory for this page only. */\n write(key: string, value: string, store?: KeyStore, options?: WriteOptions): boolean;\n /** Removes the key. */\n remove(key: string, store?: KeyStore): void;\n readJSON<T>(key: string, store?: KeyStore): T | null;\n writeJSON(key: string, value: unknown, store?: KeyStore): boolean;\n /** Keys this owner holds in `store`. */\n keys(store?: Exclude<KeyStore, 'cookie'>): string[];\n /** Sign-out: removes the `personal` keys. `{ all: true }` removes everything under this owner. */\n clearAll(options?: { all?: boolean }): void;\n /** Cookie store: change the `Domain` policy (`'auto'`, a domain, or `false` for host-only cookies). */\n setCookieDomain(domain: 'auto' | string | false): void;\n /** The `Domain` cookies are written with right now; `null` means host-only. */\n cookieDomain(): string | null;\n /** Cross-tab: calls `listener` with the new value when ANOTHER tab changes `key`. Cookies fire no events. */\n onChange(key: string, listener: (value: string | null) => void, store?: Exclude<KeyStore, 'cookie'>): () => void;\n}\n\nconst hasWindow = () => typeof window !== 'undefined';\n\nconst domainByHost = new Map<string, string | null>();\n\n/**\n * The broadest domain this page may set cookies on (`example.com` for `my.example.com`,\n * `example.co.uk` for `a.example.co.uk`), found by asking the browser: it refuses a cookie for a\n * public suffix, so no suffix list lives in our code. `null` for an IP, `localhost`, a single label\n * or when cookies are blocked (the cookie is then host-only).\n */\nfunction detectCookieDomain(): string | null {\n if (!hasWindow() || typeof document === 'undefined') return null;\n const host = window.location.hostname.toLowerCase();\n if (!host || !host.includes('.') || host.includes(':') || /^[0-9.]+$/.test(host)) return null;\n const cached = domainByHost.get(host);\n if (cached !== undefined) return cached;\n const labels = host.split('.');\n const secure = window.location.protocol === 'https:' ? '; Secure' : '';\n let found: string | null = null;\n try {\n for (let i = labels.length - 2; i >= 0 && found === null; i -= 1) {\n const candidate = labels.slice(i).join('.');\n const probe = 'cfg_probe_' + Math.random().toString(36).slice(2);\n document.cookie = probe + '=1; Domain=' + candidate + '; Path=/; Max-Age=30; SameSite=Lax' + secure;\n if (document.cookie.includes(probe + '=1')) found = candidate;\n document.cookie = probe + '=; Domain=' + candidate + '; Path=/; Max-Age=0; SameSite=Lax' + secure;\n }\n } catch {\n found = null;\n }\n domainByHost.set(host, found);\n return found;\n}\n\nfunction nativeStorage(store: 'local' | 'session'): Storage | null {\n if (!hasWindow()) return null;\n try {\n return store === 'session' ? window.sessionStorage : window.localStorage;\n } catch {\n return null;\n }\n}\n\nfunction cookieNames(): string[] {\n if (!hasWindow()) return [];\n try {\n return document.cookie\n .split('; ')\n .map((part) => decodeURIComponent(part.split('=')[0] ?? ''))\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\nexport function createStorage(owner: string, options: StorageOptions = {}): GuardedStorage {\n if (!OWNER_RE.test(owner)) {\n throw new TypeError(`createStorage: owner \"${owner}\" must match ${OWNER_RE}`);\n }\n const prefix = `${owner}.`;\n const pattern = owner === 'cfg' ? /^cfg(\\.[a-z0-9_]+)+$/ : new RegExp(`^(cfg|${owner})(\\\\.[a-z0-9_]+)+$`);\n const cookieMaxAge = options.cookieMaxAgeSeconds ?? 60 * 60 * 24 * 30;\n let cookiePolicy: 'auto' | string | false = options.cookieDomain ?? 'auto';\n const resolveCookieDomain = (): string | null =>\n cookiePolicy === false ? null : cookiePolicy === 'auto' ? detectCookieDomain() : cookiePolicy;\n // A cookie is identified by name AND Domain: expire the twin without a domain and the one with it.\n const expireCookie = (key: string, domain: string | null) => {\n const secure = window.location.protocol === 'https:' ? '; Secure' : '';\n document.cookie =\n encodeURIComponent(key) + '=; Path=/; Max-Age=0; SameSite=Lax' + (domain ? '; Domain=' + domain : '') + secure;\n };\n const specs = Object.values(options.keys ?? {});\n const families = Object.values(options.families ?? {});\n const specByKey = new Map<string, KeySpec[]>();\n for (const spec of specs) specByKey.set(spec.key, [...(specByKey.get(spec.key) ?? []), spec]);\n // Held in memory when the browser refuses a write (quota, private mode), so the page still works until reload.\n const memory: Record<KeyStore, Map<string, string>> = {\n local: new Map(),\n session: new Map(),\n cookie: new Map(),\n };\n\n const isValid = (key: string) => pattern.test(key);\n const assertValid = (key: string) => {\n if (!isValid(key)) throw new TypeError(`storage key \"${key}\" must match ${pattern}`);\n };\n const assertOwned = (key: string) => {\n assertValid(key);\n if (!key.startsWith(prefix)) throw new TypeError(`storage key \"${key}\" is not owned by \"${owner}\"`);\n };\n\n function rawGet(store: KeyStore, key: string): string | null {\n if (!hasWindow()) return null;\n if (store === 'cookie') {\n try {\n const escaped = encodeURIComponent(key).replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${escaped}=([^;]*)`));\n if (match?.[1] !== undefined) return decodeURIComponent(match[1]);\n } catch {\n /* fall through to memory */\n }\n return memory.cookie.get(key) ?? null;\n }\n try {\n const value = nativeStorage(store)?.getItem(key) ?? null;\n if (value !== null) return value;\n } catch {\n /* fall through to memory */\n }\n return memory[store].get(key) ?? null;\n }\n\n function rawSet(store: KeyStore, key: string, value: string, maxAgeSeconds?: number): boolean {\n if (!hasWindow()) return false;\n try {\n if (store === 'cookie') {\n const secure = window.location.protocol === 'https:' ? '; Secure' : '';\n const domain = resolveCookieDomain();\n const domainPart = domain ? `; Domain=${domain}` : '';\n document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${Math.max(1, Math.floor(maxAgeSeconds ?? cookieMaxAge))}; SameSite=Lax${domainPart}${secure}`;\n // A host-only cookie written earlier would shadow the shared one: drop that twin.\n if (domain) expireCookie(key, null);\n if (rawGet('cookie', key) === value && !memory.cookie.has(key)) return true;\n memory.cookie.set(key, value);\n return false;\n }\n const native = nativeStorage(store);\n if (!native) throw new Error('storage unavailable');\n native.setItem(key, value);\n memory[store].delete(key);\n return true;\n } catch {\n memory[store].set(key, value);\n return false;\n }\n }\n\n function rawRemove(store: KeyStore, key: string): void {\n memory[store].delete(key);\n if (!hasWindow()) return;\n try {\n if (store === 'cookie') {\n expireCookie(key, null);\n const domain = resolveCookieDomain();\n if (domain) expireCookie(key, domain);\n } else {\n nativeStorage(store)?.removeItem(key);\n }\n } catch {\n /* ignore */\n }\n }\n\n function resolveStore(key: string, store?: KeyStore): KeyStore {\n return store ?? specByKey.get(key)?.[0]?.store ?? 'local';\n }\n\n function listKeys(store: 'local' | 'session', startsWith: string): string[] {\n const out: string[] = [];\n try {\n const native = nativeStorage(store);\n if (native) {\n for (let i = 0; i < native.length; i += 1) {\n const name = native.key(i);\n if (name?.startsWith(startsWith)) out.push(name);\n }\n }\n } catch {\n /* ignore */\n }\n for (const name of memory[store].keys()) if (name.startsWith(startsWith) && !out.includes(name)) out.push(name);\n return out;\n }\n\n const familyKey = (family: FamilySpec, id: string) => {\n const part = normalizeSegment(id);\n if (!part) throw new TypeError('storage family id is empty after normalisation');\n return family.prefix + part;\n };\n\n const api: GuardedStorage = {\n owner,\n key(...parts) {\n const segments = parts.map(normalizeSegment);\n if (segments.length === 0 || segments.some((segment) => !segment)) {\n throw new TypeError(`storage key parts must be non-empty: ${JSON.stringify(parts)}`);\n }\n return `${prefix}${segments.join('.')}`;\n },\n familyKey,\n isValid,\n read(key, store) {\n assertValid(key);\n const target = resolveStore(key, store);\n return rawGet(target, key);\n },\n write(key, value, store, writeOptions) {\n assertOwned(key);\n const target = resolveStore(key, store);\n return rawSet(target, key, value, writeOptions?.maxAgeSeconds);\n },\n remove(key, store) {\n assertOwned(key);\n const target = resolveStore(key, store);\n rawRemove(target, key);\n },\n readJSON<T>(key: string, store?: KeyStore): T | null {\n const raw = api.read(key, store);\n if (raw === null) return null;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n },\n writeJSON(key, value, store) {\n return api.write(key, JSON.stringify(value), store);\n },\n keys(store = 'local') {\n return listKeys(store, prefix);\n },\n clearAll({ all = false } = {}) {\n for (const spec of specs) {\n if (!all && !spec.personal) continue;\n rawRemove(spec.store, spec.key);\n }\n for (const family of families) {\n if (!all && !family.personal) continue;\n for (const name of listKeys(family.store, family.prefix)) rawRemove(family.store, name);\n }\n if (all) {\n for (const store of ['local', 'session'] as const) {\n for (const name of listKeys(store, prefix)) rawRemove(store, name);\n }\n for (const name of cookieNames()) if (name.startsWith(prefix)) rawRemove('cookie', name);\n }\n },\n setCookieDomain(domain) {\n cookiePolicy = domain;\n },\n cookieDomain: resolveCookieDomain,\n onChange(key, listener, store = 'local') {\n assertValid(key);\n if (!hasWindow()) return () => {};\n const handler = (event: StorageEvent) => {\n if (event.storageArea !== nativeStorage(store)) return;\n if (event.key === null || event.key === key) listener(event.key === null ? null : event.newValue);\n };\n window.addEventListener('storage', handler);\n return () => window.removeEventListener('storage', handler);\n },\n };\n return api;\n}\n\n/** The framework's own storage: every `cfg.*` key. */\nexport const cfgStorage: GuardedStorage = createStorage('cfg', {\n keys: CFG_KEYS,\n families: CFG_FAMILIES,\n});\n\n"],"mappings":"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","names":[]}
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Server-safe cookie header parsing, for SSR code that has the raw `Cookie` header
3
+ * (Next.js `headers()`, a Node request) and wants the shared session cookie.
4
+ * No DOM, no dependencies.
5
+ */
6
+ /** The value of cookie `name` in a `Cookie` request header, or `null`. */
7
+ declare function readCookie(cookieHeader: string | null | undefined, name: string): string | null;
8
+
1
9
  type KeyStore = 'local' | 'session' | 'cookie';
2
10
  interface KeySpec {
3
11
  /** The canonical key. */
@@ -53,6 +61,16 @@ interface StorageOptions {
53
61
  readonly families?: Readonly<Record<string, FamilySpec>>;
54
62
  /** Cookie lifetime for the `cookie` store. Default 30 days. */
55
63
  readonly cookieMaxAgeSeconds?: number;
64
+ /**
65
+ * Cookie `Domain`. `'auto'` (default): the registrable domain of the page, so every subdomain
66
+ * shares the cookie (`example.com` for `my.example.com`). A string forces a domain; `false`
67
+ * keeps cookies host-only.
68
+ */
69
+ readonly cookieDomain?: 'auto' | string | false;
70
+ }
71
+ interface WriteOptions {
72
+ /** Cookie store: lifetime of this write. Default: the owner's `cookieMaxAgeSeconds`. */
73
+ readonly maxAgeSeconds?: number;
56
74
  }
57
75
  interface GuardedStorage {
58
76
  readonly owner: string;
@@ -64,7 +82,7 @@ interface GuardedStorage {
64
82
  isValid(key: string): boolean;
65
83
  read(key: string, store?: KeyStore): string | null;
66
84
  /** True when the value reached the browser's storage; false means it is held in memory for this page only. */
67
- write(key: string, value: string, store?: KeyStore): boolean;
85
+ write(key: string, value: string, store?: KeyStore, options?: WriteOptions): boolean;
68
86
  /** Removes the key. */
69
87
  remove(key: string, store?: KeyStore): void;
70
88
  readJSON<T>(key: string, store?: KeyStore): T | null;
@@ -75,6 +93,10 @@ interface GuardedStorage {
75
93
  clearAll(options?: {
76
94
  all?: boolean;
77
95
  }): void;
96
+ /** Cookie store: change the `Domain` policy (`'auto'`, a domain, or `false` for host-only cookies). */
97
+ setCookieDomain(domain: 'auto' | string | false): void;
98
+ /** The `Domain` cookies are written with right now; `null` means host-only. */
99
+ cookieDomain(): string | null;
78
100
  /** Cross-tab: calls `listener` with the new value when ANOTHER tab changes `key`. Cookies fire no events. */
79
101
  onChange(key: string, listener: (value: string | null) => void, store?: Exclude<KeyStore, 'cookie'>): () => void;
80
102
  }
@@ -82,4 +104,4 @@ declare function createStorage(owner: string, options?: StorageOptions): Guarded
82
104
  /** The framework's own storage: every `cfg.*` key. */
83
105
  declare const cfgStorage: GuardedStorage;
84
106
 
85
- export { CFG_FAMILIES, CFG_KEYS, type FamilySpec, type GuardedStorage, type KeySpec, type KeyStore, type StorageOptions, cfgStorage, createStorage, normalizeSegment };
107
+ export { CFG_FAMILIES, CFG_KEYS, type FamilySpec, type GuardedStorage, type KeySpec, type KeyStore, type StorageOptions, type WriteOptions, cfgStorage, createStorage, normalizeSegment, readCookie };
package/dist/storage.d.ts CHANGED
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Server-safe cookie header parsing, for SSR code that has the raw `Cookie` header
3
+ * (Next.js `headers()`, a Node request) and wants the shared session cookie.
4
+ * No DOM, no dependencies.
5
+ */
6
+ /** The value of cookie `name` in a `Cookie` request header, or `null`. */
7
+ declare function readCookie(cookieHeader: string | null | undefined, name: string): string | null;
8
+
1
9
  type KeyStore = 'local' | 'session' | 'cookie';
2
10
  interface KeySpec {
3
11
  /** The canonical key. */
@@ -53,6 +61,16 @@ interface StorageOptions {
53
61
  readonly families?: Readonly<Record<string, FamilySpec>>;
54
62
  /** Cookie lifetime for the `cookie` store. Default 30 days. */
55
63
  readonly cookieMaxAgeSeconds?: number;
64
+ /**
65
+ * Cookie `Domain`. `'auto'` (default): the registrable domain of the page, so every subdomain
66
+ * shares the cookie (`example.com` for `my.example.com`). A string forces a domain; `false`
67
+ * keeps cookies host-only.
68
+ */
69
+ readonly cookieDomain?: 'auto' | string | false;
70
+ }
71
+ interface WriteOptions {
72
+ /** Cookie store: lifetime of this write. Default: the owner's `cookieMaxAgeSeconds`. */
73
+ readonly maxAgeSeconds?: number;
56
74
  }
57
75
  interface GuardedStorage {
58
76
  readonly owner: string;
@@ -64,7 +82,7 @@ interface GuardedStorage {
64
82
  isValid(key: string): boolean;
65
83
  read(key: string, store?: KeyStore): string | null;
66
84
  /** True when the value reached the browser's storage; false means it is held in memory for this page only. */
67
- write(key: string, value: string, store?: KeyStore): boolean;
85
+ write(key: string, value: string, store?: KeyStore, options?: WriteOptions): boolean;
68
86
  /** Removes the key. */
69
87
  remove(key: string, store?: KeyStore): void;
70
88
  readJSON<T>(key: string, store?: KeyStore): T | null;
@@ -75,6 +93,10 @@ interface GuardedStorage {
75
93
  clearAll(options?: {
76
94
  all?: boolean;
77
95
  }): void;
96
+ /** Cookie store: change the `Domain` policy (`'auto'`, a domain, or `false` for host-only cookies). */
97
+ setCookieDomain(domain: 'auto' | string | false): void;
98
+ /** The `Domain` cookies are written with right now; `null` means host-only. */
99
+ cookieDomain(): string | null;
78
100
  /** Cross-tab: calls `listener` with the new value when ANOTHER tab changes `key`. Cookies fire no events. */
79
101
  onChange(key: string, listener: (value: string | null) => void, store?: Exclude<KeyStore, 'cookie'>): () => void;
80
102
  }
@@ -82,4 +104,4 @@ declare function createStorage(owner: string, options?: StorageOptions): Guarded
82
104
  /** The framework's own storage: every `cfg.*` key. */
83
105
  declare const cfgStorage: GuardedStorage;
84
106
 
85
- export { CFG_FAMILIES, CFG_KEYS, type FamilySpec, type GuardedStorage, type KeySpec, type KeyStore, type StorageOptions, cfgStorage, createStorage, normalizeSegment };
107
+ export { CFG_FAMILIES, CFG_KEYS, type FamilySpec, type GuardedStorage, type KeySpec, type KeyStore, type StorageOptions, type WriteOptions, cfgStorage, createStorage, normalizeSegment, readCookie };
package/dist/storage.mjs CHANGED
@@ -1,12 +1,30 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
 
4
+ // src/cookies.ts
5
+ function readCookie(cookieHeader, name) {
6
+ if (!cookieHeader) return null;
7
+ const wanted = encodeURIComponent(name);
8
+ for (const part of cookieHeader.split(";")) {
9
+ const eq = part.indexOf("=");
10
+ if (eq < 0) continue;
11
+ if (part.slice(0, eq).trim() !== wanted) continue;
12
+ try {
13
+ return decodeURIComponent(part.slice(eq + 1).trim());
14
+ } catch {
15
+ return null;
16
+ }
17
+ }
18
+ return null;
19
+ }
20
+ __name(readCookie, "readCookie");
21
+
4
22
  // src/_api/generated/helpers/keys.ts
5
23
  var k = /* @__PURE__ */ __name((key, store, personal) => ({ key, store, personal }), "k");
6
24
  var f = /* @__PURE__ */ __name((prefix, store, personal) => ({ prefix, store, personal }), "f");
7
25
  var CFG_KEYS = {
8
- accessToken: k("cfg.auth.access_token", "local", true),
9
- refreshToken: k("cfg.auth.refresh_token", "local", true),
26
+ accessToken: k("cfg.auth.access_token", "cookie", true),
27
+ refreshToken: k("cfg.auth.refresh_token", "cookie", true),
10
28
  apiKey: k("cfg.auth.api_key", "local", true),
11
29
  email: k("cfg.auth.email", "local", false),
12
30
  emailTs: k("cfg.auth.email_ts", "local", false),
@@ -41,6 +59,31 @@ function normalizeSegment(raw) {
41
59
  }
42
60
  __name(normalizeSegment, "normalizeSegment");
43
61
  var hasWindow = /* @__PURE__ */ __name(() => typeof window !== "undefined", "hasWindow");
62
+ var domainByHost = /* @__PURE__ */ new Map();
63
+ function detectCookieDomain() {
64
+ if (!hasWindow() || typeof document === "undefined") return null;
65
+ const host = window.location.hostname.toLowerCase();
66
+ if (!host || !host.includes(".") || host.includes(":") || /^[0-9.]+$/.test(host)) return null;
67
+ const cached = domainByHost.get(host);
68
+ if (cached !== void 0) return cached;
69
+ const labels = host.split(".");
70
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
71
+ let found = null;
72
+ try {
73
+ for (let i = labels.length - 2; i >= 0 && found === null; i -= 1) {
74
+ const candidate = labels.slice(i).join(".");
75
+ const probe = "cfg_probe_" + Math.random().toString(36).slice(2);
76
+ document.cookie = probe + "=1; Domain=" + candidate + "; Path=/; Max-Age=30; SameSite=Lax" + secure;
77
+ if (document.cookie.includes(probe + "=1")) found = candidate;
78
+ document.cookie = probe + "=; Domain=" + candidate + "; Path=/; Max-Age=0; SameSite=Lax" + secure;
79
+ }
80
+ } catch {
81
+ found = null;
82
+ }
83
+ domainByHost.set(host, found);
84
+ return found;
85
+ }
86
+ __name(detectCookieDomain, "detectCookieDomain");
44
87
  function nativeStorage(store) {
45
88
  if (!hasWindow()) return null;
46
89
  try {
@@ -66,6 +109,12 @@ function createStorage(owner, options = {}) {
66
109
  const prefix = `${owner}.`;
67
110
  const pattern = owner === "cfg" ? /^cfg(\.[a-z0-9_]+)+$/ : new RegExp(`^(cfg|${owner})(\\.[a-z0-9_]+)+$`);
68
111
  const cookieMaxAge = options.cookieMaxAgeSeconds ?? 60 * 60 * 24 * 30;
112
+ let cookiePolicy = options.cookieDomain ?? "auto";
113
+ const resolveCookieDomain = /* @__PURE__ */ __name(() => cookiePolicy === false ? null : cookiePolicy === "auto" ? detectCookieDomain() : cookiePolicy, "resolveCookieDomain");
114
+ const expireCookie = /* @__PURE__ */ __name((key, domain) => {
115
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
116
+ document.cookie = encodeURIComponent(key) + "=; Path=/; Max-Age=0; SameSite=Lax" + (domain ? "; Domain=" + domain : "") + secure;
117
+ }, "expireCookie");
69
118
  const specs = Object.values(options.keys ?? {});
70
119
  const families = Object.values(options.families ?? {});
71
120
  const specByKey = /* @__PURE__ */ new Map();
@@ -102,12 +151,15 @@ function createStorage(owner, options = {}) {
102
151
  return memory[store].get(key) ?? null;
103
152
  }
104
153
  __name(rawGet, "rawGet");
105
- function rawSet(store, key, value) {
154
+ function rawSet(store, key, value, maxAgeSeconds) {
106
155
  if (!hasWindow()) return false;
107
156
  try {
108
157
  if (store === "cookie") {
109
158
  const secure = window.location.protocol === "https:" ? "; Secure" : "";
110
- document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${cookieMaxAge}; SameSite=Lax${secure}`;
159
+ const domain = resolveCookieDomain();
160
+ const domainPart = domain ? `; Domain=${domain}` : "";
161
+ document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${Math.max(1, Math.floor(maxAgeSeconds ?? cookieMaxAge))}; SameSite=Lax${domainPart}${secure}`;
162
+ if (domain) expireCookie(key, null);
111
163
  if (rawGet("cookie", key) === value && !memory.cookie.has(key)) return true;
112
164
  memory.cookie.set(key, value);
113
165
  return false;
@@ -128,8 +180,9 @@ function createStorage(owner, options = {}) {
128
180
  if (!hasWindow()) return;
129
181
  try {
130
182
  if (store === "cookie") {
131
- const secure = window.location.protocol === "https:" ? "; Secure" : "";
132
- document.cookie = `${encodeURIComponent(key)}=; Path=/; Max-Age=0; SameSite=Lax${secure}`;
183
+ expireCookie(key, null);
184
+ const domain = resolveCookieDomain();
185
+ if (domain) expireCookie(key, domain);
133
186
  } else {
134
187
  nativeStorage(store)?.removeItem(key);
135
188
  }
@@ -178,10 +231,10 @@ function createStorage(owner, options = {}) {
178
231
  const target = resolveStore(key, store);
179
232
  return rawGet(target, key);
180
233
  },
181
- write(key, value, store) {
234
+ write(key, value, store, writeOptions) {
182
235
  assertOwned(key);
183
236
  const target = resolveStore(key, store);
184
- return rawSet(target, key, value);
237
+ return rawSet(target, key, value, writeOptions?.maxAgeSeconds);
185
238
  },
186
239
  remove(key, store) {
187
240
  assertOwned(key);
@@ -219,6 +272,10 @@ function createStorage(owner, options = {}) {
219
272
  for (const name of cookieNames()) if (name.startsWith(prefix)) rawRemove("cookie", name);
220
273
  }
221
274
  },
275
+ setCookieDomain(domain) {
276
+ cookiePolicy = domain;
277
+ },
278
+ cookieDomain: resolveCookieDomain,
222
279
  onChange(key, listener, store = "local") {
223
280
  assertValid(key);
224
281
  if (!hasWindow()) return () => {
@@ -243,6 +300,7 @@ export {
243
300
  CFG_KEYS,
244
301
  cfgStorage,
245
302
  createStorage,
246
- normalizeSegment
303
+ normalizeSegment,
304
+ readCookie
247
305
  };
248
306
  //# sourceMappingURL=storage.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/_api/generated/helpers/keys.ts"],"sourcesContent":["// AUTO-GENERATED by django_generator / ts_extras.wrapper\n// Browser-storage key registry: one scheme, guarded access.\n// DO NOT EDIT — re-run `make gen`.\n//\n// Rules for agents and apps: @docs/STORAGE_KEYS.md in @djangocfg/api.\n//\n// Scheme: `<owner>.<area>.<name>` — lower case, dots between levels,\n// `snake_case` inside a level. The framework's owner is `cfg`; an app picks its\n// own with `createStorage('<owner>')`. Third-party keys (a library's own\n// prefix, `NEXT_LOCALE`) are not ours to rename and stay as they are.\n\nexport type KeyStore = 'local' | 'session' | 'cookie';\n\nexport interface KeySpec {\n /** The canonical key. */\n readonly key: string;\n readonly store: KeyStore;\n /** Removed by `clearAll()` (sign-out). Preferences are kept. */\n readonly personal: boolean;\n}\n\nexport interface FamilySpec {\n /** Canonical prefix ending in a dot; the id is appended in normalised form. */\n readonly prefix: string;\n readonly store: 'local' | 'session';\n readonly personal: boolean;\n}\n\nconst k = (\n key: string,\n store: KeyStore,\n personal: boolean,\n): KeySpec => ({ key, store, personal });\n\nconst f = (\n prefix: string,\n store: 'local' | 'session',\n personal: boolean,\n): FamilySpec => ({ prefix, store, personal });\n\n/** Every key the framework writes. No legacy spellings are read: old keys are simply ignored. */\nexport const CFG_KEYS = {\n accessToken: k('cfg.auth.access_token', 'local', true),\n refreshToken: k('cfg.auth.refresh_token', 'local', true),\n apiKey: k('cfg.auth.api_key', 'local', true),\n email: k('cfg.auth.email', 'local', false),\n emailTs: k('cfg.auth.email_ts', 'local', false),\n redirectUrl: k('cfg.auth.redirect_url', 'session', true),\n redirectUrlTs: k('cfg.auth.redirect_url_ts', 'session', true),\n oauthState: k('cfg.auth.oauth_state', 'session', true),\n oauthProvider: k('cfg.auth.oauth_provider', 'session', true),\n oauthProviders: k('cfg.auth.oauth_providers', 'session', false),\n profileCache: k('cfg.profile.cache', 'local', true),\n monitorSessionId: k('cfg.monitor.session_id', 'local', false),\n monitorSessionCookie: k('cfg.monitor.session_id', 'cookie', false),\n monitorDebug: k('cfg.monitor.debug', 'local', false),\n uiTabId: k('cfg.ui.tab_id', 'session', false),\n uiRouterSerial: k('cfg.ui.router_serial', 'session', false),\n uiState: k('cfg.ui.state', 'local', false),\n chatSpeechLanguage: k('cfg.chat.speech_language', 'local', false),\n chatRecentTools: k('cfg.chat.recent_tools', 'local', false),\n formsSpeechDebug: k('cfg.forms.speech_debug', 'local', false),\n formsSpeechPrefs: k('cfg.forms.speech_prefs', 'local', false),\n agentPlaygroundApiKeyId: k('cfg.agent.playground_api_key_id', 'session', true),\n agentPlaygroundBearer: k('cfg.agent.playground_bearer', 'session', true),\n agentEndpointDoc: k('cfg.agent.endpoint_doc', 'session', false),\n} as const satisfies Record<string, KeySpec>;\n\n/** Keys with a caller-supplied id part: one per room, tree, endpoint. */\nexport const CFG_FAMILIES = {\n chatDraft: f('cfg.chat.draft.', 'session', true),\n dataTree: f('cfg.data.tree.', 'local', false),\n agentEndpointDraft: f('cfg.agent.endpoint_draft.', 'local', false),\n} as const satisfies Record<string, FamilySpec>;\n\nconst OWNER_RE = /^[a-z][a-z0-9_]*$/;\n\n/** One segment of a key: lower case, `[a-z0-9_]`, anything else folded to `_`. */\nexport function normalizeSegment(raw: string): string {\n return raw\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9_]+/g, '_')\n .replace(/^_+|_+$/g, '');\n}\n\nexport interface StorageOptions {\n /** Named keys of this owner. */\n readonly keys?: Readonly<Record<string, KeySpec>>;\n readonly families?: Readonly<Record<string, FamilySpec>>;\n /** Cookie lifetime for the `cookie` store. Default 30 days. */\n readonly cookieMaxAgeSeconds?: number;\n}\n\nexport interface GuardedStorage {\n readonly owner: string;\n /** Builds `<owner>.<part>.<part>` from free-form parts; throws if a part is empty. */\n key(...parts: string[]): string;\n /** Builds a family member key: the prefix plus the normalised id. */\n familyKey(family: FamilySpec, id: string): string;\n /** `^(cfg|<owner>)(\\.[a-z0-9_]+)+$`. */\n isValid(key: string): boolean;\n read(key: string, store?: KeyStore): string | null;\n /** True when the value reached the browser's storage; false means it is held in memory for this page only. */\n write(key: string, value: string, store?: KeyStore): boolean;\n /** Removes the key. */\n remove(key: string, store?: KeyStore): void;\n readJSON<T>(key: string, store?: KeyStore): T | null;\n writeJSON(key: string, value: unknown, store?: KeyStore): boolean;\n /** Keys this owner holds in `store`. */\n keys(store?: Exclude<KeyStore, 'cookie'>): string[];\n /** Sign-out: removes the `personal` keys. `{ all: true }` removes everything under this owner. */\n clearAll(options?: { all?: boolean }): void;\n /** Cross-tab: calls `listener` with the new value when ANOTHER tab changes `key`. Cookies fire no events. */\n onChange(key: string, listener: (value: string | null) => void, store?: Exclude<KeyStore, 'cookie'>): () => void;\n}\n\nconst hasWindow = () => typeof window !== 'undefined';\n\nfunction nativeStorage(store: 'local' | 'session'): Storage | null {\n if (!hasWindow()) return null;\n try {\n return store === 'session' ? window.sessionStorage : window.localStorage;\n } catch {\n return null;\n }\n}\n\nfunction cookieNames(): string[] {\n if (!hasWindow()) return [];\n try {\n return document.cookie\n .split('; ')\n .map((part) => decodeURIComponent(part.split('=')[0] ?? ''))\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\nexport function createStorage(owner: string, options: StorageOptions = {}): GuardedStorage {\n if (!OWNER_RE.test(owner)) {\n throw new TypeError(`createStorage: owner \"${owner}\" must match ${OWNER_RE}`);\n }\n const prefix = `${owner}.`;\n const pattern = owner === 'cfg' ? /^cfg(\\.[a-z0-9_]+)+$/ : new RegExp(`^(cfg|${owner})(\\\\.[a-z0-9_]+)+$`);\n const cookieMaxAge = options.cookieMaxAgeSeconds ?? 60 * 60 * 24 * 30;\n const specs = Object.values(options.keys ?? {});\n const families = Object.values(options.families ?? {});\n const specByKey = new Map<string, KeySpec[]>();\n for (const spec of specs) specByKey.set(spec.key, [...(specByKey.get(spec.key) ?? []), spec]);\n // Held in memory when the browser refuses a write (quota, private mode), so the page still works until reload.\n const memory: Record<KeyStore, Map<string, string>> = {\n local: new Map(),\n session: new Map(),\n cookie: new Map(),\n };\n\n const isValid = (key: string) => pattern.test(key);\n const assertValid = (key: string) => {\n if (!isValid(key)) throw new TypeError(`storage key \"${key}\" must match ${pattern}`);\n };\n const assertOwned = (key: string) => {\n assertValid(key);\n if (!key.startsWith(prefix)) throw new TypeError(`storage key \"${key}\" is not owned by \"${owner}\"`);\n };\n\n function rawGet(store: KeyStore, key: string): string | null {\n if (!hasWindow()) return null;\n if (store === 'cookie') {\n try {\n const escaped = encodeURIComponent(key).replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${escaped}=([^;]*)`));\n if (match?.[1] !== undefined) return decodeURIComponent(match[1]);\n } catch {\n /* fall through to memory */\n }\n return memory.cookie.get(key) ?? null;\n }\n try {\n const value = nativeStorage(store)?.getItem(key) ?? null;\n if (value !== null) return value;\n } catch {\n /* fall through to memory */\n }\n return memory[store].get(key) ?? null;\n }\n\n function rawSet(store: KeyStore, key: string, value: string): boolean {\n if (!hasWindow()) return false;\n try {\n if (store === 'cookie') {\n const secure = window.location.protocol === 'https:' ? '; Secure' : '';\n document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${cookieMaxAge}; SameSite=Lax${secure}`;\n if (rawGet('cookie', key) === value && !memory.cookie.has(key)) return true;\n memory.cookie.set(key, value);\n return false;\n }\n const native = nativeStorage(store);\n if (!native) throw new Error('storage unavailable');\n native.setItem(key, value);\n memory[store].delete(key);\n return true;\n } catch {\n memory[store].set(key, value);\n return false;\n }\n }\n\n function rawRemove(store: KeyStore, key: string): void {\n memory[store].delete(key);\n if (!hasWindow()) return;\n try {\n if (store === 'cookie') {\n const secure = window.location.protocol === 'https:' ? '; Secure' : '';\n document.cookie = `${encodeURIComponent(key)}=; Path=/; Max-Age=0; SameSite=Lax${secure}`;\n } else {\n nativeStorage(store)?.removeItem(key);\n }\n } catch {\n /* ignore */\n }\n }\n\n function resolveStore(key: string, store?: KeyStore): KeyStore {\n return store ?? specByKey.get(key)?.[0]?.store ?? 'local';\n }\n\n function listKeys(store: 'local' | 'session', startsWith: string): string[] {\n const out: string[] = [];\n try {\n const native = nativeStorage(store);\n if (native) {\n for (let i = 0; i < native.length; i += 1) {\n const name = native.key(i);\n if (name?.startsWith(startsWith)) out.push(name);\n }\n }\n } catch {\n /* ignore */\n }\n for (const name of memory[store].keys()) if (name.startsWith(startsWith) && !out.includes(name)) out.push(name);\n return out;\n }\n\n const familyKey = (family: FamilySpec, id: string) => {\n const part = normalizeSegment(id);\n if (!part) throw new TypeError('storage family id is empty after normalisation');\n return family.prefix + part;\n };\n\n const api: GuardedStorage = {\n owner,\n key(...parts) {\n const segments = parts.map(normalizeSegment);\n if (segments.length === 0 || segments.some((segment) => !segment)) {\n throw new TypeError(`storage key parts must be non-empty: ${JSON.stringify(parts)}`);\n }\n return `${prefix}${segments.join('.')}`;\n },\n familyKey,\n isValid,\n read(key, store) {\n assertValid(key);\n const target = resolveStore(key, store);\n return rawGet(target, key);\n },\n write(key, value, store) {\n assertOwned(key);\n const target = resolveStore(key, store);\n return rawSet(target, key, value);\n },\n remove(key, store) {\n assertOwned(key);\n const target = resolveStore(key, store);\n rawRemove(target, key);\n },\n readJSON<T>(key: string, store?: KeyStore): T | null {\n const raw = api.read(key, store);\n if (raw === null) return null;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n },\n writeJSON(key, value, store) {\n return api.write(key, JSON.stringify(value), store);\n },\n keys(store = 'local') {\n return listKeys(store, prefix);\n },\n clearAll({ all = false } = {}) {\n for (const spec of specs) {\n if (!all && !spec.personal) continue;\n rawRemove(spec.store, spec.key);\n }\n for (const family of families) {\n if (!all && !family.personal) continue;\n for (const name of listKeys(family.store, family.prefix)) rawRemove(family.store, name);\n }\n if (all) {\n for (const store of ['local', 'session'] as const) {\n for (const name of listKeys(store, prefix)) rawRemove(store, name);\n }\n for (const name of cookieNames()) if (name.startsWith(prefix)) rawRemove('cookie', name);\n }\n },\n onChange(key, listener, store = 'local') {\n assertValid(key);\n if (!hasWindow()) return () => {};\n const handler = (event: StorageEvent) => {\n if (event.storageArea !== nativeStorage(store)) return;\n if (event.key === null || event.key === key) listener(event.key === null ? null : event.newValue);\n };\n window.addEventListener('storage', handler);\n return () => window.removeEventListener('storage', handler);\n },\n };\n return api;\n}\n\n/** The framework's own storage: every `cfg.*` key. */\nexport const cfgStorage: GuardedStorage = createStorage('cfg', {\n keys: CFG_KEYS,\n families: CFG_FAMILIES,\n});\n\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cookies.ts","../src/_api/generated/helpers/keys.ts"],"sourcesContent":["/**\n * Server-safe cookie header parsing, for SSR code that has the raw `Cookie` header\n * (Next.js `headers()`, a Node request) and wants the shared session cookie.\n * No DOM, no dependencies.\n */\n\n/** The value of cookie `name` in a `Cookie` request header, or `null`. */\nexport function readCookie(cookieHeader: string | null | undefined, name: string): string | null {\n if (!cookieHeader) return null;\n const wanted = encodeURIComponent(name);\n for (const part of cookieHeader.split(';')) {\n const eq = part.indexOf('=');\n if (eq < 0) continue;\n if (part.slice(0, eq).trim() !== wanted) continue;\n try {\n return decodeURIComponent(part.slice(eq + 1).trim());\n } catch {\n return null;\n }\n }\n return null;\n}\n","// AUTO-GENERATED by django_generator / ts_extras.wrapper\n// Browser-storage key registry: one scheme, guarded access.\n// DO NOT EDIT — re-run `make gen`.\n//\n// Rules for agents and apps: @docs/STORAGE_KEYS.md in @djangocfg/api.\n//\n// Scheme: `<owner>.<area>.<name>` — lower case, dots between levels,\n// `snake_case` inside a level. The framework's owner is `cfg`; an app picks its\n// own with `createStorage('<owner>')`. Third-party keys (a library's own\n// prefix, `NEXT_LOCALE`) are not ours to rename and stay as they are.\n\nexport type KeyStore = 'local' | 'session' | 'cookie';\n\nexport interface KeySpec {\n /** The canonical key. */\n readonly key: string;\n readonly store: KeyStore;\n /** Removed by `clearAll()` (sign-out). Preferences are kept. */\n readonly personal: boolean;\n}\n\nexport interface FamilySpec {\n /** Canonical prefix ending in a dot; the id is appended in normalised form. */\n readonly prefix: string;\n readonly store: 'local' | 'session';\n readonly personal: boolean;\n}\n\nconst k = (\n key: string,\n store: KeyStore,\n personal: boolean,\n): KeySpec => ({ key, store, personal });\n\nconst f = (\n prefix: string,\n store: 'local' | 'session',\n personal: boolean,\n): FamilySpec => ({ prefix, store, personal });\n\n/** Every key the framework writes. No legacy spellings are read: old keys are simply ignored. */\nexport const CFG_KEYS = {\n accessToken: k('cfg.auth.access_token', 'cookie', true),\n refreshToken: k('cfg.auth.refresh_token', 'cookie', true),\n apiKey: k('cfg.auth.api_key', 'local', true),\n email: k('cfg.auth.email', 'local', false),\n emailTs: k('cfg.auth.email_ts', 'local', false),\n redirectUrl: k('cfg.auth.redirect_url', 'session', true),\n redirectUrlTs: k('cfg.auth.redirect_url_ts', 'session', true),\n oauthState: k('cfg.auth.oauth_state', 'session', true),\n oauthProvider: k('cfg.auth.oauth_provider', 'session', true),\n oauthProviders: k('cfg.auth.oauth_providers', 'session', false),\n profileCache: k('cfg.profile.cache', 'local', true),\n monitorSessionId: k('cfg.monitor.session_id', 'local', false),\n monitorSessionCookie: k('cfg.monitor.session_id', 'cookie', false),\n monitorDebug: k('cfg.monitor.debug', 'local', false),\n uiTabId: k('cfg.ui.tab_id', 'session', false),\n uiRouterSerial: k('cfg.ui.router_serial', 'session', false),\n uiState: k('cfg.ui.state', 'local', false),\n chatSpeechLanguage: k('cfg.chat.speech_language', 'local', false),\n chatRecentTools: k('cfg.chat.recent_tools', 'local', false),\n formsSpeechDebug: k('cfg.forms.speech_debug', 'local', false),\n formsSpeechPrefs: k('cfg.forms.speech_prefs', 'local', false),\n agentPlaygroundApiKeyId: k('cfg.agent.playground_api_key_id', 'session', true),\n agentPlaygroundBearer: k('cfg.agent.playground_bearer', 'session', true),\n agentEndpointDoc: k('cfg.agent.endpoint_doc', 'session', false),\n} as const satisfies Record<string, KeySpec>;\n\n/** Keys with a caller-supplied id part: one per room, tree, endpoint. */\nexport const CFG_FAMILIES = {\n chatDraft: f('cfg.chat.draft.', 'session', true),\n dataTree: f('cfg.data.tree.', 'local', false),\n agentEndpointDraft: f('cfg.agent.endpoint_draft.', 'local', false),\n} as const satisfies Record<string, FamilySpec>;\n\nconst OWNER_RE = /^[a-z][a-z0-9_]*$/;\n\n/** One segment of a key: lower case, `[a-z0-9_]`, anything else folded to `_`. */\nexport function normalizeSegment(raw: string): string {\n return raw\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9_]+/g, '_')\n .replace(/^_+|_+$/g, '');\n}\n\nexport interface StorageOptions {\n /** Named keys of this owner. */\n readonly keys?: Readonly<Record<string, KeySpec>>;\n readonly families?: Readonly<Record<string, FamilySpec>>;\n /** Cookie lifetime for the `cookie` store. Default 30 days. */\n readonly cookieMaxAgeSeconds?: number;\n /**\n * Cookie `Domain`. `'auto'` (default): the registrable domain of the page, so every subdomain\n * shares the cookie (`example.com` for `my.example.com`). A string forces a domain; `false`\n * keeps cookies host-only.\n */\n readonly cookieDomain?: 'auto' | string | false;\n}\n\nexport interface WriteOptions {\n /** Cookie store: lifetime of this write. Default: the owner's `cookieMaxAgeSeconds`. */\n readonly maxAgeSeconds?: number;\n}\n\nexport interface GuardedStorage {\n readonly owner: string;\n /** Builds `<owner>.<part>.<part>` from free-form parts; throws if a part is empty. */\n key(...parts: string[]): string;\n /** Builds a family member key: the prefix plus the normalised id. */\n familyKey(family: FamilySpec, id: string): string;\n /** `^(cfg|<owner>)(\\.[a-z0-9_]+)+$`. */\n isValid(key: string): boolean;\n read(key: string, store?: KeyStore): string | null;\n /** True when the value reached the browser's storage; false means it is held in memory for this page only. */\n write(key: string, value: string, store?: KeyStore, options?: WriteOptions): boolean;\n /** Removes the key. */\n remove(key: string, store?: KeyStore): void;\n readJSON<T>(key: string, store?: KeyStore): T | null;\n writeJSON(key: string, value: unknown, store?: KeyStore): boolean;\n /** Keys this owner holds in `store`. */\n keys(store?: Exclude<KeyStore, 'cookie'>): string[];\n /** Sign-out: removes the `personal` keys. `{ all: true }` removes everything under this owner. */\n clearAll(options?: { all?: boolean }): void;\n /** Cookie store: change the `Domain` policy (`'auto'`, a domain, or `false` for host-only cookies). */\n setCookieDomain(domain: 'auto' | string | false): void;\n /** The `Domain` cookies are written with right now; `null` means host-only. */\n cookieDomain(): string | null;\n /** Cross-tab: calls `listener` with the new value when ANOTHER tab changes `key`. Cookies fire no events. */\n onChange(key: string, listener: (value: string | null) => void, store?: Exclude<KeyStore, 'cookie'>): () => void;\n}\n\nconst hasWindow = () => typeof window !== 'undefined';\n\nconst domainByHost = new Map<string, string | null>();\n\n/**\n * The broadest domain this page may set cookies on (`example.com` for `my.example.com`,\n * `example.co.uk` for `a.example.co.uk`), found by asking the browser: it refuses a cookie for a\n * public suffix, so no suffix list lives in our code. `null` for an IP, `localhost`, a single label\n * or when cookies are blocked (the cookie is then host-only).\n */\nfunction detectCookieDomain(): string | null {\n if (!hasWindow() || typeof document === 'undefined') return null;\n const host = window.location.hostname.toLowerCase();\n if (!host || !host.includes('.') || host.includes(':') || /^[0-9.]+$/.test(host)) return null;\n const cached = domainByHost.get(host);\n if (cached !== undefined) return cached;\n const labels = host.split('.');\n const secure = window.location.protocol === 'https:' ? '; Secure' : '';\n let found: string | null = null;\n try {\n for (let i = labels.length - 2; i >= 0 && found === null; i -= 1) {\n const candidate = labels.slice(i).join('.');\n const probe = 'cfg_probe_' + Math.random().toString(36).slice(2);\n document.cookie = probe + '=1; Domain=' + candidate + '; Path=/; Max-Age=30; SameSite=Lax' + secure;\n if (document.cookie.includes(probe + '=1')) found = candidate;\n document.cookie = probe + '=; Domain=' + candidate + '; Path=/; Max-Age=0; SameSite=Lax' + secure;\n }\n } catch {\n found = null;\n }\n domainByHost.set(host, found);\n return found;\n}\n\nfunction nativeStorage(store: 'local' | 'session'): Storage | null {\n if (!hasWindow()) return null;\n try {\n return store === 'session' ? window.sessionStorage : window.localStorage;\n } catch {\n return null;\n }\n}\n\nfunction cookieNames(): string[] {\n if (!hasWindow()) return [];\n try {\n return document.cookie\n .split('; ')\n .map((part) => decodeURIComponent(part.split('=')[0] ?? ''))\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\nexport function createStorage(owner: string, options: StorageOptions = {}): GuardedStorage {\n if (!OWNER_RE.test(owner)) {\n throw new TypeError(`createStorage: owner \"${owner}\" must match ${OWNER_RE}`);\n }\n const prefix = `${owner}.`;\n const pattern = owner === 'cfg' ? /^cfg(\\.[a-z0-9_]+)+$/ : new RegExp(`^(cfg|${owner})(\\\\.[a-z0-9_]+)+$`);\n const cookieMaxAge = options.cookieMaxAgeSeconds ?? 60 * 60 * 24 * 30;\n let cookiePolicy: 'auto' | string | false = options.cookieDomain ?? 'auto';\n const resolveCookieDomain = (): string | null =>\n cookiePolicy === false ? null : cookiePolicy === 'auto' ? detectCookieDomain() : cookiePolicy;\n // A cookie is identified by name AND Domain: expire the twin without a domain and the one with it.\n const expireCookie = (key: string, domain: string | null) => {\n const secure = window.location.protocol === 'https:' ? '; Secure' : '';\n document.cookie =\n encodeURIComponent(key) + '=; Path=/; Max-Age=0; SameSite=Lax' + (domain ? '; Domain=' + domain : '') + secure;\n };\n const specs = Object.values(options.keys ?? {});\n const families = Object.values(options.families ?? {});\n const specByKey = new Map<string, KeySpec[]>();\n for (const spec of specs) specByKey.set(spec.key, [...(specByKey.get(spec.key) ?? []), spec]);\n // Held in memory when the browser refuses a write (quota, private mode), so the page still works until reload.\n const memory: Record<KeyStore, Map<string, string>> = {\n local: new Map(),\n session: new Map(),\n cookie: new Map(),\n };\n\n const isValid = (key: string) => pattern.test(key);\n const assertValid = (key: string) => {\n if (!isValid(key)) throw new TypeError(`storage key \"${key}\" must match ${pattern}`);\n };\n const assertOwned = (key: string) => {\n assertValid(key);\n if (!key.startsWith(prefix)) throw new TypeError(`storage key \"${key}\" is not owned by \"${owner}\"`);\n };\n\n function rawGet(store: KeyStore, key: string): string | null {\n if (!hasWindow()) return null;\n if (store === 'cookie') {\n try {\n const escaped = encodeURIComponent(key).replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${escaped}=([^;]*)`));\n if (match?.[1] !== undefined) return decodeURIComponent(match[1]);\n } catch {\n /* fall through to memory */\n }\n return memory.cookie.get(key) ?? null;\n }\n try {\n const value = nativeStorage(store)?.getItem(key) ?? null;\n if (value !== null) return value;\n } catch {\n /* fall through to memory */\n }\n return memory[store].get(key) ?? null;\n }\n\n function rawSet(store: KeyStore, key: string, value: string, maxAgeSeconds?: number): boolean {\n if (!hasWindow()) return false;\n try {\n if (store === 'cookie') {\n const secure = window.location.protocol === 'https:' ? '; Secure' : '';\n const domain = resolveCookieDomain();\n const domainPart = domain ? `; Domain=${domain}` : '';\n document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; Path=/; Max-Age=${Math.max(1, Math.floor(maxAgeSeconds ?? cookieMaxAge))}; SameSite=Lax${domainPart}${secure}`;\n // A host-only cookie written earlier would shadow the shared one: drop that twin.\n if (domain) expireCookie(key, null);\n if (rawGet('cookie', key) === value && !memory.cookie.has(key)) return true;\n memory.cookie.set(key, value);\n return false;\n }\n const native = nativeStorage(store);\n if (!native) throw new Error('storage unavailable');\n native.setItem(key, value);\n memory[store].delete(key);\n return true;\n } catch {\n memory[store].set(key, value);\n return false;\n }\n }\n\n function rawRemove(store: KeyStore, key: string): void {\n memory[store].delete(key);\n if (!hasWindow()) return;\n try {\n if (store === 'cookie') {\n expireCookie(key, null);\n const domain = resolveCookieDomain();\n if (domain) expireCookie(key, domain);\n } else {\n nativeStorage(store)?.removeItem(key);\n }\n } catch {\n /* ignore */\n }\n }\n\n function resolveStore(key: string, store?: KeyStore): KeyStore {\n return store ?? specByKey.get(key)?.[0]?.store ?? 'local';\n }\n\n function listKeys(store: 'local' | 'session', startsWith: string): string[] {\n const out: string[] = [];\n try {\n const native = nativeStorage(store);\n if (native) {\n for (let i = 0; i < native.length; i += 1) {\n const name = native.key(i);\n if (name?.startsWith(startsWith)) out.push(name);\n }\n }\n } catch {\n /* ignore */\n }\n for (const name of memory[store].keys()) if (name.startsWith(startsWith) && !out.includes(name)) out.push(name);\n return out;\n }\n\n const familyKey = (family: FamilySpec, id: string) => {\n const part = normalizeSegment(id);\n if (!part) throw new TypeError('storage family id is empty after normalisation');\n return family.prefix + part;\n };\n\n const api: GuardedStorage = {\n owner,\n key(...parts) {\n const segments = parts.map(normalizeSegment);\n if (segments.length === 0 || segments.some((segment) => !segment)) {\n throw new TypeError(`storage key parts must be non-empty: ${JSON.stringify(parts)}`);\n }\n return `${prefix}${segments.join('.')}`;\n },\n familyKey,\n isValid,\n read(key, store) {\n assertValid(key);\n const target = resolveStore(key, store);\n return rawGet(target, key);\n },\n write(key, value, store, writeOptions) {\n assertOwned(key);\n const target = resolveStore(key, store);\n return rawSet(target, key, value, writeOptions?.maxAgeSeconds);\n },\n remove(key, store) {\n assertOwned(key);\n const target = resolveStore(key, store);\n rawRemove(target, key);\n },\n readJSON<T>(key: string, store?: KeyStore): T | null {\n const raw = api.read(key, store);\n if (raw === null) return null;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n },\n writeJSON(key, value, store) {\n return api.write(key, JSON.stringify(value), store);\n },\n keys(store = 'local') {\n return listKeys(store, prefix);\n },\n clearAll({ all = false } = {}) {\n for (const spec of specs) {\n if (!all && !spec.personal) continue;\n rawRemove(spec.store, spec.key);\n }\n for (const family of families) {\n if (!all && !family.personal) continue;\n for (const name of listKeys(family.store, family.prefix)) rawRemove(family.store, name);\n }\n if (all) {\n for (const store of ['local', 'session'] as const) {\n for (const name of listKeys(store, prefix)) rawRemove(store, name);\n }\n for (const name of cookieNames()) if (name.startsWith(prefix)) rawRemove('cookie', name);\n }\n },\n setCookieDomain(domain) {\n cookiePolicy = domain;\n },\n cookieDomain: resolveCookieDomain,\n onChange(key, listener, store = 'local') {\n assertValid(key);\n if (!hasWindow()) return () => {};\n const handler = (event: StorageEvent) => {\n if (event.storageArea !== nativeStorage(store)) return;\n if (event.key === null || event.key === key) listener(event.key === null ? null : event.newValue);\n };\n window.addEventListener('storage', handler);\n return () => window.removeEventListener('storage', handler);\n },\n };\n return api;\n}\n\n/** The framework's own storage: every `cfg.*` key. */\nexport const cfgStorage: GuardedStorage = createStorage('cfg', {\n keys: CFG_KEYS,\n families: CFG_FAMILIES,\n});\n\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/api",
3
- "version": "2.1.603",
3
+ "version": "2.1.604",
4
4
  "description": "Auto-generated TypeScript API client with React hooks, SWR integration, and Zod validation for Django REST Framework backends",
5
5
  "keywords": [
6
6
  "django",
@@ -91,7 +91,7 @@
91
91
  "zod": "^4.3.6"
92
92
  },
93
93
  "devDependencies": {
94
- "@djangocfg/typescript-config": "^2.1.603",
94
+ "@djangocfg/typescript-config": "^2.1.604",
95
95
  "@testing-library/react": "^16.3.2",
96
96
  "@types/node": "^25.9.5",
97
97
  "@types/react": "19.2.15",