@victorylabs/params 0.3.0 → 0.4.0

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/snapshot.ts","../src/name-registry.ts"],"sourcesContent":["import { getDefByName, setPreHydrationValues } from './name-registry'\nimport type { ParamsDefinition } from './types'\n\n/**\n * Snapshot keyed by definition name. Returned from `paramsSnapshot()` and\n * accepted by `hydrateParams()` — round-trip transport for SSR.\n */\nexport type ParamsSnapshot = Record<string, unknown>\n\n/**\n * Server-side: produce a snapshot of the current values for the given\n * definitions, keyed by `def.name`. The returned object is JSON-serializable\n * (call `JSON.stringify` to embed in HTML, or pass through your framework's\n * data-loader contract).\n *\n * Each definition MUST have a `name` set (added in v0.1 for forward-compat,\n * load-bearing in v0.2). Throws otherwise.\n *\n * Throws on duplicate names — the snapshot keys would collide.\n *\n * Reads via the synchronous `def.storage.read()` path. Definitions backed by\n * an async-only backend (sync `read()` returns undefined) snapshot as\n * defaults; pair them with a server-side prefetch step before calling\n * `paramsSnapshot()` if you want their fetched values in the snapshot.\n */\nexport function paramsSnapshot(defs: readonly ParamsDefinition[]): ParamsSnapshot {\n const out: ParamsSnapshot = {}\n const seenNames = new Set<string>()\n\n for (const def of defs) {\n if (def.name === undefined) {\n throw new Error(\n 'paramsSnapshot: every definition must have a `name` set. Add `{ name: \"<unique>\" }` to defineParams.',\n )\n }\n if (seenNames.has(def.name)) {\n throw new Error(\n `paramsSnapshot: duplicate definition name '${def.name}'. Snapshot keys would collide.`,\n )\n }\n seenNames.add(def.name)\n\n let values: unknown = undefined\n try {\n values = def.storage.read() ?? {}\n } catch {\n values = {}\n }\n out[def.name] = values\n }\n\n return out\n}\n\n/**\n * Client-side: pre-seed the params store cache from a server-rendered\n * snapshot. Must run BEFORE the first `useParams(def)` / `getParamsStore(def)`\n * call to avoid a flicker.\n *\n * For each entry in the snapshot, looks up the definition by name (must have\n * been imported / `defineParams` already evaluated on the client) and seeds\n * the pre-hydration cache. The first `ParamsStore` constructed for that def\n * uses the seeded values instead of calling its storage backend's `read()`.\n *\n * Idempotent — re-calling overwrites. Definitions whose names aren't in the\n * snapshot use their normal storage hydration path.\n */\nexport function hydrateParams(snapshot: ParamsSnapshot): void {\n for (const [name, values] of Object.entries(snapshot)) {\n setPreHydrationValues(name, values)\n // Tolerate names with no matching def — the def may load lazily via a\n // dynamic import. The pre-hydration cache holds the values until the\n // matching ParamsStore is constructed.\n void getDefByName(name)\n }\n}\n","import type { ParamsDefinition } from './types'\n\n/**\n * Side-effect registry of all definitions that carry a `name`. Populated by\n * `defineParams()` at construction time so `paramsSnapshot()` and\n * `hydrateParams()` can look up defs by name.\n *\n * Last-write-wins: re-defining the same name overwrites silently (the\n * duplicate-name DEV warning is enforced separately at acquire time in\n * `store-cache.ts`).\n */\nconst nameRegistry = new Map<string, ParamsDefinition<unknown>>()\n\n/**\n * Pre-hydration cache for SSR snapshots. `hydrateParams(snapshot)` populates\n * this; `ParamsStore` checks it during initial hydration and uses the seeded\n * values instead of calling the storage backend's `read()`.\n *\n * Once consumed by a store on first hydration the entry is left in place\n * (idempotent re-hydrate) — the consumer can call `hydrateParams()` again\n * with overrides if needed before any store is constructed.\n */\nconst preHydrationCache = new Map<string, unknown>()\n\nexport function registerNamedDef<T>(def: ParamsDefinition<T>): void {\n if (def.name === undefined) return\n nameRegistry.set(def.name, def as ParamsDefinition<unknown>)\n}\n\nexport function getDefByName(name: string): ParamsDefinition<unknown> | undefined {\n return nameRegistry.get(name)\n}\n\nexport function getRegisteredDefs(): ReadonlyArray<ParamsDefinition<unknown>> {\n return Array.from(nameRegistry.values())\n}\n\nexport function setPreHydrationValues(name: string, values: unknown): void {\n preHydrationCache.set(name, values)\n}\n\nexport function takePreHydrationValues<T>(name: string | undefined): Partial<T> | undefined {\n if (name === undefined) return undefined\n if (!preHydrationCache.has(name)) return undefined\n return preHydrationCache.get(name) as Partial<T>\n}\n\n/** Test-only: clear both registries. Not exported from the package. */\nexport function _resetNameRegistry(): void {\n nameRegistry.clear()\n preHydrationCache.clear()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACWA,IAAM,eAAe,oBAAI,IAAuC;AAWhE,IAAM,oBAAoB,oBAAI,IAAqB;AAO5C,SAAS,aAAa,MAAqD;AAChF,SAAO,aAAa,IAAI,IAAI;AAC9B;AAMO,SAAS,sBAAsB,MAAc,QAAuB;AACzE,oBAAkB,IAAI,MAAM,MAAM;AACpC;;;ADdO,SAAS,eAAe,MAAmD;AAChF,QAAM,MAAsB,CAAC;AAC7B,QAAM,YAAY,oBAAI,IAAY;AAElC,aAAW,OAAO,MAAM;AACtB,QAAI,IAAI,SAAS,QAAW;AAC1B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,UAAU,IAAI,IAAI,IAAI,GAAG;AAC3B,YAAM,IAAI;AAAA,QACR,8CAA8C,IAAI,IAAI;AAAA,MACxD;AAAA,IACF;AACA,cAAU,IAAI,IAAI,IAAI;AAEtB,QAAI,SAAkB;AACtB,QAAI;AACF,eAAS,IAAI,QAAQ,KAAK,KAAK,CAAC;AAAA,IAClC,QAAQ;AACN,eAAS,CAAC;AAAA,IACZ;AACA,QAAI,IAAI,IAAI,IAAI;AAAA,EAClB;AAEA,SAAO;AACT;AAeO,SAAS,cAAc,UAAgC;AAC5D,aAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACrD,0BAAsB,MAAM,MAAM;AAIlC,SAAK,aAAa,IAAI;AAAA,EACxB;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/snapshot.ts","../src/name-registry.ts"],"sourcesContent":["import { getDefByName, setPreHydrationValues } from './name-registry'\nimport type { ParamsDefinition } from './types'\n\n/**\n * Snapshot keyed by definition name. Returned from `paramsSnapshot()` and\n * accepted by `hydrateParams()` — round-trip transport for SSR.\n */\nexport type ParamsSnapshot = Record<string, unknown>\n\n/**\n * Server-side: produce a snapshot of the current values for the given\n * definitions, keyed by `def.name`. The returned object is JSON-serializable\n * (call `JSON.stringify` to embed in HTML, or pass through your framework's\n * data-loader contract).\n *\n * Each definition MUST have a `name` set throws otherwise. The name keys\n * the snapshot record and links the rehydrated value back to its definition.\n *\n * Throws on duplicate names — the snapshot keys would collide.\n *\n * Reads via the synchronous `def.storage.read()` path. Definitions backed by\n * an async-only backend (sync `read()` returns undefined) snapshot as\n * defaults; pair them with a server-side prefetch step before calling\n * `paramsSnapshot()` if you want their fetched values in the snapshot.\n */\nexport function paramsSnapshot(defs: readonly ParamsDefinition[]): ParamsSnapshot {\n const out: ParamsSnapshot = {}\n const seenNames = new Set<string>()\n\n for (const def of defs) {\n if (def.name === undefined) {\n throw new Error(\n 'paramsSnapshot: every definition must have a `name` set. Add `{ name: \"<unique>\" }` to defineParams.',\n )\n }\n if (seenNames.has(def.name)) {\n throw new Error(\n `paramsSnapshot: duplicate definition name '${def.name}'. Snapshot keys would collide.`,\n )\n }\n seenNames.add(def.name)\n\n let values: unknown = undefined\n try {\n values = def.storage.read() ?? {}\n } catch {\n values = {}\n }\n out[def.name] = values\n }\n\n return out\n}\n\n/**\n * Client-side: pre-seed the params store cache from a server-rendered\n * snapshot. Must run BEFORE the first `useParams(def)` / `getParamsStore(def)`\n * call to avoid a flicker.\n *\n * For each entry in the snapshot, looks up the definition by name (must have\n * been imported / `defineParams` already evaluated on the client) and seeds\n * the pre-hydration cache. The first `ParamsStore` constructed for that def\n * uses the seeded values instead of calling its storage backend's `read()`.\n *\n * Idempotent — re-calling overwrites. Definitions whose names aren't in the\n * snapshot use their normal storage hydration path.\n */\nexport function hydrateParams(snapshot: ParamsSnapshot): void {\n for (const [name, values] of Object.entries(snapshot)) {\n setPreHydrationValues(name, values)\n // Tolerate names with no matching def — the def may load lazily via a\n // dynamic import. The pre-hydration cache holds the values until the\n // matching ParamsStore is constructed.\n void getDefByName(name)\n }\n}\n","import type { ParamsDefinition } from './types'\n\n/**\n * Side-effect registry of all definitions that carry a `name`. Populated by\n * `defineParams()` at construction time so `paramsSnapshot()` and\n * `hydrateParams()` can look up defs by name.\n *\n * Last-write-wins: re-defining the same name overwrites silently (the\n * duplicate-name DEV warning is enforced separately at acquire time in\n * `store-cache.ts`).\n */\nconst nameRegistry = new Map<string, ParamsDefinition<unknown>>()\n\n/**\n * Pre-hydration cache for SSR snapshots. `hydrateParams(snapshot)` populates\n * this; `ParamsStore` checks it during initial hydration and uses the seeded\n * values instead of calling the storage backend's `read()`.\n *\n * Once consumed by a store on first hydration the entry is left in place\n * (idempotent re-hydrate) — the consumer can call `hydrateParams()` again\n * with overrides if needed before any store is constructed.\n */\nconst preHydrationCache = new Map<string, unknown>()\n\nexport function registerNamedDef<T>(def: ParamsDefinition<T>): void {\n if (def.name === undefined) return\n nameRegistry.set(def.name, def as ParamsDefinition<unknown>)\n}\n\nexport function getDefByName(name: string): ParamsDefinition<unknown> | undefined {\n return nameRegistry.get(name)\n}\n\nexport function getRegisteredDefs(): ReadonlyArray<ParamsDefinition<unknown>> {\n return Array.from(nameRegistry.values())\n}\n\nexport function setPreHydrationValues(name: string, values: unknown): void {\n preHydrationCache.set(name, values)\n}\n\nexport function takePreHydrationValues<T>(name: string | undefined): Partial<T> | undefined {\n if (name === undefined) return undefined\n if (!preHydrationCache.has(name)) return undefined\n return preHydrationCache.get(name) as Partial<T>\n}\n\n/** Test-only: clear both registries. Not exported from the package. */\nexport function _resetNameRegistry(): void {\n nameRegistry.clear()\n preHydrationCache.clear()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACWA,IAAM,eAAe,oBAAI,IAAuC;AAWhE,IAAM,oBAAoB,oBAAI,IAAqB;AAO5C,SAAS,aAAa,MAAqD;AAChF,SAAO,aAAa,IAAI,IAAI;AAC9B;AAMO,SAAS,sBAAsB,MAAc,QAAuB;AACzE,oBAAkB,IAAI,MAAM,MAAM;AACpC;;;ADdO,SAAS,eAAe,MAAmD;AAChF,QAAM,MAAsB,CAAC;AAC7B,QAAM,YAAY,oBAAI,IAAY;AAElC,aAAW,OAAO,MAAM;AACtB,QAAI,IAAI,SAAS,QAAW;AAC1B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,UAAU,IAAI,IAAI,IAAI,GAAG;AAC3B,YAAM,IAAI;AAAA,QACR,8CAA8C,IAAI,IAAI;AAAA,MACxD;AAAA,IACF;AACA,cAAU,IAAI,IAAI,IAAI;AAEtB,QAAI,SAAkB;AACtB,QAAI;AACF,eAAS,IAAI,QAAQ,KAAK,KAAK,CAAC;AAAA,IAClC,QAAQ;AACN,eAAS,CAAC;AAAA,IACZ;AACA,QAAI,IAAI,IAAI,IAAI;AAAA,EAClB;AAEA,SAAO;AACT;AAeO,SAAS,cAAc,UAAgC;AAC5D,aAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACrD,0BAAsB,MAAM,MAAM;AAIlC,SAAK,aAAa,IAAI;AAAA,EACxB;AACF;","names":[]}
@@ -13,8 +13,8 @@ type ParamsSnapshot = Record<string, unknown>;
13
13
  * (call `JSON.stringify` to embed in HTML, or pass through your framework's
14
14
  * data-loader contract).
15
15
  *
16
- * Each definition MUST have a `name` set (added in v0.1 for forward-compat,
17
- * load-bearing in v0.2). Throws otherwise.
16
+ * Each definition MUST have a `name` set throws otherwise. The name keys
17
+ * the snapshot record and links the rehydrated value back to its definition.
18
18
  *
19
19
  * Throws on duplicate names — the snapshot keys would collide.
20
20
  *
@@ -13,8 +13,8 @@ type ParamsSnapshot = Record<string, unknown>;
13
13
  * (call `JSON.stringify` to embed in HTML, or pass through your framework's
14
14
  * data-loader contract).
15
15
  *
16
- * Each definition MUST have a `name` set (added in v0.1 for forward-compat,
17
- * load-bearing in v0.2). Throws otherwise.
16
+ * Each definition MUST have a `name` set throws otherwise. The name keys
17
+ * the snapshot record and links the rehydrated value back to its definition.
18
18
  *
19
19
  * Throws on duplicate names — the snapshot keys would collide.
20
20
  *
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/snapshot.ts"],"sourcesContent":["import { getDefByName, setPreHydrationValues } from './name-registry'\nimport type { ParamsDefinition } from './types'\n\n/**\n * Snapshot keyed by definition name. Returned from `paramsSnapshot()` and\n * accepted by `hydrateParams()` — round-trip transport for SSR.\n */\nexport type ParamsSnapshot = Record<string, unknown>\n\n/**\n * Server-side: produce a snapshot of the current values for the given\n * definitions, keyed by `def.name`. The returned object is JSON-serializable\n * (call `JSON.stringify` to embed in HTML, or pass through your framework's\n * data-loader contract).\n *\n * Each definition MUST have a `name` set (added in v0.1 for forward-compat,\n * load-bearing in v0.2). Throws otherwise.\n *\n * Throws on duplicate names — the snapshot keys would collide.\n *\n * Reads via the synchronous `def.storage.read()` path. Definitions backed by\n * an async-only backend (sync `read()` returns undefined) snapshot as\n * defaults; pair them with a server-side prefetch step before calling\n * `paramsSnapshot()` if you want their fetched values in the snapshot.\n */\nexport function paramsSnapshot(defs: readonly ParamsDefinition[]): ParamsSnapshot {\n const out: ParamsSnapshot = {}\n const seenNames = new Set<string>()\n\n for (const def of defs) {\n if (def.name === undefined) {\n throw new Error(\n 'paramsSnapshot: every definition must have a `name` set. Add `{ name: \"<unique>\" }` to defineParams.',\n )\n }\n if (seenNames.has(def.name)) {\n throw new Error(\n `paramsSnapshot: duplicate definition name '${def.name}'. Snapshot keys would collide.`,\n )\n }\n seenNames.add(def.name)\n\n let values: unknown = undefined\n try {\n values = def.storage.read() ?? {}\n } catch {\n values = {}\n }\n out[def.name] = values\n }\n\n return out\n}\n\n/**\n * Client-side: pre-seed the params store cache from a server-rendered\n * snapshot. Must run BEFORE the first `useParams(def)` / `getParamsStore(def)`\n * call to avoid a flicker.\n *\n * For each entry in the snapshot, looks up the definition by name (must have\n * been imported / `defineParams` already evaluated on the client) and seeds\n * the pre-hydration cache. The first `ParamsStore` constructed for that def\n * uses the seeded values instead of calling its storage backend's `read()`.\n *\n * Idempotent — re-calling overwrites. Definitions whose names aren't in the\n * snapshot use their normal storage hydration path.\n */\nexport function hydrateParams(snapshot: ParamsSnapshot): void {\n for (const [name, values] of Object.entries(snapshot)) {\n setPreHydrationValues(name, values)\n // Tolerate names with no matching def — the def may load lazily via a\n // dynamic import. The pre-hydration cache holds the values until the\n // matching ParamsStore is constructed.\n void getDefByName(name)\n }\n}\n"],"mappings":";;;;;;AAyBO,SAAS,eAAe,MAAmD;AAChF,QAAM,MAAsB,CAAC;AAC7B,QAAM,YAAY,oBAAI,IAAY;AAElC,aAAW,OAAO,MAAM;AACtB,QAAI,IAAI,SAAS,QAAW;AAC1B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,UAAU,IAAI,IAAI,IAAI,GAAG;AAC3B,YAAM,IAAI;AAAA,QACR,8CAA8C,IAAI,IAAI;AAAA,MACxD;AAAA,IACF;AACA,cAAU,IAAI,IAAI,IAAI;AAEtB,QAAI,SAAkB;AACtB,QAAI;AACF,eAAS,IAAI,QAAQ,KAAK,KAAK,CAAC;AAAA,IAClC,QAAQ;AACN,eAAS,CAAC;AAAA,IACZ;AACA,QAAI,IAAI,IAAI,IAAI;AAAA,EAClB;AAEA,SAAO;AACT;AAeO,SAAS,cAAc,UAAgC;AAC5D,aAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACrD,0BAAsB,MAAM,MAAM;AAIlC,SAAK,aAAa,IAAI;AAAA,EACxB;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/snapshot.ts"],"sourcesContent":["import { getDefByName, setPreHydrationValues } from './name-registry'\nimport type { ParamsDefinition } from './types'\n\n/**\n * Snapshot keyed by definition name. Returned from `paramsSnapshot()` and\n * accepted by `hydrateParams()` — round-trip transport for SSR.\n */\nexport type ParamsSnapshot = Record<string, unknown>\n\n/**\n * Server-side: produce a snapshot of the current values for the given\n * definitions, keyed by `def.name`. The returned object is JSON-serializable\n * (call `JSON.stringify` to embed in HTML, or pass through your framework's\n * data-loader contract).\n *\n * Each definition MUST have a `name` set throws otherwise. The name keys\n * the snapshot record and links the rehydrated value back to its definition.\n *\n * Throws on duplicate names — the snapshot keys would collide.\n *\n * Reads via the synchronous `def.storage.read()` path. Definitions backed by\n * an async-only backend (sync `read()` returns undefined) snapshot as\n * defaults; pair them with a server-side prefetch step before calling\n * `paramsSnapshot()` if you want their fetched values in the snapshot.\n */\nexport function paramsSnapshot(defs: readonly ParamsDefinition[]): ParamsSnapshot {\n const out: ParamsSnapshot = {}\n const seenNames = new Set<string>()\n\n for (const def of defs) {\n if (def.name === undefined) {\n throw new Error(\n 'paramsSnapshot: every definition must have a `name` set. Add `{ name: \"<unique>\" }` to defineParams.',\n )\n }\n if (seenNames.has(def.name)) {\n throw new Error(\n `paramsSnapshot: duplicate definition name '${def.name}'. Snapshot keys would collide.`,\n )\n }\n seenNames.add(def.name)\n\n let values: unknown = undefined\n try {\n values = def.storage.read() ?? {}\n } catch {\n values = {}\n }\n out[def.name] = values\n }\n\n return out\n}\n\n/**\n * Client-side: pre-seed the params store cache from a server-rendered\n * snapshot. Must run BEFORE the first `useParams(def)` / `getParamsStore(def)`\n * call to avoid a flicker.\n *\n * For each entry in the snapshot, looks up the definition by name (must have\n * been imported / `defineParams` already evaluated on the client) and seeds\n * the pre-hydration cache. The first `ParamsStore` constructed for that def\n * uses the seeded values instead of calling its storage backend's `read()`.\n *\n * Idempotent — re-calling overwrites. Definitions whose names aren't in the\n * snapshot use their normal storage hydration path.\n */\nexport function hydrateParams(snapshot: ParamsSnapshot): void {\n for (const [name, values] of Object.entries(snapshot)) {\n setPreHydrationValues(name, values)\n // Tolerate names with no matching def — the def may load lazily via a\n // dynamic import. The pre-hydration cache holds the values until the\n // matching ParamsStore is constructed.\n void getDefByName(name)\n }\n}\n"],"mappings":";;;;;;AAyBO,SAAS,eAAe,MAAmD;AAChF,QAAM,MAAsB,CAAC;AAC7B,QAAM,YAAY,oBAAI,IAAY;AAElC,aAAW,OAAO,MAAM;AACtB,QAAI,IAAI,SAAS,QAAW;AAC1B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,UAAU,IAAI,IAAI,IAAI,GAAG;AAC3B,YAAM,IAAI;AAAA,QACR,8CAA8C,IAAI,IAAI;AAAA,MACxD;AAAA,IACF;AACA,cAAU,IAAI,IAAI,IAAI;AAEtB,QAAI,SAAkB;AACtB,QAAI;AACF,eAAS,IAAI,QAAQ,KAAK,KAAK,CAAC;AAAA,IAClC,QAAQ;AACN,eAAS,CAAC;AAAA,IACZ;AACA,QAAI,IAAI,IAAI,IAAI;AAAA,EAClB;AAEA,SAAO;AACT;AAeO,SAAS,cAAc,UAAgC;AAC5D,aAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACrD,0BAAsB,MAAM,MAAM;AAIlC,SAAK,aAAa,IAAI;AAAA,EACxB;AACF;","names":[]}
@@ -87,8 +87,8 @@ function cookieStorage(options = {}) {
87
87
  } catch {
88
88
  }
89
89
  }
90
- // No subscribe — cookies don't have change events. Cross-tab sync would
91
- // require BroadcastChannel; out of scope for v0.2.
90
+ // No subscribe — cookies don't emit change events. Cross-tab sync would
91
+ // require BroadcastChannel.
92
92
  };
93
93
  }
94
94
  function readRawCookie(key, readCookie) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/storage/cookie/index.ts"],"sourcesContent":["import type { ParamsStorage } from '../../storage'\n\nexport interface CookieStorageAttributes {\n path?: string\n maxAge?: number\n expires?: Date\n domain?: string\n sameSite?: 'Lax' | 'Strict' | 'None'\n secure?: boolean\n}\n\nexport interface CookieStorageOptions<T> {\n /** Cookie name. Default: `'params'`. */\n readonly key?: string\n\n /**\n * Server-side: read from the incoming request's cookies. Closure-bound at\n * factory time. Receives nothing; returns the raw cookie value (already\n * URL-decoded) or `undefined`.\n *\n * If omitted, the backend assumes a client environment and reads from\n * `document.cookie`.\n */\n readonly readCookie?: () => string | undefined\n\n /**\n * Server-side: append to the outgoing response. Closure-bound at factory\n * time. Receives the full `Set-Cookie` header value (e.g. `\"params=foo;\n * Path=/; SameSite=Lax\"`); the consumer is responsible for actually\n * sending it to the browser via their framework's response API.\n *\n * If omitted, the backend assumes a client environment and writes to\n * `document.cookie`.\n */\n readonly writeCookie?: (setCookieValue: string) => void\n\n /** Whole-blob serializer. Default: `JSON.stringify`. */\n readonly serialize?: (values: Partial<T>) => string\n\n /** Whole-blob deserializer. Default: `JSON.parse`. */\n readonly deserialize?: (raw: string) => Partial<T> | undefined\n\n /** Cookie attributes appended to writes. */\n readonly attributes?: CookieStorageAttributes\n}\n\nconst isClient = typeof window !== 'undefined' && typeof document !== 'undefined'\nconst DEFAULT_KEY = 'params'\n\n/**\n * Cookie-backed storage. Works on both the server (via closure-bound\n * `readCookie` / `writeCookie` adapters) and the client (via\n * `document.cookie`). The whole values blob is JSON-encoded under one\n * cookie key.\n *\n * Use cases:\n * - User preferences that should survive a hard refresh (theme, locale).\n * - SSR snapshot transport when paired with `paramsSnapshot()` /\n * `hydrateParams()`.\n *\n * Cookies have a ~4 KB limit per domain — for filter state, prefer\n * `urlStorage`; for app config not tied to a user account, prefer\n * `localStorage`.\n */\nexport function cookieStorage<T = Record<string, unknown>>(\n options: CookieStorageOptions<T> = {},\n): ParamsStorage<T> {\n const key = options.key ?? DEFAULT_KEY\n const serialize = options.serialize ?? (JSON.stringify as (values: Partial<T>) => string)\n const deserialize = options.deserialize ?? (JSON.parse as (raw: string) => Partial<T> | undefined)\n const attrs = options.attributes ?? { path: '/', sameSite: 'Lax' as const }\n\n const readImpl = (): Partial<T> | undefined => {\n const raw = readRawCookie(key, options.readCookie)\n if (raw === undefined) return undefined\n try {\n const parsed = deserialize(raw)\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return undefined\n }\n return parsed\n } catch {\n return undefined\n }\n }\n\n return {\n name: 'cookie',\n // Cookies WORK on the server — that's the whole point of this backend.\n // The store reads on construction, which on the server uses the\n // closure-bound readCookie. clientOnly stays false.\n clientOnly: false,\n read: readImpl,\n write: (values) => {\n try {\n const existing = readImpl() ?? ({} as Partial<T>)\n const merged: Record<string, unknown> = { ...existing }\n for (const [path, value] of Object.entries(values as Record<string, unknown>)) {\n if (value === undefined) {\n delete merged[path]\n } else {\n merged[path] = value\n }\n }\n if (Object.keys(merged).length === 0) {\n writeRawCookie(key, '', { ...attrs, maxAge: 0 }, options.writeCookie)\n return\n }\n writeRawCookie(key, serialize(merged as Partial<T>), attrs, options.writeCookie)\n } catch {\n // Silent fallback — same contract as other backends.\n }\n },\n clear: (paths) => {\n try {\n if (paths.length === 0) {\n writeRawCookie(key, '', { ...attrs, maxAge: 0 }, options.writeCookie)\n return\n }\n const existing = readImpl()\n if (!existing) return\n const next: Record<string, unknown> = { ...(existing as Record<string, unknown>) }\n for (const path of paths) delete next[path]\n if (Object.keys(next).length === 0) {\n writeRawCookie(key, '', { ...attrs, maxAge: 0 }, options.writeCookie)\n return\n }\n writeRawCookie(key, serialize(next as Partial<T>), attrs, options.writeCookie)\n } catch {\n // Silent fallback\n }\n },\n // No subscribe — cookies don't have change events. Cross-tab sync would\n // require BroadcastChannel; out of scope for v0.2.\n }\n}\n\nfunction readRawCookie(\n key: string,\n readCookie: (() => string | undefined) | undefined,\n): string | undefined {\n if (readCookie) {\n const v = readCookie()\n return v === undefined || v === null ? undefined : decodeURIComponent(v)\n }\n if (!isClient) return undefined\n return parseCookieJar(document.cookie, key)\n}\n\nfunction writeRawCookie(\n key: string,\n value: string,\n attrs: CookieStorageAttributes,\n writeCookie: ((setCookieValue: string) => void) | undefined,\n): void {\n const setCookieValue = formatSetCookie(key, value, attrs)\n if (writeCookie) {\n writeCookie(setCookieValue)\n return\n }\n if (!isClient) return\n document.cookie = setCookieValue\n}\n\nfunction parseCookieJar(jar: string, key: string): string | undefined {\n if (!jar) return undefined\n for (const part of jar.split(';')) {\n const eq = part.indexOf('=')\n if (eq === -1) continue\n const k = part.slice(0, eq).trim()\n if (k !== key) continue\n return decodeURIComponent(part.slice(eq + 1).trim())\n }\n return undefined\n}\n\nfunction formatSetCookie(key: string, value: string, attrs: CookieStorageAttributes): string {\n const segments: string[] = [`${key}=${encodeURIComponent(value)}`]\n if (attrs.path !== undefined) segments.push(`Path=${attrs.path}`)\n if (attrs.maxAge !== undefined) segments.push(`Max-Age=${attrs.maxAge}`)\n if (attrs.expires !== undefined) segments.push(`Expires=${attrs.expires.toUTCString()}`)\n if (attrs.domain !== undefined) segments.push(`Domain=${attrs.domain}`)\n if (attrs.sameSite !== undefined) segments.push(`SameSite=${attrs.sameSite}`)\n if (attrs.secure) segments.push('Secure')\n return segments.join('; ')\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/storage/cookie/index.ts"],"sourcesContent":["import type { ParamsStorage } from '../../storage'\n\nexport interface CookieStorageAttributes {\n path?: string\n maxAge?: number\n expires?: Date\n domain?: string\n sameSite?: 'Lax' | 'Strict' | 'None'\n secure?: boolean\n}\n\nexport interface CookieStorageOptions<T> {\n /** Cookie name. Default: `'params'`. */\n readonly key?: string\n\n /**\n * Server-side: read from the incoming request's cookies. Closure-bound at\n * factory time. Receives nothing; returns the raw cookie value (already\n * URL-decoded) or `undefined`.\n *\n * If omitted, the backend assumes a client environment and reads from\n * `document.cookie`.\n */\n readonly readCookie?: () => string | undefined\n\n /**\n * Server-side: append to the outgoing response. Closure-bound at factory\n * time. Receives the full `Set-Cookie` header value (e.g. `\"params=foo;\n * Path=/; SameSite=Lax\"`); the consumer is responsible for actually\n * sending it to the browser via their framework's response API.\n *\n * If omitted, the backend assumes a client environment and writes to\n * `document.cookie`.\n */\n readonly writeCookie?: (setCookieValue: string) => void\n\n /** Whole-blob serializer. Default: `JSON.stringify`. */\n readonly serialize?: (values: Partial<T>) => string\n\n /** Whole-blob deserializer. Default: `JSON.parse`. */\n readonly deserialize?: (raw: string) => Partial<T> | undefined\n\n /** Cookie attributes appended to writes. */\n readonly attributes?: CookieStorageAttributes\n}\n\nconst isClient = typeof window !== 'undefined' && typeof document !== 'undefined'\nconst DEFAULT_KEY = 'params'\n\n/**\n * Cookie-backed storage. Works on both the server (via closure-bound\n * `readCookie` / `writeCookie` adapters) and the client (via\n * `document.cookie`). The whole values blob is JSON-encoded under one\n * cookie key.\n *\n * Use cases:\n * - User preferences that should survive a hard refresh (theme, locale).\n * - SSR snapshot transport when paired with `paramsSnapshot()` /\n * `hydrateParams()`.\n *\n * Cookies have a ~4 KB limit per domain — for filter state, prefer\n * `urlStorage`; for app config not tied to a user account, prefer\n * `localStorage`.\n */\nexport function cookieStorage<T = Record<string, unknown>>(\n options: CookieStorageOptions<T> = {},\n): ParamsStorage<T> {\n const key = options.key ?? DEFAULT_KEY\n const serialize = options.serialize ?? (JSON.stringify as (values: Partial<T>) => string)\n const deserialize = options.deserialize ?? (JSON.parse as (raw: string) => Partial<T> | undefined)\n const attrs = options.attributes ?? { path: '/', sameSite: 'Lax' as const }\n\n const readImpl = (): Partial<T> | undefined => {\n const raw = readRawCookie(key, options.readCookie)\n if (raw === undefined) return undefined\n try {\n const parsed = deserialize(raw)\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return undefined\n }\n return parsed\n } catch {\n return undefined\n }\n }\n\n return {\n name: 'cookie',\n // Cookies WORK on the server — that's the whole point of this backend.\n // The store reads on construction, which on the server uses the\n // closure-bound readCookie. clientOnly stays false.\n clientOnly: false,\n read: readImpl,\n write: (values) => {\n try {\n const existing = readImpl() ?? ({} as Partial<T>)\n const merged: Record<string, unknown> = { ...existing }\n for (const [path, value] of Object.entries(values as Record<string, unknown>)) {\n if (value === undefined) {\n delete merged[path]\n } else {\n merged[path] = value\n }\n }\n if (Object.keys(merged).length === 0) {\n writeRawCookie(key, '', { ...attrs, maxAge: 0 }, options.writeCookie)\n return\n }\n writeRawCookie(key, serialize(merged as Partial<T>), attrs, options.writeCookie)\n } catch {\n // Silent fallback — same contract as other backends.\n }\n },\n clear: (paths) => {\n try {\n if (paths.length === 0) {\n writeRawCookie(key, '', { ...attrs, maxAge: 0 }, options.writeCookie)\n return\n }\n const existing = readImpl()\n if (!existing) return\n const next: Record<string, unknown> = { ...(existing as Record<string, unknown>) }\n for (const path of paths) delete next[path]\n if (Object.keys(next).length === 0) {\n writeRawCookie(key, '', { ...attrs, maxAge: 0 }, options.writeCookie)\n return\n }\n writeRawCookie(key, serialize(next as Partial<T>), attrs, options.writeCookie)\n } catch {\n // Silent fallback\n }\n },\n // No subscribe — cookies don't emit change events. Cross-tab sync would\n // require BroadcastChannel.\n }\n}\n\nfunction readRawCookie(\n key: string,\n readCookie: (() => string | undefined) | undefined,\n): string | undefined {\n if (readCookie) {\n const v = readCookie()\n return v === undefined || v === null ? undefined : decodeURIComponent(v)\n }\n if (!isClient) return undefined\n return parseCookieJar(document.cookie, key)\n}\n\nfunction writeRawCookie(\n key: string,\n value: string,\n attrs: CookieStorageAttributes,\n writeCookie: ((setCookieValue: string) => void) | undefined,\n): void {\n const setCookieValue = formatSetCookie(key, value, attrs)\n if (writeCookie) {\n writeCookie(setCookieValue)\n return\n }\n if (!isClient) return\n document.cookie = setCookieValue\n}\n\nfunction parseCookieJar(jar: string, key: string): string | undefined {\n if (!jar) return undefined\n for (const part of jar.split(';')) {\n const eq = part.indexOf('=')\n if (eq === -1) continue\n const k = part.slice(0, eq).trim()\n if (k !== key) continue\n return decodeURIComponent(part.slice(eq + 1).trim())\n }\n return undefined\n}\n\nfunction formatSetCookie(key: string, value: string, attrs: CookieStorageAttributes): string {\n const segments: string[] = [`${key}=${encodeURIComponent(value)}`]\n if (attrs.path !== undefined) segments.push(`Path=${attrs.path}`)\n if (attrs.maxAge !== undefined) segments.push(`Max-Age=${attrs.maxAge}`)\n if (attrs.expires !== undefined) segments.push(`Expires=${attrs.expires.toUTCString()}`)\n if (attrs.domain !== undefined) segments.push(`Domain=${attrs.domain}`)\n if (attrs.sameSite !== undefined) segments.push(`SameSite=${attrs.sameSite}`)\n if (attrs.secure) segments.push('Secure')\n return segments.join('; ')\n}\n"],"mappings":"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","names":[]}
@@ -63,8 +63,8 @@ function cookieStorage(options = {}) {
63
63
  } catch {
64
64
  }
65
65
  }
66
- // No subscribe — cookies don't have change events. Cross-tab sync would
67
- // require BroadcastChannel; out of scope for v0.2.
66
+ // No subscribe — cookies don't emit change events. Cross-tab sync would
67
+ // require BroadcastChannel.
68
68
  };
69
69
  }
70
70
  function readRawCookie(key, readCookie) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/storage/cookie/index.ts"],"sourcesContent":["import type { ParamsStorage } from '../../storage'\n\nexport interface CookieStorageAttributes {\n path?: string\n maxAge?: number\n expires?: Date\n domain?: string\n sameSite?: 'Lax' | 'Strict' | 'None'\n secure?: boolean\n}\n\nexport interface CookieStorageOptions<T> {\n /** Cookie name. Default: `'params'`. */\n readonly key?: string\n\n /**\n * Server-side: read from the incoming request's cookies. Closure-bound at\n * factory time. Receives nothing; returns the raw cookie value (already\n * URL-decoded) or `undefined`.\n *\n * If omitted, the backend assumes a client environment and reads from\n * `document.cookie`.\n */\n readonly readCookie?: () => string | undefined\n\n /**\n * Server-side: append to the outgoing response. Closure-bound at factory\n * time. Receives the full `Set-Cookie` header value (e.g. `\"params=foo;\n * Path=/; SameSite=Lax\"`); the consumer is responsible for actually\n * sending it to the browser via their framework's response API.\n *\n * If omitted, the backend assumes a client environment and writes to\n * `document.cookie`.\n */\n readonly writeCookie?: (setCookieValue: string) => void\n\n /** Whole-blob serializer. Default: `JSON.stringify`. */\n readonly serialize?: (values: Partial<T>) => string\n\n /** Whole-blob deserializer. Default: `JSON.parse`. */\n readonly deserialize?: (raw: string) => Partial<T> | undefined\n\n /** Cookie attributes appended to writes. */\n readonly attributes?: CookieStorageAttributes\n}\n\nconst isClient = typeof window !== 'undefined' && typeof document !== 'undefined'\nconst DEFAULT_KEY = 'params'\n\n/**\n * Cookie-backed storage. Works on both the server (via closure-bound\n * `readCookie` / `writeCookie` adapters) and the client (via\n * `document.cookie`). The whole values blob is JSON-encoded under one\n * cookie key.\n *\n * Use cases:\n * - User preferences that should survive a hard refresh (theme, locale).\n * - SSR snapshot transport when paired with `paramsSnapshot()` /\n * `hydrateParams()`.\n *\n * Cookies have a ~4 KB limit per domain — for filter state, prefer\n * `urlStorage`; for app config not tied to a user account, prefer\n * `localStorage`.\n */\nexport function cookieStorage<T = Record<string, unknown>>(\n options: CookieStorageOptions<T> = {},\n): ParamsStorage<T> {\n const key = options.key ?? DEFAULT_KEY\n const serialize = options.serialize ?? (JSON.stringify as (values: Partial<T>) => string)\n const deserialize = options.deserialize ?? (JSON.parse as (raw: string) => Partial<T> | undefined)\n const attrs = options.attributes ?? { path: '/', sameSite: 'Lax' as const }\n\n const readImpl = (): Partial<T> | undefined => {\n const raw = readRawCookie(key, options.readCookie)\n if (raw === undefined) return undefined\n try {\n const parsed = deserialize(raw)\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return undefined\n }\n return parsed\n } catch {\n return undefined\n }\n }\n\n return {\n name: 'cookie',\n // Cookies WORK on the server — that's the whole point of this backend.\n // The store reads on construction, which on the server uses the\n // closure-bound readCookie. clientOnly stays false.\n clientOnly: false,\n read: readImpl,\n write: (values) => {\n try {\n const existing = readImpl() ?? ({} as Partial<T>)\n const merged: Record<string, unknown> = { ...existing }\n for (const [path, value] of Object.entries(values as Record<string, unknown>)) {\n if (value === undefined) {\n delete merged[path]\n } else {\n merged[path] = value\n }\n }\n if (Object.keys(merged).length === 0) {\n writeRawCookie(key, '', { ...attrs, maxAge: 0 }, options.writeCookie)\n return\n }\n writeRawCookie(key, serialize(merged as Partial<T>), attrs, options.writeCookie)\n } catch {\n // Silent fallback — same contract as other backends.\n }\n },\n clear: (paths) => {\n try {\n if (paths.length === 0) {\n writeRawCookie(key, '', { ...attrs, maxAge: 0 }, options.writeCookie)\n return\n }\n const existing = readImpl()\n if (!existing) return\n const next: Record<string, unknown> = { ...(existing as Record<string, unknown>) }\n for (const path of paths) delete next[path]\n if (Object.keys(next).length === 0) {\n writeRawCookie(key, '', { ...attrs, maxAge: 0 }, options.writeCookie)\n return\n }\n writeRawCookie(key, serialize(next as Partial<T>), attrs, options.writeCookie)\n } catch {\n // Silent fallback\n }\n },\n // No subscribe — cookies don't have change events. Cross-tab sync would\n // require BroadcastChannel; out of scope for v0.2.\n }\n}\n\nfunction readRawCookie(\n key: string,\n readCookie: (() => string | undefined) | undefined,\n): string | undefined {\n if (readCookie) {\n const v = readCookie()\n return v === undefined || v === null ? undefined : decodeURIComponent(v)\n }\n if (!isClient) return undefined\n return parseCookieJar(document.cookie, key)\n}\n\nfunction writeRawCookie(\n key: string,\n value: string,\n attrs: CookieStorageAttributes,\n writeCookie: ((setCookieValue: string) => void) | undefined,\n): void {\n const setCookieValue = formatSetCookie(key, value, attrs)\n if (writeCookie) {\n writeCookie(setCookieValue)\n return\n }\n if (!isClient) return\n document.cookie = setCookieValue\n}\n\nfunction parseCookieJar(jar: string, key: string): string | undefined {\n if (!jar) return undefined\n for (const part of jar.split(';')) {\n const eq = part.indexOf('=')\n if (eq === -1) continue\n const k = part.slice(0, eq).trim()\n if (k !== key) continue\n return decodeURIComponent(part.slice(eq + 1).trim())\n }\n return undefined\n}\n\nfunction formatSetCookie(key: string, value: string, attrs: CookieStorageAttributes): string {\n const segments: string[] = [`${key}=${encodeURIComponent(value)}`]\n if (attrs.path !== undefined) segments.push(`Path=${attrs.path}`)\n if (attrs.maxAge !== undefined) segments.push(`Max-Age=${attrs.maxAge}`)\n if (attrs.expires !== undefined) segments.push(`Expires=${attrs.expires.toUTCString()}`)\n if (attrs.domain !== undefined) segments.push(`Domain=${attrs.domain}`)\n if (attrs.sameSite !== undefined) segments.push(`SameSite=${attrs.sameSite}`)\n if (attrs.secure) segments.push('Secure')\n return segments.join('; ')\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/storage/cookie/index.ts"],"sourcesContent":["import type { ParamsStorage } from '../../storage'\n\nexport interface CookieStorageAttributes {\n path?: string\n maxAge?: number\n expires?: Date\n domain?: string\n sameSite?: 'Lax' | 'Strict' | 'None'\n secure?: boolean\n}\n\nexport interface CookieStorageOptions<T> {\n /** Cookie name. Default: `'params'`. */\n readonly key?: string\n\n /**\n * Server-side: read from the incoming request's cookies. Closure-bound at\n * factory time. Receives nothing; returns the raw cookie value (already\n * URL-decoded) or `undefined`.\n *\n * If omitted, the backend assumes a client environment and reads from\n * `document.cookie`.\n */\n readonly readCookie?: () => string | undefined\n\n /**\n * Server-side: append to the outgoing response. Closure-bound at factory\n * time. Receives the full `Set-Cookie` header value (e.g. `\"params=foo;\n * Path=/; SameSite=Lax\"`); the consumer is responsible for actually\n * sending it to the browser via their framework's response API.\n *\n * If omitted, the backend assumes a client environment and writes to\n * `document.cookie`.\n */\n readonly writeCookie?: (setCookieValue: string) => void\n\n /** Whole-blob serializer. Default: `JSON.stringify`. */\n readonly serialize?: (values: Partial<T>) => string\n\n /** Whole-blob deserializer. Default: `JSON.parse`. */\n readonly deserialize?: (raw: string) => Partial<T> | undefined\n\n /** Cookie attributes appended to writes. */\n readonly attributes?: CookieStorageAttributes\n}\n\nconst isClient = typeof window !== 'undefined' && typeof document !== 'undefined'\nconst DEFAULT_KEY = 'params'\n\n/**\n * Cookie-backed storage. Works on both the server (via closure-bound\n * `readCookie` / `writeCookie` adapters) and the client (via\n * `document.cookie`). The whole values blob is JSON-encoded under one\n * cookie key.\n *\n * Use cases:\n * - User preferences that should survive a hard refresh (theme, locale).\n * - SSR snapshot transport when paired with `paramsSnapshot()` /\n * `hydrateParams()`.\n *\n * Cookies have a ~4 KB limit per domain — for filter state, prefer\n * `urlStorage`; for app config not tied to a user account, prefer\n * `localStorage`.\n */\nexport function cookieStorage<T = Record<string, unknown>>(\n options: CookieStorageOptions<T> = {},\n): ParamsStorage<T> {\n const key = options.key ?? DEFAULT_KEY\n const serialize = options.serialize ?? (JSON.stringify as (values: Partial<T>) => string)\n const deserialize = options.deserialize ?? (JSON.parse as (raw: string) => Partial<T> | undefined)\n const attrs = options.attributes ?? { path: '/', sameSite: 'Lax' as const }\n\n const readImpl = (): Partial<T> | undefined => {\n const raw = readRawCookie(key, options.readCookie)\n if (raw === undefined) return undefined\n try {\n const parsed = deserialize(raw)\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return undefined\n }\n return parsed\n } catch {\n return undefined\n }\n }\n\n return {\n name: 'cookie',\n // Cookies WORK on the server — that's the whole point of this backend.\n // The store reads on construction, which on the server uses the\n // closure-bound readCookie. clientOnly stays false.\n clientOnly: false,\n read: readImpl,\n write: (values) => {\n try {\n const existing = readImpl() ?? ({} as Partial<T>)\n const merged: Record<string, unknown> = { ...existing }\n for (const [path, value] of Object.entries(values as Record<string, unknown>)) {\n if (value === undefined) {\n delete merged[path]\n } else {\n merged[path] = value\n }\n }\n if (Object.keys(merged).length === 0) {\n writeRawCookie(key, '', { ...attrs, maxAge: 0 }, options.writeCookie)\n return\n }\n writeRawCookie(key, serialize(merged as Partial<T>), attrs, options.writeCookie)\n } catch {\n // Silent fallback — same contract as other backends.\n }\n },\n clear: (paths) => {\n try {\n if (paths.length === 0) {\n writeRawCookie(key, '', { ...attrs, maxAge: 0 }, options.writeCookie)\n return\n }\n const existing = readImpl()\n if (!existing) return\n const next: Record<string, unknown> = { ...(existing as Record<string, unknown>) }\n for (const path of paths) delete next[path]\n if (Object.keys(next).length === 0) {\n writeRawCookie(key, '', { ...attrs, maxAge: 0 }, options.writeCookie)\n return\n }\n writeRawCookie(key, serialize(next as Partial<T>), attrs, options.writeCookie)\n } catch {\n // Silent fallback\n }\n },\n // No subscribe — cookies don't emit change events. Cross-tab sync would\n // require BroadcastChannel.\n }\n}\n\nfunction readRawCookie(\n key: string,\n readCookie: (() => string | undefined) | undefined,\n): string | undefined {\n if (readCookie) {\n const v = readCookie()\n return v === undefined || v === null ? undefined : decodeURIComponent(v)\n }\n if (!isClient) return undefined\n return parseCookieJar(document.cookie, key)\n}\n\nfunction writeRawCookie(\n key: string,\n value: string,\n attrs: CookieStorageAttributes,\n writeCookie: ((setCookieValue: string) => void) | undefined,\n): void {\n const setCookieValue = formatSetCookie(key, value, attrs)\n if (writeCookie) {\n writeCookie(setCookieValue)\n return\n }\n if (!isClient) return\n document.cookie = setCookieValue\n}\n\nfunction parseCookieJar(jar: string, key: string): string | undefined {\n if (!jar) return undefined\n for (const part of jar.split(';')) {\n const eq = part.indexOf('=')\n if (eq === -1) continue\n const k = part.slice(0, eq).trim()\n if (k !== key) continue\n return decodeURIComponent(part.slice(eq + 1).trim())\n }\n return undefined\n}\n\nfunction formatSetCookie(key: string, value: string, attrs: CookieStorageAttributes): string {\n const segments: string[] = [`${key}=${encodeURIComponent(value)}`]\n if (attrs.path !== undefined) segments.push(`Path=${attrs.path}`)\n if (attrs.maxAge !== undefined) segments.push(`Max-Age=${attrs.maxAge}`)\n if (attrs.expires !== undefined) segments.push(`Expires=${attrs.expires.toUTCString()}`)\n if (attrs.domain !== undefined) segments.push(`Domain=${attrs.domain}`)\n if (attrs.sameSite !== undefined) segments.push(`SameSite=${attrs.sameSite}`)\n if (attrs.secure) segments.push('Secure')\n return segments.join('; ')\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@victorylabs/params",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Centralized view-state config (filters, sort, pagination, app config) with pluggable storage. Memory by default; URL/localStorage/sessionStorage opt-in. Single React hook DX, schema-validated reads, cross-component sharing.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -87,7 +87,7 @@
87
87
  "fake-indexeddb": "^6.0.0",
88
88
  "valibot": "^1.3.1",
89
89
  "zod": "^3.23.8",
90
- "@victorylabs/forms": "0.3.0",
90
+ "@victorylabs/forms": "0.4.0",
91
91
  "@victorylabs/utils": "0.1.0"
92
92
  },
93
93
  "peerDependencies": {