@victorylabs/params 0.1.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.
Files changed (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +70 -0
  3. package/dist/chunk-43PUAYQP.js +573 -0
  4. package/dist/chunk-43PUAYQP.js.map +1 -0
  5. package/dist/chunk-4T4THPFW.js +100 -0
  6. package/dist/chunk-4T4THPFW.js.map +1 -0
  7. package/dist/chunk-5NSLHAHG.js +26 -0
  8. package/dist/chunk-5NSLHAHG.js.map +1 -0
  9. package/dist/chunk-NHCH2WKC.js +96 -0
  10. package/dist/chunk-NHCH2WKC.js.map +1 -0
  11. package/dist/chunk-NUO3GOXV.js +72 -0
  12. package/dist/chunk-NUO3GOXV.js.map +1 -0
  13. package/dist/devtools.cjs +41 -0
  14. package/dist/devtools.cjs.map +1 -0
  15. package/dist/devtools.d.cts +45 -0
  16. package/dist/devtools.d.ts +45 -0
  17. package/dist/devtools.js +16 -0
  18. package/dist/devtools.js.map +1 -0
  19. package/dist/index.cjs +777 -0
  20. package/dist/index.cjs.map +1 -0
  21. package/dist/index.d.cts +133 -0
  22. package/dist/index.d.ts +133 -0
  23. package/dist/index.js +83 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/integrations/forms-reverse.cjs +777 -0
  26. package/dist/integrations/forms-reverse.cjs.map +1 -0
  27. package/dist/integrations/forms-reverse.d.cts +32 -0
  28. package/dist/integrations/forms-reverse.d.ts +32 -0
  29. package/dist/integrations/forms-reverse.js +73 -0
  30. package/dist/integrations/forms-reverse.js.map +1 -0
  31. package/dist/integrations/forms.cjs +771 -0
  32. package/dist/integrations/forms.cjs.map +1 -0
  33. package/dist/integrations/forms.d.cts +25 -0
  34. package/dist/integrations/forms.d.ts +25 -0
  35. package/dist/integrations/forms.js +65 -0
  36. package/dist/integrations/forms.js.map +1 -0
  37. package/dist/params-store-Cgbtn53j.d.cts +115 -0
  38. package/dist/params-store-CguA9-yr.d.ts +115 -0
  39. package/dist/react.cjs +910 -0
  40. package/dist/react.cjs.map +1 -0
  41. package/dist/react.d.cts +75 -0
  42. package/dist/react.d.ts +75 -0
  43. package/dist/react.js +202 -0
  44. package/dist/react.js.map +1 -0
  45. package/dist/snapshot.cjs +75 -0
  46. package/dist/snapshot.cjs.map +1 -0
  47. package/dist/snapshot.d.cts +42 -0
  48. package/dist/snapshot.d.ts +42 -0
  49. package/dist/snapshot.js +42 -0
  50. package/dist/snapshot.js.map +1 -0
  51. package/dist/storage/compose.cjs +196 -0
  52. package/dist/storage/compose.cjs.map +1 -0
  53. package/dist/storage/compose.d.cts +35 -0
  54. package/dist/storage/compose.d.ts +35 -0
  55. package/dist/storage/compose.js +123 -0
  56. package/dist/storage/compose.js.map +1 -0
  57. package/dist/storage/cookie.cjs +136 -0
  58. package/dist/storage/cookie.cjs.map +1 -0
  59. package/dist/storage/cookie.d.cts +57 -0
  60. package/dist/storage/cookie.d.ts +57 -0
  61. package/dist/storage/cookie.js +111 -0
  62. package/dist/storage/cookie.js.map +1 -0
  63. package/dist/storage/idb.cjs +144 -0
  64. package/dist/storage/idb.cjs.map +1 -0
  65. package/dist/storage/idb.d.cts +31 -0
  66. package/dist/storage/idb.d.ts +31 -0
  67. package/dist/storage/idb.js +119 -0
  68. package/dist/storage/idb.js.map +1 -0
  69. package/dist/storage/local.cjs +121 -0
  70. package/dist/storage/local.cjs.map +1 -0
  71. package/dist/storage/local.d.cts +23 -0
  72. package/dist/storage/local.d.ts +23 -0
  73. package/dist/storage/local.js +9 -0
  74. package/dist/storage/local.js.map +1 -0
  75. package/dist/storage/server.cjs +158 -0
  76. package/dist/storage/server.cjs.map +1 -0
  77. package/dist/storage/server.d.cts +57 -0
  78. package/dist/storage/server.d.ts +57 -0
  79. package/dist/storage/server.js +133 -0
  80. package/dist/storage/server.js.map +1 -0
  81. package/dist/storage/session.cjs +123 -0
  82. package/dist/storage/session.cjs.map +1 -0
  83. package/dist/storage/session.d.cts +14 -0
  84. package/dist/storage/session.d.ts +14 -0
  85. package/dist/storage/session.js +12 -0
  86. package/dist/storage/session.js.map +1 -0
  87. package/dist/storage/url.cjs +132 -0
  88. package/dist/storage/url.cjs.map +1 -0
  89. package/dist/storage/url.d.cts +37 -0
  90. package/dist/storage/url.d.ts +37 -0
  91. package/dist/storage/url.js +100 -0
  92. package/dist/storage/url.js.map +1 -0
  93. package/dist/storage-DBLIRR-4.d.cts +59 -0
  94. package/dist/storage-DBLIRR-4.d.ts +59 -0
  95. package/dist/types-BSWKH-jw.d.cts +68 -0
  96. package/dist/types-BUmNpSyP.d.ts +68 -0
  97. package/package.json +114 -0
@@ -0,0 +1,119 @@
1
+ // src/storage/idb/index.ts
2
+ var isClient = typeof window !== "undefined" && typeof window.indexedDB !== "undefined";
3
+ function idbStorage(opts) {
4
+ const dbName = opts.db;
5
+ const storeName = opts.store ?? "params";
6
+ const recordKey = opts.key ?? "default";
7
+ const version = opts.version ?? 1;
8
+ let dbHandle;
9
+ const openDb = async () => {
10
+ if (!isClient) throw new Error("idbStorage: window.indexedDB unavailable");
11
+ if (dbHandle && dbHandle.version === version) return dbHandle;
12
+ return new Promise((resolve, reject) => {
13
+ const req = window.indexedDB.open(dbName, version);
14
+ req.onupgradeneeded = () => {
15
+ const db = req.result;
16
+ if (!db.objectStoreNames.contains(storeName)) {
17
+ db.createObjectStore(storeName);
18
+ }
19
+ };
20
+ req.onsuccess = () => {
21
+ dbHandle = req.result;
22
+ dbHandle.onclose = () => {
23
+ dbHandle = void 0;
24
+ };
25
+ resolve(req.result);
26
+ };
27
+ req.onerror = () => reject(req.error);
28
+ });
29
+ };
30
+ const withVersionRetry = async (op) => {
31
+ try {
32
+ return await op(await openDb());
33
+ } catch (err) {
34
+ const isVersionError = typeof DOMException !== "undefined" && err instanceof DOMException && err.name === "VersionError";
35
+ if (!isVersionError) throw err;
36
+ try {
37
+ dbHandle?.close();
38
+ } catch {
39
+ }
40
+ dbHandle = void 0;
41
+ return op(await openDb());
42
+ }
43
+ };
44
+ return {
45
+ name: "idbStorage",
46
+ clientOnly: true,
47
+ // IDB has no synchronous API. Engine consults `readAsync` for hydration;
48
+ // `read()` always returns undefined.
49
+ read: () => void 0,
50
+ readAsync: async () => {
51
+ if (!isClient) return void 0;
52
+ try {
53
+ return await withVersionRetry(
54
+ (db) => new Promise((resolve, reject) => {
55
+ const tx = db.transaction(storeName, "readonly");
56
+ const req = tx.objectStore(storeName).get(recordKey);
57
+ req.onsuccess = () => resolve(req.result ?? void 0);
58
+ req.onerror = () => reject(req.error);
59
+ })
60
+ );
61
+ } catch {
62
+ return void 0;
63
+ }
64
+ },
65
+ write: async (values, _changed, _options) => {
66
+ if (!isClient) return;
67
+ try {
68
+ await withVersionRetry(
69
+ (db) => new Promise((resolve, reject) => {
70
+ const tx = db.transaction(storeName, "readwrite");
71
+ const req = tx.objectStore(storeName).put(values, recordKey);
72
+ req.onsuccess = () => resolve();
73
+ req.onerror = () => reject(req.error);
74
+ })
75
+ );
76
+ } catch {
77
+ }
78
+ },
79
+ clear: async (paths, _options) => {
80
+ if (!isClient) return;
81
+ try {
82
+ if (paths.length === 0) {
83
+ await withVersionRetry(
84
+ (db) => new Promise((resolve, reject) => {
85
+ const tx = db.transaction(storeName, "readwrite");
86
+ const req = tx.objectStore(storeName).delete(recordKey);
87
+ req.onsuccess = () => resolve();
88
+ req.onerror = () => reject(req.error);
89
+ })
90
+ );
91
+ return;
92
+ }
93
+ const current = await withVersionRetry(
94
+ (db) => new Promise((resolve, reject) => {
95
+ const tx = db.transaction(storeName, "readonly");
96
+ const req = tx.objectStore(storeName).get(recordKey);
97
+ req.onsuccess = () => resolve(req.result ?? {});
98
+ req.onerror = () => reject(req.error);
99
+ })
100
+ );
101
+ for (const p of paths) delete current[p];
102
+ await withVersionRetry(
103
+ (db) => new Promise((resolve, reject) => {
104
+ const tx = db.transaction(storeName, "readwrite");
105
+ const req = tx.objectStore(storeName).put(current, recordKey);
106
+ req.onsuccess = () => resolve();
107
+ req.onerror = () => reject(req.error);
108
+ })
109
+ );
110
+ } catch {
111
+ }
112
+ }
113
+ // No `subscribe` — IDB doesn't fire native change events. v0.6+ via BroadcastChannel.
114
+ };
115
+ }
116
+ export {
117
+ idbStorage
118
+ };
119
+ //# sourceMappingURL=idb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/storage/idb/index.ts"],"sourcesContent":["import type { ParamsStorage } from '../../storage'\n\nexport interface IdbStorageOptions {\n /** Database name. Required. */\n readonly db: string\n /** Object store name within the database. Default: `'params'`. */\n readonly store?: string\n /** Record key within the store. Default: `'default'`. */\n readonly key?: string\n /** Schema version. Bump if you change the value shape across releases. Default: `1`. */\n readonly version?: number\n}\n\nconst isClient = typeof window !== 'undefined' && typeof window.indexedDB !== 'undefined'\n\n/**\n * IndexedDB storage backend.\n *\n * Async-only — `read()` returns `undefined` synchronously; the engine should\n * consult `readAsync()` for hydration. Single record per definition (the\n * `key` option), stored as a structured-clonable object — no JSON\n * serialization layer.\n *\n * v0.5 limitations (likely v0.6+ candidates if a consumer asks):\n * - **No cross-tab sync** (no BroadcastChannel). The same database is shared\n * across tabs, but writes from one tab don't push to another. Subscribe is\n * intentionally absent.\n * - **No consumer-supplied `onupgradeneeded` hook.** The `version` option\n * triggers an upgrade transaction and the lib creates the object store on\n * first open, but you can't migrate from a previous shape.\n */\nexport function idbStorage<T = Record<string, unknown>>(opts: IdbStorageOptions): ParamsStorage<T> {\n const dbName = opts.db\n const storeName = opts.store ?? 'params'\n const recordKey = opts.key ?? 'default'\n const version = opts.version ?? 1\n\n // Cache the database handle. Re-opens on demand if closed.\n let dbHandle: IDBDatabase | undefined\n const openDb = async (): Promise<IDBDatabase> => {\n if (!isClient) throw new Error('idbStorage: window.indexedDB unavailable')\n if (dbHandle && dbHandle.version === version) return dbHandle\n return new Promise((resolve, reject) => {\n const req = window.indexedDB.open(dbName, version)\n req.onupgradeneeded = () => {\n const db = req.result\n if (!db.objectStoreNames.contains(storeName)) {\n db.createObjectStore(storeName)\n }\n }\n req.onsuccess = () => {\n dbHandle = req.result\n dbHandle.onclose = () => {\n dbHandle = undefined\n }\n resolve(req.result)\n }\n req.onerror = () => reject(req.error)\n })\n }\n\n /**\n * v0.5: retry once on `VersionError`. Another tab opening the DB at a\n * different version invalidates our cached handle. Close it, re-open, and\n * retry the operation. After one retry, fall back to silent (existing\n * contract).\n */\n const withVersionRetry = async <R>(op: (db: IDBDatabase) => Promise<R>): Promise<R> => {\n try {\n return await op(await openDb())\n } catch (err) {\n const isVersionError =\n typeof DOMException !== 'undefined' &&\n err instanceof DOMException &&\n err.name === 'VersionError'\n if (!isVersionError) throw err\n try {\n dbHandle?.close()\n } catch {\n // ignore — handle may already be invalid\n }\n dbHandle = undefined\n return op(await openDb())\n }\n }\n\n return {\n name: 'idbStorage',\n clientOnly: true,\n\n // IDB has no synchronous API. Engine consults `readAsync` for hydration;\n // `read()` always returns undefined.\n read: () => undefined,\n\n readAsync: async () => {\n if (!isClient) return undefined\n try {\n return await withVersionRetry(\n (db) =>\n new Promise<Partial<T> | undefined>((resolve, reject) => {\n const tx = db.transaction(storeName, 'readonly')\n const req = tx.objectStore(storeName).get(recordKey)\n req.onsuccess = () => resolve((req.result as Partial<T> | undefined) ?? undefined)\n req.onerror = () => reject(req.error)\n }),\n )\n } catch {\n return undefined\n }\n },\n\n write: async (values, _changed, _options) => {\n if (!isClient) return\n try {\n await withVersionRetry(\n (db) =>\n new Promise<void>((resolve, reject) => {\n const tx = db.transaction(storeName, 'readwrite')\n const req = tx.objectStore(storeName).put(values, recordKey)\n req.onsuccess = () => resolve()\n req.onerror = () => reject(req.error)\n }),\n )\n } catch {\n // Silent fallback per the storage error contract — values still live in memory.\n }\n },\n\n clear: async (paths, _options) => {\n if (!isClient) return\n try {\n if (paths.length === 0) {\n // Clear everything — delete the record.\n await withVersionRetry(\n (db) =>\n new Promise<void>((resolve, reject) => {\n const tx = db.transaction(storeName, 'readwrite')\n const req = tx.objectStore(storeName).delete(recordKey)\n req.onsuccess = () => resolve()\n req.onerror = () => reject(req.error)\n }),\n )\n return\n }\n // Per-path clear: read current, omit cleared paths, write back.\n const current = await withVersionRetry(\n (db) =>\n new Promise<Record<string, unknown>>((resolve, reject) => {\n const tx = db.transaction(storeName, 'readonly')\n const req = tx.objectStore(storeName).get(recordKey)\n req.onsuccess = () =>\n resolve((req.result as Record<string, unknown> | undefined) ?? {})\n req.onerror = () => reject(req.error)\n }),\n )\n for (const p of paths) delete current[p]\n await withVersionRetry(\n (db) =>\n new Promise<void>((resolve, reject) => {\n const tx = db.transaction(storeName, 'readwrite')\n const req = tx.objectStore(storeName).put(current, recordKey)\n req.onsuccess = () => resolve()\n req.onerror = () => reject(req.error)\n }),\n )\n } catch {\n // Silent fallback.\n }\n },\n\n // No `subscribe` — IDB doesn't fire native change events. v0.6+ via BroadcastChannel.\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/storage/local/index.ts
21
+ var local_exports = {};
22
+ __export(local_exports, {
23
+ browserStorage: () => browserStorage,
24
+ localStorage: () => localStorage
25
+ });
26
+ module.exports = __toCommonJS(local_exports);
27
+ var isClient = typeof window !== "undefined";
28
+ function localStorage(options) {
29
+ return browserStorage("localStorage", options);
30
+ }
31
+ function getStore(kind) {
32
+ if (!isClient) return void 0;
33
+ try {
34
+ return kind === "localStorage" ? window.localStorage : window.sessionStorage;
35
+ } catch {
36
+ return void 0;
37
+ }
38
+ }
39
+ function browserStorage(kind, options) {
40
+ const serialize = options.serialize ?? JSON.stringify;
41
+ const deserialize = options.deserialize ?? JSON.parse;
42
+ const readImpl = () => {
43
+ const store = getStore(kind);
44
+ if (!store) return void 0;
45
+ try {
46
+ const raw = store.getItem(options.key);
47
+ if (raw === null) return void 0;
48
+ const parsed = deserialize(raw);
49
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
50
+ return void 0;
51
+ }
52
+ return parsed;
53
+ } catch {
54
+ return void 0;
55
+ }
56
+ };
57
+ return {
58
+ name: kind === "localStorage" ? "localStorage" : "sessionStorage",
59
+ clientOnly: true,
60
+ read: readImpl,
61
+ write: (values) => {
62
+ const store = getStore(kind);
63
+ if (!store) return;
64
+ try {
65
+ const existing = readImpl() ?? {};
66
+ const merged = { ...existing };
67
+ for (const [path, value] of Object.entries(values)) {
68
+ if (value === void 0) {
69
+ delete merged[path];
70
+ } else {
71
+ merged[path] = value;
72
+ }
73
+ }
74
+ if (Object.keys(merged).length === 0) {
75
+ store.removeItem(options.key);
76
+ } else {
77
+ store.setItem(options.key, serialize(merged));
78
+ }
79
+ } catch {
80
+ }
81
+ },
82
+ clear: (paths) => {
83
+ const store = getStore(kind);
84
+ if (!store) return;
85
+ try {
86
+ if (paths.length === 0) {
87
+ store.removeItem(options.key);
88
+ return;
89
+ }
90
+ const existing = readImpl();
91
+ if (!existing) return;
92
+ const next = { ...existing };
93
+ for (const path of paths) delete next[path];
94
+ if (Object.keys(next).length === 0) {
95
+ store.removeItem(options.key);
96
+ } else {
97
+ store.setItem(options.key, serialize(next));
98
+ }
99
+ } catch {
100
+ }
101
+ },
102
+ subscribe: (callback) => {
103
+ if (!isClient) return () => void 0;
104
+ const targetStore = getStore(kind);
105
+ const handler = (event) => {
106
+ if (event.key !== options.key && event.key !== null) return;
107
+ if (targetStore && event.storageArea !== targetStore) return;
108
+ const values = readImpl();
109
+ if (values) callback(values);
110
+ };
111
+ window.addEventListener("storage", handler);
112
+ return () => window.removeEventListener("storage", handler);
113
+ }
114
+ };
115
+ }
116
+ // Annotate the CommonJS export names for ESM import in node:
117
+ 0 && (module.exports = {
118
+ browserStorage,
119
+ localStorage
120
+ });
121
+ //# sourceMappingURL=local.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/storage/local/index.ts"],"sourcesContent":["import type { ParamsStorage } from '../../storage'\n\nexport interface LocalStorageOptions {\n /** Storage key the backend owns. */\n readonly key: string\n /** Whole-blob serializer. Default: `JSON.stringify`. */\n readonly serialize?: (values: unknown) => string\n /** Whole-blob deserializer. Default: `JSON.parse`. */\n readonly deserialize?: (raw: string) => unknown\n}\n\nconst isClient = typeof window !== 'undefined'\n\n/**\n * `localStorage`-backed storage. Persists managed paths under a single\n * JSON-encoded key. Cross-tab sync via `storage` events.\n *\n * Limitations:\n * - Same-tab `localStorage.setItem(key, ...)` calls from outside the lib\n * are not observed (`storage` event doesn't fire for same-tab writes).\n * - Storage failures (quota, private mode) silently fall back to in-memory.\n */\nexport function localStorage<T = Record<string, unknown>>(\n options: LocalStorageOptions,\n): ParamsStorage<T> {\n return browserStorage<T>('localStorage', options)\n}\n\nfunction getStore(kind: 'localStorage' | 'sessionStorage'): Storage | undefined {\n if (!isClient) return undefined\n try {\n return kind === 'localStorage' ? window.localStorage : window.sessionStorage\n } catch {\n // Some browsers throw accessing storage in private mode\n return undefined\n }\n}\n\nexport function browserStorage<T>(\n kind: 'localStorage' | 'sessionStorage',\n options: LocalStorageOptions,\n): ParamsStorage<T> {\n const serialize = options.serialize ?? JSON.stringify\n const deserialize = options.deserialize ?? JSON.parse\n\n const readImpl = (): Partial<T> | undefined => {\n const store = getStore(kind)\n if (!store) return undefined\n try {\n const raw = store.getItem(options.key)\n if (raw === null) return undefined\n const parsed = deserialize(raw)\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return undefined\n }\n return parsed as Partial<T>\n } catch {\n return undefined\n }\n }\n\n return {\n name: kind === 'localStorage' ? 'localStorage' : 'sessionStorage',\n clientOnly: true,\n read: readImpl,\n write: (values) => {\n const store = getStore(kind)\n if (!store) return\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 store.removeItem(options.key)\n } else {\n store.setItem(options.key, serialize(merged))\n }\n } catch {\n // Quota exceeded / unavailable — silent fallback\n }\n },\n clear: (paths) => {\n const store = getStore(kind)\n if (!store) return\n try {\n if (paths.length === 0) {\n store.removeItem(options.key)\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 store.removeItem(options.key)\n } else {\n store.setItem(options.key, serialize(next))\n }\n } catch {\n // Silent fallback\n }\n },\n subscribe: (callback) => {\n if (!isClient) return () => undefined\n const targetStore = getStore(kind)\n const handler = (event: StorageEvent) => {\n // Ignore unrelated keys; null === storage cleared\n if (event.key !== options.key && event.key !== null) return\n if (targetStore && event.storageArea !== targetStore) return\n const values = readImpl()\n if (values) callback(values)\n }\n window.addEventListener('storage', handler)\n return () => window.removeEventListener('storage', handler)\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA,IAAM,WAAW,OAAO,WAAW;AAW5B,SAAS,aACd,SACkB;AAClB,SAAO,eAAkB,gBAAgB,OAAO;AAClD;AAEA,SAAS,SAAS,MAA8D;AAC9E,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI;AACF,WAAO,SAAS,iBAAiB,OAAO,eAAe,OAAO;AAAA,EAChE,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,eACd,MACA,SACkB;AAClB,QAAM,YAAY,QAAQ,aAAa,KAAK;AAC5C,QAAM,cAAc,QAAQ,eAAe,KAAK;AAEhD,QAAM,WAAW,MAA8B;AAC7C,UAAM,QAAQ,SAAS,IAAI;AAC3B,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI;AACF,YAAM,MAAM,MAAM,QAAQ,QAAQ,GAAG;AACrC,UAAI,QAAQ,KAAM,QAAO;AACzB,YAAM,SAAS,YAAY,GAAG;AAC9B,UAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AAC1E,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,SAAS,iBAAiB,iBAAiB;AAAA,IACjD,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,OAAO,CAAC,WAAW;AACjB,YAAM,QAAQ,SAAS,IAAI;AAC3B,UAAI,CAAC,MAAO;AACZ,UAAI;AACF,cAAM,WAAW,SAAS,KAAM,CAAC;AACjC,cAAM,SAAkC,EAAE,GAAG,SAAS;AACtD,mBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,MAAiC,GAAG;AAC7E,cAAI,UAAU,QAAW;AACvB,mBAAO,OAAO,IAAI;AAAA,UACpB,OAAO;AACL,mBAAO,IAAI,IAAI;AAAA,UACjB;AAAA,QACF;AACA,YAAI,OAAO,KAAK,MAAM,EAAE,WAAW,GAAG;AACpC,gBAAM,WAAW,QAAQ,GAAG;AAAA,QAC9B,OAAO;AACL,gBAAM,QAAQ,QAAQ,KAAK,UAAU,MAAM,CAAC;AAAA,QAC9C;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,OAAO,CAAC,UAAU;AAChB,YAAM,QAAQ,SAAS,IAAI;AAC3B,UAAI,CAAC,MAAO;AACZ,UAAI;AACF,YAAI,MAAM,WAAW,GAAG;AACtB,gBAAM,WAAW,QAAQ,GAAG;AAC5B;AAAA,QACF;AACA,cAAM,WAAW,SAAS;AAC1B,YAAI,CAAC,SAAU;AACf,cAAM,OAAgC,EAAE,GAAI,SAAqC;AACjF,mBAAW,QAAQ,MAAO,QAAO,KAAK,IAAI;AAC1C,YAAI,OAAO,KAAK,IAAI,EAAE,WAAW,GAAG;AAClC,gBAAM,WAAW,QAAQ,GAAG;AAAA,QAC9B,OAAO;AACL,gBAAM,QAAQ,QAAQ,KAAK,UAAU,IAAI,CAAC;AAAA,QAC5C;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,WAAW,CAAC,aAAa;AACvB,UAAI,CAAC,SAAU,QAAO,MAAM;AAC5B,YAAM,cAAc,SAAS,IAAI;AACjC,YAAM,UAAU,CAAC,UAAwB;AAEvC,YAAI,MAAM,QAAQ,QAAQ,OAAO,MAAM,QAAQ,KAAM;AACrD,YAAI,eAAe,MAAM,gBAAgB,YAAa;AACtD,cAAM,SAAS,SAAS;AACxB,YAAI,OAAQ,UAAS,MAAM;AAAA,MAC7B;AACA,aAAO,iBAAiB,WAAW,OAAO;AAC1C,aAAO,MAAM,OAAO,oBAAoB,WAAW,OAAO;AAAA,IAC5D;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,23 @@
1
+ import { P as ParamsStorage } from '../storage-DBLIRR-4.cjs';
2
+
3
+ interface LocalStorageOptions {
4
+ /** Storage key the backend owns. */
5
+ readonly key: string;
6
+ /** Whole-blob serializer. Default: `JSON.stringify`. */
7
+ readonly serialize?: (values: unknown) => string;
8
+ /** Whole-blob deserializer. Default: `JSON.parse`. */
9
+ readonly deserialize?: (raw: string) => unknown;
10
+ }
11
+ /**
12
+ * `localStorage`-backed storage. Persists managed paths under a single
13
+ * JSON-encoded key. Cross-tab sync via `storage` events.
14
+ *
15
+ * Limitations:
16
+ * - Same-tab `localStorage.setItem(key, ...)` calls from outside the lib
17
+ * are not observed (`storage` event doesn't fire for same-tab writes).
18
+ * - Storage failures (quota, private mode) silently fall back to in-memory.
19
+ */
20
+ declare function localStorage<T = Record<string, unknown>>(options: LocalStorageOptions): ParamsStorage<T>;
21
+ declare function browserStorage<T>(kind: 'localStorage' | 'sessionStorage', options: LocalStorageOptions): ParamsStorage<T>;
22
+
23
+ export { type LocalStorageOptions, browserStorage, localStorage };
@@ -0,0 +1,23 @@
1
+ import { P as ParamsStorage } from '../storage-DBLIRR-4.js';
2
+
3
+ interface LocalStorageOptions {
4
+ /** Storage key the backend owns. */
5
+ readonly key: string;
6
+ /** Whole-blob serializer. Default: `JSON.stringify`. */
7
+ readonly serialize?: (values: unknown) => string;
8
+ /** Whole-blob deserializer. Default: `JSON.parse`. */
9
+ readonly deserialize?: (raw: string) => unknown;
10
+ }
11
+ /**
12
+ * `localStorage`-backed storage. Persists managed paths under a single
13
+ * JSON-encoded key. Cross-tab sync via `storage` events.
14
+ *
15
+ * Limitations:
16
+ * - Same-tab `localStorage.setItem(key, ...)` calls from outside the lib
17
+ * are not observed (`storage` event doesn't fire for same-tab writes).
18
+ * - Storage failures (quota, private mode) silently fall back to in-memory.
19
+ */
20
+ declare function localStorage<T = Record<string, unknown>>(options: LocalStorageOptions): ParamsStorage<T>;
21
+ declare function browserStorage<T>(kind: 'localStorage' | 'sessionStorage', options: LocalStorageOptions): ParamsStorage<T>;
22
+
23
+ export { type LocalStorageOptions, browserStorage, localStorage };
@@ -0,0 +1,9 @@
1
+ import {
2
+ browserStorage,
3
+ localStorage
4
+ } from "../chunk-NHCH2WKC.js";
5
+ export {
6
+ browserStorage,
7
+ localStorage
8
+ };
9
+ //# sourceMappingURL=local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/storage/server/index.ts
21
+ var server_exports = {};
22
+ __export(server_exports, {
23
+ serverStorage: () => serverStorage
24
+ });
25
+ module.exports = __toCommonJS(server_exports);
26
+ var RETRY_CAP = 10;
27
+ var DEFAULT_RETRY = 3;
28
+ var MAX_BACKOFF_MS = 5e3;
29
+ function serverStorage(opts) {
30
+ const name = opts.name ?? "serverStorage";
31
+ const retryDelay = opts.retryDelay ?? defaultBackoff;
32
+ let cache;
33
+ let lastFetchAt = 0;
34
+ const controllers = /* @__PURE__ */ new Set();
35
+ const subscribers = /* @__PURE__ */ new Set();
36
+ let revalidateTimer;
37
+ const cancelInFlight = () => {
38
+ for (const c of controllers) c.abort();
39
+ controllers.clear();
40
+ if (revalidateTimer !== void 0) {
41
+ clearTimeout(revalidateTimer);
42
+ revalidateTimer = void 0;
43
+ }
44
+ };
45
+ const performRead = async () => {
46
+ const controller = new AbortController();
47
+ controllers.add(controller);
48
+ try {
49
+ const values = await runWithRetry(
50
+ (signal) => opts.read(signal),
51
+ controller.signal,
52
+ opts.retry ?? DEFAULT_RETRY,
53
+ retryDelay
54
+ );
55
+ if (controller.signal.aborted) return void 0;
56
+ if (values !== void 0) {
57
+ cache = values;
58
+ lastFetchAt = Date.now();
59
+ for (const sub of subscribers) sub(values);
60
+ }
61
+ return values ?? void 0;
62
+ } finally {
63
+ controllers.delete(controller);
64
+ }
65
+ };
66
+ const scheduleRevalidate = (delayMs) => {
67
+ if (revalidateTimer !== void 0) return;
68
+ revalidateTimer = setTimeout(() => {
69
+ revalidateTimer = void 0;
70
+ void performRead();
71
+ }, delayMs);
72
+ };
73
+ return {
74
+ name,
75
+ clientOnly: false,
76
+ // Sync read returns the cached snapshot. Returns undefined until the
77
+ // first successful readAsync — the engine then falls back to defaults.
78
+ read: () => cache,
79
+ // Async read with retry + cancellation + optional SWR.
80
+ readAsync: async () => {
81
+ const staleTime = opts.staleTime ?? 0;
82
+ const elapsed = Date.now() - lastFetchAt;
83
+ if (staleTime > 0 && cache !== void 0 && elapsed < staleTime) {
84
+ return cache;
85
+ }
86
+ if (staleTime > 0 && cache !== void 0 && elapsed >= staleTime) {
87
+ scheduleRevalidate(0);
88
+ return cache;
89
+ }
90
+ return performRead();
91
+ },
92
+ write: async (values) => {
93
+ await runWithRetry(
94
+ () => opts.write(values),
95
+ // Writes are committal — no engine-driven cancellation.
96
+ new AbortController().signal,
97
+ opts.retry ?? DEFAULT_RETRY,
98
+ retryDelay
99
+ );
100
+ cache = { ...cache, ...values };
101
+ },
102
+ subscribe: (callback) => {
103
+ subscribers.add(callback);
104
+ return () => {
105
+ subscribers.delete(callback);
106
+ if (subscribers.size === 0) cancelInFlight();
107
+ };
108
+ },
109
+ clear: async () => {
110
+ cache = void 0;
111
+ lastFetchAt = 0;
112
+ }
113
+ };
114
+ }
115
+ async function runWithRetry(op, signal, retry, retryDelay) {
116
+ let attempt = 0;
117
+ let lastError;
118
+ while (attempt <= RETRY_CAP) {
119
+ if (signal.aborted) throw new DOMException("aborted", "AbortError");
120
+ try {
121
+ return await op(signal);
122
+ } catch (err) {
123
+ lastError = err;
124
+ if (signal.aborted) throw err;
125
+ const shouldRetry = typeof retry === "number" ? attempt < retry : retry(attempt, err) && attempt < RETRY_CAP;
126
+ if (!shouldRetry) throw err;
127
+ const delay = Math.min(retryDelay(attempt), MAX_BACKOFF_MS);
128
+ await sleep(delay, signal);
129
+ attempt++;
130
+ }
131
+ }
132
+ throw lastError;
133
+ }
134
+ function defaultBackoff(attempt) {
135
+ return Math.min(100 * 2 ** attempt, MAX_BACKOFF_MS);
136
+ }
137
+ function sleep(ms, signal) {
138
+ return new Promise((resolve, reject) => {
139
+ if (signal.aborted) {
140
+ reject(new DOMException("aborted", "AbortError"));
141
+ return;
142
+ }
143
+ const timer = setTimeout(() => {
144
+ signal.removeEventListener("abort", onAbort);
145
+ resolve();
146
+ }, ms);
147
+ const onAbort = () => {
148
+ clearTimeout(timer);
149
+ reject(new DOMException("aborted", "AbortError"));
150
+ };
151
+ signal.addEventListener("abort", onAbort, { once: true });
152
+ });
153
+ }
154
+ // Annotate the CommonJS export names for ESM import in node:
155
+ 0 && (module.exports = {
156
+ serverStorage
157
+ });
158
+ //# sourceMappingURL=server.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/storage/server/index.ts"],"sourcesContent":["import type { ParamsStorage } from '../../storage'\n\nexport interface ServerStorageOptions<T> {\n /**\n * Async fetch; returns the latest server values or undefined. Closure-bound\n * at factory time. Receives an `AbortSignal` so the consumer's HTTP client\n * can short-circuit when the store is disposed mid-flight.\n */\n read: (signal: AbortSignal) => Promise<Partial<T> | undefined>\n\n /**\n * Async write; throws on failure. The engine catches the throw and silently\n * falls back to in-memory state — the standard storage error contract.\n */\n write: (values: Partial<T>) => Promise<void>\n\n /**\n * Stale-while-revalidate window in ms. When > 0, `readAsync` returns the\n * cached snapshot immediately and revalidates in the background after this\n * many ms have elapsed since the last successful read.\n *\n * Default: 0 (no SWR — every readAsync hits the wire).\n */\n staleTime?: number\n\n /**\n * Retry policy. Number of retries on read/write failure, OR a predicate\n * receiving `(attempt, error)` returning `true` to retry. Default: 3.\n * Capped at 10 internally regardless of predicate behavior.\n */\n retry?: number | ((attempt: number, error: unknown) => boolean)\n\n /**\n * Backoff delay (ms) for the Nth retry (0-indexed: attempt 0 = first retry).\n * Default: exponential `100 * 2^attempt`, capped at 5000.\n */\n retryDelay?: (attempt: number) => number\n\n /** Diagnostics name. Default: 'serverStorage'. */\n name?: string\n}\n\nconst RETRY_CAP = 10\nconst DEFAULT_RETRY = 3\nconst MAX_BACKOFF_MS = 5000\n\n/**\n * Server-state backed storage. Pair an async `read`/`write` adapter (your\n * HTTP client of choice) with built-in retry, AbortController cancellation,\n * and optional stale-while-revalidate semantics.\n *\n * Use cases:\n * - User-account-tied app config (theme + locale stored on the server).\n * - Saved filter views, pinned dashboards, etc.\n * - Anything that should round-trip through your API on every change.\n *\n * For high-frequency state (filters, search), prefer `urlStorage`. Server\n * storage shines when the values must persist across devices.\n *\n * Cancellation: when the params store disposes, the subscribe cleanup runs\n * and aborts any in-flight `readAsync` via the signal threaded into the\n * consumer's `read()` adapter. Wire the signal through your fetch call to\n * get full short-circuit behavior.\n */\nexport function serverStorage<T>(opts: ServerStorageOptions<T>): ParamsStorage<T> {\n const name = opts.name ?? 'serverStorage'\n const retryDelay = opts.retryDelay ?? defaultBackoff\n let cache: Partial<T> | undefined\n let lastFetchAt = 0\n const controllers = new Set<AbortController>()\n const subscribers = new Set<(values: Partial<T>) => void>()\n let revalidateTimer: ReturnType<typeof setTimeout> | undefined\n\n const cancelInFlight = (): void => {\n for (const c of controllers) c.abort()\n controllers.clear()\n if (revalidateTimer !== undefined) {\n clearTimeout(revalidateTimer)\n revalidateTimer = undefined\n }\n }\n\n const performRead = async (): Promise<Partial<T> | undefined> => {\n const controller = new AbortController()\n controllers.add(controller)\n try {\n const values = await runWithRetry(\n (signal) => opts.read(signal),\n controller.signal,\n opts.retry ?? DEFAULT_RETRY,\n retryDelay,\n )\n if (controller.signal.aborted) return undefined\n if (values !== undefined) {\n cache = values\n lastFetchAt = Date.now()\n for (const sub of subscribers) sub(values)\n }\n return values ?? undefined\n } finally {\n controllers.delete(controller)\n }\n }\n\n const scheduleRevalidate = (delayMs: number): void => {\n if (revalidateTimer !== undefined) return\n revalidateTimer = setTimeout(() => {\n revalidateTimer = undefined\n void performRead()\n }, delayMs)\n }\n\n return {\n name,\n clientOnly: false,\n\n // Sync read returns the cached snapshot. Returns undefined until the\n // first successful readAsync — the engine then falls back to defaults.\n read: () => cache,\n\n // Async read with retry + cancellation + optional SWR.\n readAsync: async () => {\n const staleTime = opts.staleTime ?? 0\n const elapsed = Date.now() - lastFetchAt\n // SWR fast path: cache is fresh, return it without hitting the wire.\n if (staleTime > 0 && cache !== undefined && elapsed < staleTime) {\n return cache\n }\n // SWR background path: cache is stale but present — return it,\n // schedule a background revalidation.\n if (staleTime > 0 && cache !== undefined && elapsed >= staleTime) {\n scheduleRevalidate(0)\n return cache\n }\n // Cold path: no cache yet, must wait for the read.\n return performRead()\n },\n\n write: async (values) => {\n await runWithRetry(\n () => opts.write(values),\n // Writes are committal — no engine-driven cancellation.\n new AbortController().signal,\n opts.retry ?? DEFAULT_RETRY,\n retryDelay,\n )\n // Optimistic cache update so subsequent sync reads see the new values\n // without waiting for a server round-trip.\n cache = { ...cache, ...values }\n },\n\n subscribe: (callback) => {\n subscribers.add(callback)\n return () => {\n subscribers.delete(callback)\n // When the LAST subscriber unsubscribes (typical: store disposes),\n // abort in-flight reads + cancel any pending revalidation.\n if (subscribers.size === 0) cancelInFlight()\n }\n },\n\n clear: async () => {\n // Reset cache; consumers can choose to also call write({}) to wipe\n // the server state — that's a higher-level decision.\n cache = undefined\n lastFetchAt = 0\n },\n }\n}\n\n/**\n * Run an async operation with retry + abort. The signal short-circuits both\n * the in-flight call and the inter-attempt backoff sleeps.\n */\nasync function runWithRetry<R>(\n op: (signal: AbortSignal) => Promise<R>,\n signal: AbortSignal,\n retry: number | ((attempt: number, error: unknown) => boolean),\n retryDelay: (attempt: number) => number,\n): Promise<R> {\n let attempt = 0\n let lastError: unknown\n while (attempt <= RETRY_CAP) {\n if (signal.aborted) throw new DOMException('aborted', 'AbortError')\n try {\n return await op(signal)\n } catch (err) {\n lastError = err\n if (signal.aborted) throw err\n const shouldRetry =\n typeof retry === 'number' ? attempt < retry : retry(attempt, err) && attempt < RETRY_CAP\n if (!shouldRetry) throw err\n const delay = Math.min(retryDelay(attempt), MAX_BACKOFF_MS)\n await sleep(delay, signal)\n attempt++\n }\n }\n throw lastError\n}\n\nfunction defaultBackoff(attempt: number): number {\n return Math.min(100 * 2 ** attempt, MAX_BACKOFF_MS)\n}\n\nfunction sleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal.aborted) {\n reject(new DOMException('aborted', 'AbortError'))\n return\n }\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n const onAbort = (): void => {\n clearTimeout(timer)\n reject(new DOMException('aborted', 'AbortError'))\n }\n signal.addEventListener('abort', onAbort, { once: true })\n })\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,57 @@
1
+ import { P as ParamsStorage } from '../storage-DBLIRR-4.cjs';
2
+
3
+ interface ServerStorageOptions<T> {
4
+ /**
5
+ * Async fetch; returns the latest server values or undefined. Closure-bound
6
+ * at factory time. Receives an `AbortSignal` so the consumer's HTTP client
7
+ * can short-circuit when the store is disposed mid-flight.
8
+ */
9
+ read: (signal: AbortSignal) => Promise<Partial<T> | undefined>;
10
+ /**
11
+ * Async write; throws on failure. The engine catches the throw and silently
12
+ * falls back to in-memory state — the standard storage error contract.
13
+ */
14
+ write: (values: Partial<T>) => Promise<void>;
15
+ /**
16
+ * Stale-while-revalidate window in ms. When > 0, `readAsync` returns the
17
+ * cached snapshot immediately and revalidates in the background after this
18
+ * many ms have elapsed since the last successful read.
19
+ *
20
+ * Default: 0 (no SWR — every readAsync hits the wire).
21
+ */
22
+ staleTime?: number;
23
+ /**
24
+ * Retry policy. Number of retries on read/write failure, OR a predicate
25
+ * receiving `(attempt, error)` returning `true` to retry. Default: 3.
26
+ * Capped at 10 internally regardless of predicate behavior.
27
+ */
28
+ retry?: number | ((attempt: number, error: unknown) => boolean);
29
+ /**
30
+ * Backoff delay (ms) for the Nth retry (0-indexed: attempt 0 = first retry).
31
+ * Default: exponential `100 * 2^attempt`, capped at 5000.
32
+ */
33
+ retryDelay?: (attempt: number) => number;
34
+ /** Diagnostics name. Default: 'serverStorage'. */
35
+ name?: string;
36
+ }
37
+ /**
38
+ * Server-state backed storage. Pair an async `read`/`write` adapter (your
39
+ * HTTP client of choice) with built-in retry, AbortController cancellation,
40
+ * and optional stale-while-revalidate semantics.
41
+ *
42
+ * Use cases:
43
+ * - User-account-tied app config (theme + locale stored on the server).
44
+ * - Saved filter views, pinned dashboards, etc.
45
+ * - Anything that should round-trip through your API on every change.
46
+ *
47
+ * For high-frequency state (filters, search), prefer `urlStorage`. Server
48
+ * storage shines when the values must persist across devices.
49
+ *
50
+ * Cancellation: when the params store disposes, the subscribe cleanup runs
51
+ * and aborts any in-flight `readAsync` via the signal threaded into the
52
+ * consumer's `read()` adapter. Wire the signal through your fetch call to
53
+ * get full short-circuit behavior.
54
+ */
55
+ declare function serverStorage<T>(opts: ServerStorageOptions<T>): ParamsStorage<T>;
56
+
57
+ export { type ServerStorageOptions, serverStorage };
@@ -0,0 +1,57 @@
1
+ import { P as ParamsStorage } from '../storage-DBLIRR-4.js';
2
+
3
+ interface ServerStorageOptions<T> {
4
+ /**
5
+ * Async fetch; returns the latest server values or undefined. Closure-bound
6
+ * at factory time. Receives an `AbortSignal` so the consumer's HTTP client
7
+ * can short-circuit when the store is disposed mid-flight.
8
+ */
9
+ read: (signal: AbortSignal) => Promise<Partial<T> | undefined>;
10
+ /**
11
+ * Async write; throws on failure. The engine catches the throw and silently
12
+ * falls back to in-memory state — the standard storage error contract.
13
+ */
14
+ write: (values: Partial<T>) => Promise<void>;
15
+ /**
16
+ * Stale-while-revalidate window in ms. When > 0, `readAsync` returns the
17
+ * cached snapshot immediately and revalidates in the background after this
18
+ * many ms have elapsed since the last successful read.
19
+ *
20
+ * Default: 0 (no SWR — every readAsync hits the wire).
21
+ */
22
+ staleTime?: number;
23
+ /**
24
+ * Retry policy. Number of retries on read/write failure, OR a predicate
25
+ * receiving `(attempt, error)` returning `true` to retry. Default: 3.
26
+ * Capped at 10 internally regardless of predicate behavior.
27
+ */
28
+ retry?: number | ((attempt: number, error: unknown) => boolean);
29
+ /**
30
+ * Backoff delay (ms) for the Nth retry (0-indexed: attempt 0 = first retry).
31
+ * Default: exponential `100 * 2^attempt`, capped at 5000.
32
+ */
33
+ retryDelay?: (attempt: number) => number;
34
+ /** Diagnostics name. Default: 'serverStorage'. */
35
+ name?: string;
36
+ }
37
+ /**
38
+ * Server-state backed storage. Pair an async `read`/`write` adapter (your
39
+ * HTTP client of choice) with built-in retry, AbortController cancellation,
40
+ * and optional stale-while-revalidate semantics.
41
+ *
42
+ * Use cases:
43
+ * - User-account-tied app config (theme + locale stored on the server).
44
+ * - Saved filter views, pinned dashboards, etc.
45
+ * - Anything that should round-trip through your API on every change.
46
+ *
47
+ * For high-frequency state (filters, search), prefer `urlStorage`. Server
48
+ * storage shines when the values must persist across devices.
49
+ *
50
+ * Cancellation: when the params store disposes, the subscribe cleanup runs
51
+ * and aborts any in-flight `readAsync` via the signal threaded into the
52
+ * consumer's `read()` adapter. Wire the signal through your fetch call to
53
+ * get full short-circuit behavior.
54
+ */
55
+ declare function serverStorage<T>(opts: ServerStorageOptions<T>): ParamsStorage<T>;
56
+
57
+ export { type ServerStorageOptions, serverStorage };