@choksheak/react-utils 0.3.6 → 0.3.7

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 (54) hide show
  1. package/NoSSR.cjs +37 -0
  2. package/NoSSR.d.mts +24 -0
  3. package/NoSSR.d.ts +20 -0
  4. package/NoSSR.min.cjs +2 -0
  5. package/NoSSR.min.cjs.map +1 -0
  6. package/NoSSR.min.mjs +2 -0
  7. package/NoSSR.min.mjs.map +1 -0
  8. package/NoSSR.mjs +12 -0
  9. package/README.md +10 -1
  10. package/fetcher.cjs +3 -3
  11. package/fetcher.d.mts +5 -4
  12. package/fetcher.d.ts +4 -3
  13. package/fetcher.min.cjs +1 -1
  14. package/fetcher.min.cjs.map +1 -1
  15. package/fetcher.min.mjs +1 -1
  16. package/fetcher.min.mjs.map +1 -1
  17. package/fetcher.mjs +2 -2
  18. package/package.json +21 -3
  19. package/sharedQuery.cjs +461 -487
  20. package/sharedQuery.d.mts +64 -61
  21. package/sharedQuery.d.ts +62 -59
  22. package/sharedQuery.min.cjs +1 -1
  23. package/sharedQuery.min.cjs.map +1 -1
  24. package/sharedQuery.min.mjs +1 -1
  25. package/sharedQuery.min.mjs.map +1 -1
  26. package/sharedQuery.mjs +462 -487
  27. package/sharedState.cjs +200 -199
  28. package/sharedState.d.mts +48 -38
  29. package/sharedState.d.ts +45 -36
  30. package/sharedState.min.cjs +1 -1
  31. package/sharedState.min.cjs.map +1 -1
  32. package/sharedState.min.mjs +1 -1
  33. package/sharedState.min.mjs.map +1 -1
  34. package/sharedState.mjs +201 -199
  35. package/storage.cjs +78 -65
  36. package/storage.d.mts +39 -2
  37. package/storage.d.ts +37 -1
  38. package/storage.min.cjs +1 -1
  39. package/storage.min.cjs.map +1 -1
  40. package/storage.min.mjs +1 -1
  41. package/storage.min.mjs.map +1 -1
  42. package/storage.mjs +76 -65
  43. package/stringify.d.mts +9 -0
  44. package/stringify.d.ts +9 -0
  45. package/stringify.min.cjs.map +1 -1
  46. package/stringify.min.mjs.map +1 -1
  47. package/useDeepMemo.cjs +1 -1
  48. package/useDeepMemo.d.mts +11 -0
  49. package/useDeepMemo.d.ts +11 -0
  50. package/useDeepMemo.min.cjs +1 -1
  51. package/useDeepMemo.min.cjs.map +1 -1
  52. package/useDeepMemo.min.mjs +1 -1
  53. package/useDeepMemo.min.mjs.map +1 -1
  54. package/useDeepMemo.mjs +1 -1
package/storage.d.ts CHANGED
@@ -1,3 +1,14 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * Backing storage implementation for the shared state. Note that this uses the
5
+ * LocalStore and KvStore from package "@choksheak/ts-utils", but is customized
6
+ * to be used for shared states.
7
+ *
8
+ * Normally you will not need to use this module directly, but if you have a
9
+ * need for it, feel free to use it.
10
+ */
11
+ import { Duration } from "@choksheak/ts-utils/duration";
1
12
  import { StorageAdapter } from "@choksheak/ts-utils/storageAdapter";
2
13
  /** List of all available pre-built persistence options. */
3
14
  export type PersistTo = "localStorage" | "indexedDb";
@@ -8,10 +19,11 @@ export type StoreOptions = {
8
19
  /** Storage key to act as a namespace to store the data. */
9
20
  key: string;
10
21
  /** How long to wait before the value is considered expired. */
11
- expiryMs?: number;
22
+ expiryMs?: number | Duration;
12
23
  /** Returns true if the given value supposed to be of type T is valid. */
13
24
  isValid?: (u: unknown) => boolean;
14
25
  };
26
+ export type StoreConstructorArgs = Omit<StoreOptions, "persistTo">;
15
27
  /** Either use a pre-built store, or a custom one you provide. */
16
28
  export type StorageOptions<T> = {
17
29
  /**
@@ -20,4 +32,28 @@ export type StorageOptions<T> = {
20
32
  */
21
33
  store?: StorageAdapter<T> | StoreOptions;
22
34
  };
35
+ /**
36
+ * Convert a StorageOptions<T> config object into an actual storage adapter, or
37
+ * returns null if a storage adapter is not configured.
38
+ */
23
39
  export declare function getStorageAdapter<T>(options: StorageOptions<T> | undefined, defaultStoreExpiryMs: number): StorageAdapter<T> | null;
40
+ /**
41
+ * Create a new SSR-safe local store adapter, which allows users to reuse the
42
+ * same adapter in multiple shared states or shared queries.
43
+ */
44
+ export declare function localStoreAdapter<T>({ key, expiryMs, isValid, }: StoreConstructorArgs): {
45
+ set: (key: string, value: T) => void;
46
+ get: (key: string) => T | undefined;
47
+ delete: (key: string) => void;
48
+ clear: () => void;
49
+ };
50
+ /**
51
+ * Create a new SSR-safe indexed DB KV store adapter, which allows users to
52
+ * reuse the same adapter in multiple shared states or shared queries.
53
+ */
54
+ export declare function kvStoreAdapter<T>({ key, expiryMs, isValid, }: StoreConstructorArgs): {
55
+ set: (key: string, value: T) => Promise<void>;
56
+ get: (key: string) => Promise<T | undefined>;
57
+ delete: (key: string) => Promise<void>;
58
+ clear: () => Promise<void>;
59
+ };
package/storage.min.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var p=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var S=(n,r)=>{for(var e in r)p(n,e,{get:r[e],enumerable:!0})},w=(n,r,e,u)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of T(r))!y.call(n,s)&&s!==e&&p(n,s,{get:()=>r[s],enumerable:!(u=g(r,s))||u.enumerable});return n};var v=n=>w(p({},"__esModule",{value:!0}),n);var x={};S(x,{getStorageAdapter:()=>m});module.exports=v(x);var d=require("@choksheak/ts-utils/kvStore"),c=require("@choksheak/ts-utils/localStore"),a=typeof window>"u";function m(n,r){let{store:e}=n??{};if(!e)return null;if("persistTo"in e&&typeof e.persistTo=="string"&&"key"in e&&typeof e.key=="string"){let u=e.expiryMs||r,s=e.isValid;switch(e.persistTo){case"localStorage":{let o=new c.LocalStore(e.key,{defaultExpiryMs:u});return{set:(i,t)=>{a||o.set(i,t)},get:i=>{if(a)return;let t=o.get(i);if(s&&!s(t)){console.warn(`localStorage adapter: Auto-discard invalid value for ${i}: ${JSON.stringify(t)}`),o.delete(i);return}return t},delete:i=>{a||o.delete(i)},clear:()=>{a||o.clear()}}}case"indexedDb":{let o=e.key+":",i=e.isValid;return{set:async(t,l)=>{a||await d.kvStore.set(o+t,l,u)},get:async t=>{if(a)return;let l=o+t,f=await d.kvStore.get(l);if(i&&!i(f)){console.warn(`indexedDb adapter: Auto-discard invalid value for ${t}: ${JSON.stringify(f)}`),await d.kvStore.delete(l);return}return f},delete:async t=>{a||await d.kvStore.delete(o+t)},clear:async()=>{a||await d.kvStore.clear()}}}default:throw e.persistTo,new Error(`Unknown store.adapter ${e.persistTo}`)}}return e}0&&(module.exports={getStorageAdapter});
1
+ "use strict";var u=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var T=Object.prototype.hasOwnProperty;var S=(n,r)=>{for(var t in r)u(n,t,{get:r[t],enumerable:!0})},y=(n,r,t,o)=>{if(r&&typeof r=="object"||typeof r=="function")for(let e of g(r))!T.call(n,e)&&e!==t&&u(n,e,{get:()=>r[e],enumerable:!(o=l(r,e))||o.enumerable});return n};var m=n=>y(u({},"__esModule",{value:!0}),n);var x={};S(x,{getStorageAdapter:()=>v,kvStoreAdapter:()=>c,localStoreAdapter:()=>f});module.exports=m(x);var a=require("@choksheak/ts-utils/kvStore"),p=require("@choksheak/ts-utils/localStore"),s=typeof window>"u";function v(n,r){let{store:t}=n??{};if(!t)return null;if("persistTo"in t&&typeof t.persistTo=="string"&&"key"in t&&typeof t.key=="string"){let o=t.expiryMs||r,e={...t,expiryMs:o};switch(t.persistTo){case"localStorage":return f(e);case"indexedDb":return c(e);default:throw t.persistTo,new Error(`Unknown store.adapter ${t.persistTo}`)}}return t}function f({key:n,expiryMs:r,isValid:t}){let o=(0,p.createLocalStore)(n,{defaultExpiryMs:r});return{set:(e,i)=>{s||o.set(e,i)},get:e=>{if(s)return;let i=o.get(e);if(t&&!t(i)){console.warn(`localStorage adapter: Auto-discard invalid value for ${e}: ${JSON.stringify(i)}`),o.delete(e);return}return i},delete:e=>{s||o.delete(e)},clear:()=>{s||o.clear()}}}function c({key:n,expiryMs:r,isValid:t}){let o=n+":";return{set:async(e,i)=>{s||await a.kvStore.set(o+e,i,r)},get:async e=>{if(s)return;let i=o+e,d=await a.kvStore.get(i);if(t&&!t(d)){console.warn(`indexedDb adapter: Auto-discard invalid value for ${e}: ${JSON.stringify(d)}`),await a.kvStore.delete(i);return}return d},delete:async e=>{s||await a.kvStore.delete(o+e)},clear:async()=>{s||await a.kvStore.clear()}}}0&&(module.exports={getStorageAdapter,kvStoreAdapter,localStoreAdapter});
2
2
  //# sourceMappingURL=storage.min.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/storage.ts"],"sourcesContent":["import { kvStore } from \"@choksheak/ts-utils/kvStore\";\nimport { LocalStore } from \"@choksheak/ts-utils/localStore\";\nimport { StorageAdapter } from \"@choksheak/ts-utils/storageAdapter\";\n\n/** List of all available pre-built persistence options. */\nexport type PersistTo = \"localStorage\" | \"indexedDb\";\n\n/** Options to configure a pre-built store adapter. */\nexport type StoreOptions = {\n /** Choose which pre-built store adapter to use. */\n persistTo: PersistTo;\n\n /** Storage key to act as a namespace to store the data. */\n key: string;\n\n /** How long to wait before the value is considered expired. */\n expiryMs?: number;\n\n /** Returns true if the given value supposed to be of type T is valid. */\n isValid?: (u: unknown) => boolean;\n};\n\n/** Either use a pre-built store, or a custom one you provide. */\nexport type StorageOptions<T> = {\n /**\n * You can either specify the storage adapter directly to use a custom\n * store, or specify the properties to use the pre-built ones.\n */\n store?: StorageAdapter<T> | StoreOptions;\n};\n\n// In SSR (Server-Side Rendering) mode, we never want to use our storage\n// adapters for anything.\nconst IS_NOT_BROWSER = typeof window === \"undefined\";\n\nexport function getStorageAdapter<T>(\n options: StorageOptions<T> | undefined,\n defaultStoreExpiryMs: number,\n): StorageAdapter<T> | null {\n const { store } = options ?? {};\n\n if (!store) {\n return null;\n }\n\n if (\n \"persistTo\" in store &&\n typeof store.persistTo === \"string\" &&\n \"key\" in store &&\n typeof store.key === \"string\"\n ) {\n const expiryMs = store.expiryMs || defaultStoreExpiryMs;\n const isValid = store.isValid;\n\n switch (store.persistTo) {\n case \"localStorage\": {\n const adapter = new LocalStore(store.key, {\n defaultExpiryMs: expiryMs,\n });\n\n // Handle SSR.\n return {\n set: (key: string, value: T): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n // Also apply the custom expiryMs on every item in this store.\n adapter.set(key, value);\n },\n get: (key: string): T | undefined => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const value = adapter.get<T>(key);\n\n if (isValid && !isValid(value)) {\n console.warn(\n `localStorage adapter: Auto-discard invalid value for ${key}: ${JSON.stringify(value)}`,\n );\n adapter.delete(key);\n return undefined;\n }\n\n return value;\n },\n delete: (key: string): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n adapter.delete(key);\n },\n clear: (): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n adapter.clear();\n },\n };\n }\n\n case \"indexedDb\": {\n // Use the key prefix as a unique namespace for this store.\n const keyPrefix = store.key + \":\";\n const isValid = store.isValid;\n\n // Prefix all keys using `keyPrefix` so that we can keep all data in\n // the same store in the same DB. If we keep the data in different\n // DB stores, then GC will not be able to clean up abandoned stores.\n return {\n set: async (key: string, value: T): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n // Also apply the custom expiryMs on every item in this store.\n await kvStore.set(keyPrefix + key, value, expiryMs);\n },\n get: async (key: string): Promise<T | undefined> => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const fullKey = keyPrefix + key;\n const value = await kvStore.get<T>(fullKey);\n\n if (isValid && !isValid(value)) {\n console.warn(\n `indexedDb adapter: Auto-discard invalid value for ${key}: ${JSON.stringify(value)}`,\n );\n await kvStore.delete(fullKey);\n return undefined;\n }\n\n return value;\n },\n delete: async (key: string): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n await kvStore.delete(keyPrefix + key);\n },\n clear: async (): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n await kvStore.clear();\n },\n };\n }\n\n default:\n store.persistTo satisfies never;\n throw new Error(`Unknown store.adapter ${store.persistTo}`);\n }\n }\n\n return store as StorageAdapter<T>;\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,uBAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAAwB,uCACxBC,EAA2B,0CAgCrBC,EAAiB,OAAO,OAAW,IAElC,SAASJ,EACdK,EACAC,EAC0B,CAC1B,GAAM,CAAE,MAAAC,CAAM,EAAIF,GAAW,CAAC,EAE9B,GAAI,CAACE,EACH,OAAO,KAGT,GACE,cAAeA,GACf,OAAOA,EAAM,WAAc,UAC3B,QAASA,GACT,OAAOA,EAAM,KAAQ,SACrB,CACA,IAAMC,EAAWD,EAAM,UAAYD,EAC7BG,EAAUF,EAAM,QAEtB,OAAQA,EAAM,UAAW,CACvB,IAAK,eAAgB,CACnB,IAAMG,EAAU,IAAI,aAAWH,EAAM,IAAK,CACxC,gBAAiBC,CACnB,CAAC,EAGD,MAAO,CACL,IAAK,CAACG,EAAaC,IAAmB,CAChCR,GAGJM,EAAQ,IAAIC,EAAKC,CAAK,CACxB,EACA,IAAMD,GAA+B,CACnC,GAAIP,EAAgB,OAEpB,IAAMQ,EAAQF,EAAQ,IAAOC,CAAG,EAEhC,GAAIF,GAAW,CAACA,EAAQG,CAAK,EAAG,CAC9B,QAAQ,KACN,wDAAwDD,CAAG,KAAK,KAAK,UAAUC,CAAK,CAAC,EACvF,EACAF,EAAQ,OAAOC,CAAG,EAClB,MACF,CAEA,OAAOC,CACT,EACA,OAASD,GAAsB,CACzBP,GAEJM,EAAQ,OAAOC,CAAG,CACpB,EACA,MAAO,IAAY,CACbP,GAEJM,EAAQ,MAAM,CAChB,CACF,CACF,CAEA,IAAK,YAAa,CAEhB,IAAMG,EAAYN,EAAM,IAAM,IACxBE,EAAUF,EAAM,QAKtB,MAAO,CACL,IAAK,MAAOI,EAAaC,IAA4B,CAC/CR,GAGJ,MAAM,UAAQ,IAAIS,EAAYF,EAAKC,EAAOJ,CAAQ,CACpD,EACA,IAAK,MAAOG,GAAwC,CAClD,GAAIP,EAAgB,OAEpB,IAAMU,EAAUD,EAAYF,EACtBC,EAAQ,MAAM,UAAQ,IAAOE,CAAO,EAE1C,GAAIL,GAAW,CAACA,EAAQG,CAAK,EAAG,CAC9B,QAAQ,KACN,qDAAqDD,CAAG,KAAK,KAAK,UAAUC,CAAK,CAAC,EACpF,EACA,MAAM,UAAQ,OAAOE,CAAO,EAC5B,MACF,CAEA,OAAOF,CACT,EACA,OAAQ,MAAOD,GAA+B,CACxCP,GAEJ,MAAM,UAAQ,OAAOS,EAAYF,CAAG,CACtC,EACA,MAAO,SAA2B,CAC5BP,GAEJ,MAAM,UAAQ,MAAM,CACtB,CACF,CACF,CAEA,QACE,MAAAG,EAAM,UACA,IAAI,MAAM,yBAAyBA,EAAM,SAAS,EAAE,CAC9D,CACF,CAEA,OAAOA,CACT","names":["storage_exports","__export","getStorageAdapter","__toCommonJS","import_kvStore","import_localStore","IS_NOT_BROWSER","options","defaultStoreExpiryMs","store","expiryMs","isValid","adapter","key","value","keyPrefix","fullKey"]}
1
+ {"version":3,"sources":["../src/storage.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * Backing storage implementation for the shared state. Note that this uses the\n * LocalStore and KvStore from package \"@choksheak/ts-utils\", but is customized\n * to be used for shared states.\n *\n * Normally you will not need to use this module directly, but if you have a\n * need for it, feel free to use it.\n */\n\nimport { Duration } from \"@choksheak/ts-utils/duration\";\nimport { kvStore } from \"@choksheak/ts-utils/kvStore\";\nimport { createLocalStore } from \"@choksheak/ts-utils/localStore\";\nimport { StorageAdapter } from \"@choksheak/ts-utils/storageAdapter\";\n\n/** List of all available pre-built persistence options. */\nexport type PersistTo = \"localStorage\" | \"indexedDb\";\n\n/** Options to configure a pre-built store adapter. */\nexport type StoreOptions = {\n /** Choose which pre-built store adapter to use. */\n persistTo: PersistTo;\n\n /** Storage key to act as a namespace to store the data. */\n key: string;\n\n /** How long to wait before the value is considered expired. */\n expiryMs?: number | Duration;\n\n /** Returns true if the given value supposed to be of type T is valid. */\n isValid?: (u: unknown) => boolean;\n};\n\nexport type StoreConstructorArgs = Omit<StoreOptions, \"persistTo\">;\n\n/** Either use a pre-built store, or a custom one you provide. */\nexport type StorageOptions<T> = {\n /**\n * You can either specify the storage adapter directly to use a custom\n * store, or specify the properties to use the pre-built ones.\n */\n store?: StorageAdapter<T> | StoreOptions;\n};\n\n// In SSR (Server-Side Rendering) mode, we never want to use our storage\n// adapters for anything.\nconst IS_NOT_BROWSER = typeof window === \"undefined\";\n\n/**\n * Convert a StorageOptions<T> config object into an actual storage adapter, or\n * returns null if a storage adapter is not configured.\n */\nexport function getStorageAdapter<T>(\n options: StorageOptions<T> | undefined,\n defaultStoreExpiryMs: number,\n): StorageAdapter<T> | null {\n const { store } = options ?? {};\n\n if (!store) {\n return null;\n }\n\n if (\n \"persistTo\" in store &&\n typeof store.persistTo === \"string\" &&\n \"key\" in store &&\n typeof store.key === \"string\"\n ) {\n const expiryMs = store.expiryMs || defaultStoreExpiryMs;\n const config = { ...store, expiryMs };\n\n switch (store.persistTo) {\n case \"localStorage\":\n return localStoreAdapter<T>(config);\n\n case \"indexedDb\":\n return kvStoreAdapter<T>(config);\n\n default:\n store.persistTo satisfies never;\n throw new Error(`Unknown store.adapter ${store.persistTo}`);\n }\n }\n\n return store as StorageAdapter<T>;\n}\n\n/**\n * Create a new SSR-safe local store adapter, which allows users to reuse the\n * same adapter in multiple shared states or shared queries.\n */\nexport function localStoreAdapter<T>({\n key,\n expiryMs,\n isValid,\n}: StoreConstructorArgs) {\n const adapter = createLocalStore(key, { defaultExpiryMs: expiryMs });\n\n return {\n set: (key: string, value: T): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n // Also apply the custom expiryMs on every item in this store.\n adapter.set(key, value);\n },\n\n get: (key: string): T | undefined => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const value = adapter.get<T>(key);\n\n if (isValid && !isValid(value)) {\n console.warn(\n `localStorage adapter: Auto-discard invalid value for ${key}: ${JSON.stringify(value)}`,\n );\n adapter.delete(key);\n return undefined;\n }\n\n return value;\n },\n\n delete: (key: string): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n adapter.delete(key);\n },\n\n clear: (): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n adapter.clear();\n },\n };\n}\n\n/**\n * Create a new SSR-safe indexed DB KV store adapter, which allows users to\n * reuse the same adapter in multiple shared states or shared queries.\n */\nexport function kvStoreAdapter<T>({\n key,\n expiryMs,\n isValid,\n}: StoreConstructorArgs) {\n // Use the key prefix as a unique namespace for this store.\n const keyPrefix = key + \":\";\n\n // Prefix all keys using `keyPrefix` so that we can keep all data in\n // the same store in the same DB. If we keep the data in different\n // DB stores, then GC will not be able to clean up abandoned stores.\n return {\n set: async (key: string, value: T): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n // Also apply the custom expiryMs on every item in this store.\n await kvStore.set(keyPrefix + key, value, expiryMs);\n },\n get: async (key: string): Promise<T | undefined> => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const fullKey = keyPrefix + key;\n const value = await kvStore.get<T>(fullKey);\n\n if (isValid && !isValid(value)) {\n console.warn(\n `indexedDb adapter: Auto-discard invalid value for ${key}: ${JSON.stringify(value)}`,\n );\n await kvStore.delete(fullKey);\n return undefined;\n }\n\n return value;\n },\n delete: async (key: string): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n await kvStore.delete(keyPrefix + key);\n },\n clear: async (): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n await kvStore.clear();\n },\n };\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,uBAAAE,EAAA,mBAAAC,EAAA,sBAAAC,IAAA,eAAAC,EAAAL,GAYA,IAAAM,EAAwB,uCACxBC,EAAiC,0CAkC3BC,EAAiB,OAAO,OAAW,IAMlC,SAASN,EACdO,EACAC,EAC0B,CAC1B,GAAM,CAAE,MAAAC,CAAM,EAAIF,GAAW,CAAC,EAE9B,GAAI,CAACE,EACH,OAAO,KAGT,GACE,cAAeA,GACf,OAAOA,EAAM,WAAc,UAC3B,QAASA,GACT,OAAOA,EAAM,KAAQ,SACrB,CACA,IAAMC,EAAWD,EAAM,UAAYD,EAC7BG,EAAS,CAAE,GAAGF,EAAO,SAAAC,CAAS,EAEpC,OAAQD,EAAM,UAAW,CACvB,IAAK,eACH,OAAOP,EAAqBS,CAAM,EAEpC,IAAK,YACH,OAAOV,EAAkBU,CAAM,EAEjC,QACE,MAAAF,EAAM,UACA,IAAI,MAAM,yBAAyBA,EAAM,SAAS,EAAE,CAC9D,CACF,CAEA,OAAOA,CACT,CAMO,SAASP,EAAqB,CACnC,IAAAU,EACA,SAAAF,EACA,QAAAG,CACF,EAAyB,CACvB,IAAMC,KAAU,oBAAiBF,EAAK,CAAE,gBAAiBF,CAAS,CAAC,EAEnE,MAAO,CACL,IAAK,CAACE,EAAaG,IAAmB,CAChCT,GAGJQ,EAAQ,IAAIF,EAAKG,CAAK,CACxB,EAEA,IAAMH,GAA+B,CACnC,GAAIN,EAAgB,OAEpB,IAAMS,EAAQD,EAAQ,IAAOF,CAAG,EAEhC,GAAIC,GAAW,CAACA,EAAQE,CAAK,EAAG,CAC9B,QAAQ,KACN,wDAAwDH,CAAG,KAAK,KAAK,UAAUG,CAAK,CAAC,EACvF,EACAD,EAAQ,OAAOF,CAAG,EAClB,MACF,CAEA,OAAOG,CACT,EAEA,OAASH,GAAsB,CACzBN,GAEJQ,EAAQ,OAAOF,CAAG,CACpB,EAEA,MAAO,IAAY,CACbN,GAEJQ,EAAQ,MAAM,CAChB,CACF,CACF,CAMO,SAASb,EAAkB,CAChC,IAAAW,EACA,SAAAF,EACA,QAAAG,CACF,EAAyB,CAEvB,IAAMG,EAAYJ,EAAM,IAKxB,MAAO,CACL,IAAK,MAAOA,EAAaG,IAA4B,CAC/CT,GAGJ,MAAM,UAAQ,IAAIU,EAAYJ,EAAKG,EAAOL,CAAQ,CACpD,EACA,IAAK,MAAOE,GAAwC,CAClD,GAAIN,EAAgB,OAEpB,IAAMW,EAAUD,EAAYJ,EACtBG,EAAQ,MAAM,UAAQ,IAAOE,CAAO,EAE1C,GAAIJ,GAAW,CAACA,EAAQE,CAAK,EAAG,CAC9B,QAAQ,KACN,qDAAqDH,CAAG,KAAK,KAAK,UAAUG,CAAK,CAAC,EACpF,EACA,MAAM,UAAQ,OAAOE,CAAO,EAC5B,MACF,CAEA,OAAOF,CACT,EACA,OAAQ,MAAOH,GAA+B,CACxCN,GAEJ,MAAM,UAAQ,OAAOU,EAAYJ,CAAG,CACtC,EACA,MAAO,SAA2B,CAC5BN,GAEJ,MAAM,UAAQ,MAAM,CACtB,CACF,CACF","names":["storage_exports","__export","getStorageAdapter","kvStoreAdapter","localStoreAdapter","__toCommonJS","import_kvStore","import_localStore","IS_NOT_BROWSER","options","defaultStoreExpiryMs","store","expiryMs","config","key","isValid","adapter","value","keyPrefix","fullKey"]}
package/storage.min.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{kvStore as o}from"@choksheak/ts-utils/kvStore";import{LocalStore as p}from"@choksheak/ts-utils/localStore";var n=typeof window>"u";function T(l,f){let{store:e}=l??{};if(!e)return null;if("persistTo"in e&&typeof e.persistTo=="string"&&"key"in e&&typeof e.key=="string"){let d=e.expiryMs||f,u=e.isValid;switch(e.persistTo){case"localStorage":{let i=new p(e.key,{defaultExpiryMs:d});return{set:(r,t)=>{n||i.set(r,t)},get:r=>{if(n)return;let t=i.get(r);if(u&&!u(t)){console.warn(`localStorage adapter: Auto-discard invalid value for ${r}: ${JSON.stringify(t)}`),i.delete(r);return}return t},delete:r=>{n||i.delete(r)},clear:()=>{n||i.clear()}}}case"indexedDb":{let i=e.key+":",r=e.isValid;return{set:async(t,s)=>{n||await o.set(i+t,s,d)},get:async t=>{if(n)return;let s=i+t,a=await o.get(s);if(r&&!r(a)){console.warn(`indexedDb adapter: Auto-discard invalid value for ${t}: ${JSON.stringify(a)}`),await o.delete(s);return}return a},delete:async t=>{n||await o.delete(i+t)},clear:async()=>{n||await o.clear()}}}default:throw e.persistTo,new Error(`Unknown store.adapter ${e.persistTo}`)}}return e}export{T as getStorageAdapter};
1
+ import{kvStore as a}from"@choksheak/ts-utils/kvStore";import{createLocalStore as u}from"@choksheak/ts-utils/localStore";var n=typeof window>"u";function g(i,s){let{store:e}=i??{};if(!e)return null;if("persistTo"in e&&typeof e.persistTo=="string"&&"key"in e&&typeof e.key=="string"){let r=e.expiryMs||s,t={...e,expiryMs:r};switch(e.persistTo){case"localStorage":return p(t);case"indexedDb":return f(t);default:throw e.persistTo,new Error(`Unknown store.adapter ${e.persistTo}`)}}return e}function p({key:i,expiryMs:s,isValid:e}){let r=u(i,{defaultExpiryMs:s});return{set:(t,o)=>{n||r.set(t,o)},get:t=>{if(n)return;let o=r.get(t);if(e&&!e(o)){console.warn(`localStorage adapter: Auto-discard invalid value for ${t}: ${JSON.stringify(o)}`),r.delete(t);return}return o},delete:t=>{n||r.delete(t)},clear:()=>{n||r.clear()}}}function f({key:i,expiryMs:s,isValid:e}){let r=i+":";return{set:async(t,o)=>{n||await a.set(r+t,o,s)},get:async t=>{if(n)return;let o=r+t,d=await a.get(o);if(e&&!e(d)){console.warn(`indexedDb adapter: Auto-discard invalid value for ${t}: ${JSON.stringify(d)}`),await a.delete(o);return}return d},delete:async t=>{n||await a.delete(r+t)},clear:async()=>{n||await a.clear()}}}export{g as getStorageAdapter,f as kvStoreAdapter,p as localStoreAdapter};
2
2
  //# sourceMappingURL=storage.min.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/storage.ts"],"sourcesContent":["import { kvStore } from \"@choksheak/ts-utils/kvStore\";\nimport { LocalStore } from \"@choksheak/ts-utils/localStore\";\nimport { StorageAdapter } from \"@choksheak/ts-utils/storageAdapter\";\n\n/** List of all available pre-built persistence options. */\nexport type PersistTo = \"localStorage\" | \"indexedDb\";\n\n/** Options to configure a pre-built store adapter. */\nexport type StoreOptions = {\n /** Choose which pre-built store adapter to use. */\n persistTo: PersistTo;\n\n /** Storage key to act as a namespace to store the data. */\n key: string;\n\n /** How long to wait before the value is considered expired. */\n expiryMs?: number;\n\n /** Returns true if the given value supposed to be of type T is valid. */\n isValid?: (u: unknown) => boolean;\n};\n\n/** Either use a pre-built store, or a custom one you provide. */\nexport type StorageOptions<T> = {\n /**\n * You can either specify the storage adapter directly to use a custom\n * store, or specify the properties to use the pre-built ones.\n */\n store?: StorageAdapter<T> | StoreOptions;\n};\n\n// In SSR (Server-Side Rendering) mode, we never want to use our storage\n// adapters for anything.\nconst IS_NOT_BROWSER = typeof window === \"undefined\";\n\nexport function getStorageAdapter<T>(\n options: StorageOptions<T> | undefined,\n defaultStoreExpiryMs: number,\n): StorageAdapter<T> | null {\n const { store } = options ?? {};\n\n if (!store) {\n return null;\n }\n\n if (\n \"persistTo\" in store &&\n typeof store.persistTo === \"string\" &&\n \"key\" in store &&\n typeof store.key === \"string\"\n ) {\n const expiryMs = store.expiryMs || defaultStoreExpiryMs;\n const isValid = store.isValid;\n\n switch (store.persistTo) {\n case \"localStorage\": {\n const adapter = new LocalStore(store.key, {\n defaultExpiryMs: expiryMs,\n });\n\n // Handle SSR.\n return {\n set: (key: string, value: T): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n // Also apply the custom expiryMs on every item in this store.\n adapter.set(key, value);\n },\n get: (key: string): T | undefined => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const value = adapter.get<T>(key);\n\n if (isValid && !isValid(value)) {\n console.warn(\n `localStorage adapter: Auto-discard invalid value for ${key}: ${JSON.stringify(value)}`,\n );\n adapter.delete(key);\n return undefined;\n }\n\n return value;\n },\n delete: (key: string): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n adapter.delete(key);\n },\n clear: (): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n adapter.clear();\n },\n };\n }\n\n case \"indexedDb\": {\n // Use the key prefix as a unique namespace for this store.\n const keyPrefix = store.key + \":\";\n const isValid = store.isValid;\n\n // Prefix all keys using `keyPrefix` so that we can keep all data in\n // the same store in the same DB. If we keep the data in different\n // DB stores, then GC will not be able to clean up abandoned stores.\n return {\n set: async (key: string, value: T): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n // Also apply the custom expiryMs on every item in this store.\n await kvStore.set(keyPrefix + key, value, expiryMs);\n },\n get: async (key: string): Promise<T | undefined> => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const fullKey = keyPrefix + key;\n const value = await kvStore.get<T>(fullKey);\n\n if (isValid && !isValid(value)) {\n console.warn(\n `indexedDb adapter: Auto-discard invalid value for ${key}: ${JSON.stringify(value)}`,\n );\n await kvStore.delete(fullKey);\n return undefined;\n }\n\n return value;\n },\n delete: async (key: string): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n await kvStore.delete(keyPrefix + key);\n },\n clear: async (): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n await kvStore.clear();\n },\n };\n }\n\n default:\n store.persistTo satisfies never;\n throw new Error(`Unknown store.adapter ${store.persistTo}`);\n }\n }\n\n return store as StorageAdapter<T>;\n}\n"],"mappings":"AAAA,OAAS,WAAAA,MAAe,8BACxB,OAAS,cAAAC,MAAkB,iCAgC3B,IAAMC,EAAiB,OAAO,OAAW,IAElC,SAASC,EACdC,EACAC,EAC0B,CAC1B,GAAM,CAAE,MAAAC,CAAM,EAAIF,GAAW,CAAC,EAE9B,GAAI,CAACE,EACH,OAAO,KAGT,GACE,cAAeA,GACf,OAAOA,EAAM,WAAc,UAC3B,QAASA,GACT,OAAOA,EAAM,KAAQ,SACrB,CACA,IAAMC,EAAWD,EAAM,UAAYD,EAC7BG,EAAUF,EAAM,QAEtB,OAAQA,EAAM,UAAW,CACvB,IAAK,eAAgB,CACnB,IAAMG,EAAU,IAAIR,EAAWK,EAAM,IAAK,CACxC,gBAAiBC,CACnB,CAAC,EAGD,MAAO,CACL,IAAK,CAACG,EAAaC,IAAmB,CAChCT,GAGJO,EAAQ,IAAIC,EAAKC,CAAK,CACxB,EACA,IAAMD,GAA+B,CACnC,GAAIR,EAAgB,OAEpB,IAAMS,EAAQF,EAAQ,IAAOC,CAAG,EAEhC,GAAIF,GAAW,CAACA,EAAQG,CAAK,EAAG,CAC9B,QAAQ,KACN,wDAAwDD,CAAG,KAAK,KAAK,UAAUC,CAAK,CAAC,EACvF,EACAF,EAAQ,OAAOC,CAAG,EAClB,MACF,CAEA,OAAOC,CACT,EACA,OAASD,GAAsB,CACzBR,GAEJO,EAAQ,OAAOC,CAAG,CACpB,EACA,MAAO,IAAY,CACbR,GAEJO,EAAQ,MAAM,CAChB,CACF,CACF,CAEA,IAAK,YAAa,CAEhB,IAAMG,EAAYN,EAAM,IAAM,IACxBE,EAAUF,EAAM,QAKtB,MAAO,CACL,IAAK,MAAOI,EAAaC,IAA4B,CAC/CT,GAGJ,MAAMF,EAAQ,IAAIY,EAAYF,EAAKC,EAAOJ,CAAQ,CACpD,EACA,IAAK,MAAOG,GAAwC,CAClD,GAAIR,EAAgB,OAEpB,IAAMW,EAAUD,EAAYF,EACtBC,EAAQ,MAAMX,EAAQ,IAAOa,CAAO,EAE1C,GAAIL,GAAW,CAACA,EAAQG,CAAK,EAAG,CAC9B,QAAQ,KACN,qDAAqDD,CAAG,KAAK,KAAK,UAAUC,CAAK,CAAC,EACpF,EACA,MAAMX,EAAQ,OAAOa,CAAO,EAC5B,MACF,CAEA,OAAOF,CACT,EACA,OAAQ,MAAOD,GAA+B,CACxCR,GAEJ,MAAMF,EAAQ,OAAOY,EAAYF,CAAG,CACtC,EACA,MAAO,SAA2B,CAC5BR,GAEJ,MAAMF,EAAQ,MAAM,CACtB,CACF,CACF,CAEA,QACE,MAAAM,EAAM,UACA,IAAI,MAAM,yBAAyBA,EAAM,SAAS,EAAE,CAC9D,CACF,CAEA,OAAOA,CACT","names":["kvStore","LocalStore","IS_NOT_BROWSER","getStorageAdapter","options","defaultStoreExpiryMs","store","expiryMs","isValid","adapter","key","value","keyPrefix","fullKey"]}
1
+ {"version":3,"sources":["../src/storage.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * Backing storage implementation for the shared state. Note that this uses the\n * LocalStore and KvStore from package \"@choksheak/ts-utils\", but is customized\n * to be used for shared states.\n *\n * Normally you will not need to use this module directly, but if you have a\n * need for it, feel free to use it.\n */\n\nimport { Duration } from \"@choksheak/ts-utils/duration\";\nimport { kvStore } from \"@choksheak/ts-utils/kvStore\";\nimport { createLocalStore } from \"@choksheak/ts-utils/localStore\";\nimport { StorageAdapter } from \"@choksheak/ts-utils/storageAdapter\";\n\n/** List of all available pre-built persistence options. */\nexport type PersistTo = \"localStorage\" | \"indexedDb\";\n\n/** Options to configure a pre-built store adapter. */\nexport type StoreOptions = {\n /** Choose which pre-built store adapter to use. */\n persistTo: PersistTo;\n\n /** Storage key to act as a namespace to store the data. */\n key: string;\n\n /** How long to wait before the value is considered expired. */\n expiryMs?: number | Duration;\n\n /** Returns true if the given value supposed to be of type T is valid. */\n isValid?: (u: unknown) => boolean;\n};\n\nexport type StoreConstructorArgs = Omit<StoreOptions, \"persistTo\">;\n\n/** Either use a pre-built store, or a custom one you provide. */\nexport type StorageOptions<T> = {\n /**\n * You can either specify the storage adapter directly to use a custom\n * store, or specify the properties to use the pre-built ones.\n */\n store?: StorageAdapter<T> | StoreOptions;\n};\n\n// In SSR (Server-Side Rendering) mode, we never want to use our storage\n// adapters for anything.\nconst IS_NOT_BROWSER = typeof window === \"undefined\";\n\n/**\n * Convert a StorageOptions<T> config object into an actual storage adapter, or\n * returns null if a storage adapter is not configured.\n */\nexport function getStorageAdapter<T>(\n options: StorageOptions<T> | undefined,\n defaultStoreExpiryMs: number,\n): StorageAdapter<T> | null {\n const { store } = options ?? {};\n\n if (!store) {\n return null;\n }\n\n if (\n \"persistTo\" in store &&\n typeof store.persistTo === \"string\" &&\n \"key\" in store &&\n typeof store.key === \"string\"\n ) {\n const expiryMs = store.expiryMs || defaultStoreExpiryMs;\n const config = { ...store, expiryMs };\n\n switch (store.persistTo) {\n case \"localStorage\":\n return localStoreAdapter<T>(config);\n\n case \"indexedDb\":\n return kvStoreAdapter<T>(config);\n\n default:\n store.persistTo satisfies never;\n throw new Error(`Unknown store.adapter ${store.persistTo}`);\n }\n }\n\n return store as StorageAdapter<T>;\n}\n\n/**\n * Create a new SSR-safe local store adapter, which allows users to reuse the\n * same adapter in multiple shared states or shared queries.\n */\nexport function localStoreAdapter<T>({\n key,\n expiryMs,\n isValid,\n}: StoreConstructorArgs) {\n const adapter = createLocalStore(key, { defaultExpiryMs: expiryMs });\n\n return {\n set: (key: string, value: T): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n // Also apply the custom expiryMs on every item in this store.\n adapter.set(key, value);\n },\n\n get: (key: string): T | undefined => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const value = adapter.get<T>(key);\n\n if (isValid && !isValid(value)) {\n console.warn(\n `localStorage adapter: Auto-discard invalid value for ${key}: ${JSON.stringify(value)}`,\n );\n adapter.delete(key);\n return undefined;\n }\n\n return value;\n },\n\n delete: (key: string): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n adapter.delete(key);\n },\n\n clear: (): void => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n adapter.clear();\n },\n };\n}\n\n/**\n * Create a new SSR-safe indexed DB KV store adapter, which allows users to\n * reuse the same adapter in multiple shared states or shared queries.\n */\nexport function kvStoreAdapter<T>({\n key,\n expiryMs,\n isValid,\n}: StoreConstructorArgs) {\n // Use the key prefix as a unique namespace for this store.\n const keyPrefix = key + \":\";\n\n // Prefix all keys using `keyPrefix` so that we can keep all data in\n // the same store in the same DB. If we keep the data in different\n // DB stores, then GC will not be able to clean up abandoned stores.\n return {\n set: async (key: string, value: T): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n // Also apply the custom expiryMs on every item in this store.\n await kvStore.set(keyPrefix + key, value, expiryMs);\n },\n get: async (key: string): Promise<T | undefined> => {\n if (IS_NOT_BROWSER) return undefined; // handle SSR\n\n const fullKey = keyPrefix + key;\n const value = await kvStore.get<T>(fullKey);\n\n if (isValid && !isValid(value)) {\n console.warn(\n `indexedDb adapter: Auto-discard invalid value for ${key}: ${JSON.stringify(value)}`,\n );\n await kvStore.delete(fullKey);\n return undefined;\n }\n\n return value;\n },\n delete: async (key: string): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n await kvStore.delete(keyPrefix + key);\n },\n clear: async (): Promise<void> => {\n if (IS_NOT_BROWSER) return; // handle SSR\n\n await kvStore.clear();\n },\n };\n}\n"],"mappings":"AAYA,OAAS,WAAAA,MAAe,8BACxB,OAAS,oBAAAC,MAAwB,iCAkCjC,IAAMC,EAAiB,OAAO,OAAW,IAMlC,SAASC,EACdC,EACAC,EAC0B,CAC1B,GAAM,CAAE,MAAAC,CAAM,EAAIF,GAAW,CAAC,EAE9B,GAAI,CAACE,EACH,OAAO,KAGT,GACE,cAAeA,GACf,OAAOA,EAAM,WAAc,UAC3B,QAASA,GACT,OAAOA,EAAM,KAAQ,SACrB,CACA,IAAMC,EAAWD,EAAM,UAAYD,EAC7BG,EAAS,CAAE,GAAGF,EAAO,SAAAC,CAAS,EAEpC,OAAQD,EAAM,UAAW,CACvB,IAAK,eACH,OAAOG,EAAqBD,CAAM,EAEpC,IAAK,YACH,OAAOE,EAAkBF,CAAM,EAEjC,QACE,MAAAF,EAAM,UACA,IAAI,MAAM,yBAAyBA,EAAM,SAAS,EAAE,CAC9D,CACF,CAEA,OAAOA,CACT,CAMO,SAASG,EAAqB,CACnC,IAAAE,EACA,SAAAJ,EACA,QAAAK,CACF,EAAyB,CACvB,IAAMC,EAAUZ,EAAiBU,EAAK,CAAE,gBAAiBJ,CAAS,CAAC,EAEnE,MAAO,CACL,IAAK,CAACI,EAAaG,IAAmB,CAChCZ,GAGJW,EAAQ,IAAIF,EAAKG,CAAK,CACxB,EAEA,IAAMH,GAA+B,CACnC,GAAIT,EAAgB,OAEpB,IAAMY,EAAQD,EAAQ,IAAOF,CAAG,EAEhC,GAAIC,GAAW,CAACA,EAAQE,CAAK,EAAG,CAC9B,QAAQ,KACN,wDAAwDH,CAAG,KAAK,KAAK,UAAUG,CAAK,CAAC,EACvF,EACAD,EAAQ,OAAOF,CAAG,EAClB,MACF,CAEA,OAAOG,CACT,EAEA,OAASH,GAAsB,CACzBT,GAEJW,EAAQ,OAAOF,CAAG,CACpB,EAEA,MAAO,IAAY,CACbT,GAEJW,EAAQ,MAAM,CAChB,CACF,CACF,CAMO,SAASH,EAAkB,CAChC,IAAAC,EACA,SAAAJ,EACA,QAAAK,CACF,EAAyB,CAEvB,IAAMG,EAAYJ,EAAM,IAKxB,MAAO,CACL,IAAK,MAAOA,EAAaG,IAA4B,CAC/CZ,GAGJ,MAAMF,EAAQ,IAAIe,EAAYJ,EAAKG,EAAOP,CAAQ,CACpD,EACA,IAAK,MAAOI,GAAwC,CAClD,GAAIT,EAAgB,OAEpB,IAAMc,EAAUD,EAAYJ,EACtBG,EAAQ,MAAMd,EAAQ,IAAOgB,CAAO,EAE1C,GAAIJ,GAAW,CAACA,EAAQE,CAAK,EAAG,CAC9B,QAAQ,KACN,qDAAqDH,CAAG,KAAK,KAAK,UAAUG,CAAK,CAAC,EACpF,EACA,MAAMd,EAAQ,OAAOgB,CAAO,EAC5B,MACF,CAEA,OAAOF,CACT,EACA,OAAQ,MAAOH,GAA+B,CACxCT,GAEJ,MAAMF,EAAQ,OAAOe,EAAYJ,CAAG,CACtC,EACA,MAAO,SAA2B,CAC5BT,GAEJ,MAAMF,EAAQ,MAAM,CACtB,CACF,CACF","names":["kvStore","createLocalStore","IS_NOT_BROWSER","getStorageAdapter","options","defaultStoreExpiryMs","store","expiryMs","config","localStoreAdapter","kvStoreAdapter","key","isValid","adapter","value","keyPrefix","fullKey"]}
package/storage.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/storage.ts
2
2
  import { kvStore } from "@choksheak/ts-utils/kvStore";
3
- import { LocalStore } from "@choksheak/ts-utils/localStore";
3
+ import { createLocalStore } from "@choksheak/ts-utils/localStore";
4
4
  var IS_NOT_BROWSER = typeof window === "undefined";
5
5
  function getStorageAdapter(options, defaultStoreExpiryMs) {
6
6
  const { store } = options ?? {};
@@ -9,70 +9,12 @@ function getStorageAdapter(options, defaultStoreExpiryMs) {
9
9
  }
10
10
  if ("persistTo" in store && typeof store.persistTo === "string" && "key" in store && typeof store.key === "string") {
11
11
  const expiryMs = store.expiryMs || defaultStoreExpiryMs;
12
- const isValid = store.isValid;
12
+ const config = { ...store, expiryMs };
13
13
  switch (store.persistTo) {
14
- case "localStorage": {
15
- const adapter = new LocalStore(store.key, {
16
- defaultExpiryMs: expiryMs
17
- });
18
- return {
19
- set: (key, value) => {
20
- if (IS_NOT_BROWSER) return;
21
- adapter.set(key, value);
22
- },
23
- get: (key) => {
24
- if (IS_NOT_BROWSER) return void 0;
25
- const value = adapter.get(key);
26
- if (isValid && !isValid(value)) {
27
- console.warn(
28
- `localStorage adapter: Auto-discard invalid value for ${key}: ${JSON.stringify(value)}`
29
- );
30
- adapter.delete(key);
31
- return void 0;
32
- }
33
- return value;
34
- },
35
- delete: (key) => {
36
- if (IS_NOT_BROWSER) return;
37
- adapter.delete(key);
38
- },
39
- clear: () => {
40
- if (IS_NOT_BROWSER) return;
41
- adapter.clear();
42
- }
43
- };
44
- }
45
- case "indexedDb": {
46
- const keyPrefix = store.key + ":";
47
- const isValid2 = store.isValid;
48
- return {
49
- set: async (key, value) => {
50
- if (IS_NOT_BROWSER) return;
51
- await kvStore.set(keyPrefix + key, value, expiryMs);
52
- },
53
- get: async (key) => {
54
- if (IS_NOT_BROWSER) return void 0;
55
- const fullKey = keyPrefix + key;
56
- const value = await kvStore.get(fullKey);
57
- if (isValid2 && !isValid2(value)) {
58
- console.warn(
59
- `indexedDb adapter: Auto-discard invalid value for ${key}: ${JSON.stringify(value)}`
60
- );
61
- await kvStore.delete(fullKey);
62
- return void 0;
63
- }
64
- return value;
65
- },
66
- delete: async (key) => {
67
- if (IS_NOT_BROWSER) return;
68
- await kvStore.delete(keyPrefix + key);
69
- },
70
- clear: async () => {
71
- if (IS_NOT_BROWSER) return;
72
- await kvStore.clear();
73
- }
74
- };
75
- }
14
+ case "localStorage":
15
+ return localStoreAdapter(config);
16
+ case "indexedDb":
17
+ return kvStoreAdapter(config);
76
18
  default:
77
19
  store.persistTo;
78
20
  throw new Error(`Unknown store.adapter ${store.persistTo}`);
@@ -80,6 +22,75 @@ function getStorageAdapter(options, defaultStoreExpiryMs) {
80
22
  }
81
23
  return store;
82
24
  }
25
+ function localStoreAdapter({
26
+ key,
27
+ expiryMs,
28
+ isValid
29
+ }) {
30
+ const adapter = createLocalStore(key, { defaultExpiryMs: expiryMs });
31
+ return {
32
+ set: (key2, value) => {
33
+ if (IS_NOT_BROWSER) return;
34
+ adapter.set(key2, value);
35
+ },
36
+ get: (key2) => {
37
+ if (IS_NOT_BROWSER) return void 0;
38
+ const value = adapter.get(key2);
39
+ if (isValid && !isValid(value)) {
40
+ console.warn(
41
+ `localStorage adapter: Auto-discard invalid value for ${key2}: ${JSON.stringify(value)}`
42
+ );
43
+ adapter.delete(key2);
44
+ return void 0;
45
+ }
46
+ return value;
47
+ },
48
+ delete: (key2) => {
49
+ if (IS_NOT_BROWSER) return;
50
+ adapter.delete(key2);
51
+ },
52
+ clear: () => {
53
+ if (IS_NOT_BROWSER) return;
54
+ adapter.clear();
55
+ }
56
+ };
57
+ }
58
+ function kvStoreAdapter({
59
+ key,
60
+ expiryMs,
61
+ isValid
62
+ }) {
63
+ const keyPrefix = key + ":";
64
+ return {
65
+ set: async (key2, value) => {
66
+ if (IS_NOT_BROWSER) return;
67
+ await kvStore.set(keyPrefix + key2, value, expiryMs);
68
+ },
69
+ get: async (key2) => {
70
+ if (IS_NOT_BROWSER) return void 0;
71
+ const fullKey = keyPrefix + key2;
72
+ const value = await kvStore.get(fullKey);
73
+ if (isValid && !isValid(value)) {
74
+ console.warn(
75
+ `indexedDb adapter: Auto-discard invalid value for ${key2}: ${JSON.stringify(value)}`
76
+ );
77
+ await kvStore.delete(fullKey);
78
+ return void 0;
79
+ }
80
+ return value;
81
+ },
82
+ delete: async (key2) => {
83
+ if (IS_NOT_BROWSER) return;
84
+ await kvStore.delete(keyPrefix + key2);
85
+ },
86
+ clear: async () => {
87
+ if (IS_NOT_BROWSER) return;
88
+ await kvStore.clear();
89
+ }
90
+ };
91
+ }
83
92
  export {
84
- getStorageAdapter
93
+ getStorageAdapter,
94
+ kvStoreAdapter,
95
+ localStoreAdapter
85
96
  };
package/stringify.d.mts CHANGED
@@ -1,3 +1,12 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * Implements special stringify for use in the shared queries. This will likely
5
+ * not be reusable for your own use cases.
6
+ *
7
+ * Normally you will not need to use this module directly, but if you have a
8
+ * need for it, feel free to use it.
9
+ */
1
10
  /**
2
11
  * JSON stringify a value of any type, and returns an unsafe string. The string
3
12
  * is "unsafe" because you might not be able to restore the original object
package/stringify.d.ts CHANGED
@@ -1,3 +1,12 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * Implements special stringify for use in the shared queries. This will likely
5
+ * not be reusable for your own use cases.
6
+ *
7
+ * Normally you will not need to use this module directly, but if you have a
8
+ * need for it, feel free to use it.
9
+ */
1
10
  /**
2
11
  * JSON stringify a value of any type, and returns an unsafe string. The string
3
12
  * is "unsafe" because you might not be able to restore the original object
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stringify.ts"],"sourcesContent":["/**\n * JSON stringify a value of any type, and returns an unsafe string. The string\n * is \"unsafe\" because you might not be able to restore the original object\n * using the serialized JSON. This is specifically used for query key generation\n * and is not suitable for more general uses.\n *\n * Note: The given value should not contain any functions because functions\n * cannot be serialized and deserialized properly.\n */\nexport function stringifyDeterministicForKeys(params: unknown): string {\n const cache = new Set();\n\n return JSON.stringify(params, (_, value) => {\n if (typeof value === \"function\") {\n throw new Error(`Functions should not be passed into query parameters`);\n }\n\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n\n if (cache.has(value)) {\n // Circular reference detected! Return a placeholder string.\n return \"[Circular]\";\n }\n\n cache.add(value);\n\n // Don't crash on circular references, but don't mark the top level object\n // as circular because we want to return as much string as possible.\n if (value !== params) {\n try {\n JSON.stringify(value);\n } catch {\n return \"[Unserializable]\";\n }\n }\n\n return Object.keys(value)\n .sort()\n .reduce(\n (result: Record<string, unknown>, key: string) => {\n result[key] = value[key];\n return result;\n },\n {} as Record<string, unknown>,\n );\n });\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mCAAAE,IAAA,eAAAC,EAAAH,GASO,SAASE,EAA8BE,EAAyB,CACrE,IAAMC,EAAQ,IAAI,IAElB,OAAO,KAAK,UAAUD,EAAQ,CAACE,EAAGC,IAAU,CAC1C,GAAI,OAAOA,GAAU,WACnB,MAAM,IAAI,MAAM,sDAAsD,EAGxE,GAAI,CAACA,GAAS,OAAOA,GAAU,UAAY,MAAM,QAAQA,CAAK,EAC5D,OAAOA,EAGT,GAAIF,EAAM,IAAIE,CAAK,EAEjB,MAAO,aAOT,GAJAF,EAAM,IAAIE,CAAK,EAIXA,IAAUH,EACZ,GAAI,CACF,KAAK,UAAUG,CAAK,CACtB,MAAQ,CACN,MAAO,kBACT,CAGF,OAAO,OAAO,KAAKA,CAAK,EACrB,KAAK,EACL,OACC,CAACC,EAAiCC,KAChCD,EAAOC,CAAG,EAAIF,EAAME,CAAG,EAChBD,GAET,CAAC,CACH,CACJ,CAAC,CACH","names":["stringify_exports","__export","stringifyDeterministicForKeys","__toCommonJS","params","cache","_","value","result","key"]}
1
+ {"version":3,"sources":["../src/stringify.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * Implements special stringify for use in the shared queries. This will likely\n * not be reusable for your own use cases.\n *\n * Normally you will not need to use this module directly, but if you have a\n * need for it, feel free to use it.\n */\n\n/**\n * JSON stringify a value of any type, and returns an unsafe string. The string\n * is \"unsafe\" because you might not be able to restore the original object\n * using the serialized JSON. This is specifically used for query key generation\n * and is not suitable for more general uses.\n *\n * Note: The given value should not contain any functions because functions\n * cannot be serialized and deserialized properly.\n */\nexport function stringifyDeterministicForKeys(params: unknown): string {\n const cache = new Set();\n\n return JSON.stringify(params, (_, value) => {\n if (typeof value === \"function\") {\n throw new Error(`Functions should not be passed into query parameters`);\n }\n\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n\n if (cache.has(value)) {\n // Circular reference detected! Return a placeholder string.\n return \"[Circular]\";\n }\n\n cache.add(value);\n\n // Don't crash on circular references, but don't mark the top level object\n // as circular because we want to return as much string as possible.\n if (value !== params) {\n try {\n JSON.stringify(value);\n } catch {\n return \"[Unserializable]\";\n }\n }\n\n return Object.keys(value)\n .sort()\n .reduce(\n (result: Record<string, unknown>, key: string) => {\n result[key] = value[key];\n return result;\n },\n {} as Record<string, unknown>,\n );\n });\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mCAAAE,IAAA,eAAAC,EAAAH,GAmBO,SAASE,EAA8BE,EAAyB,CACrE,IAAMC,EAAQ,IAAI,IAElB,OAAO,KAAK,UAAUD,EAAQ,CAACE,EAAGC,IAAU,CAC1C,GAAI,OAAOA,GAAU,WACnB,MAAM,IAAI,MAAM,sDAAsD,EAGxE,GAAI,CAACA,GAAS,OAAOA,GAAU,UAAY,MAAM,QAAQA,CAAK,EAC5D,OAAOA,EAGT,GAAIF,EAAM,IAAIE,CAAK,EAEjB,MAAO,aAOT,GAJAF,EAAM,IAAIE,CAAK,EAIXA,IAAUH,EACZ,GAAI,CACF,KAAK,UAAUG,CAAK,CACtB,MAAQ,CACN,MAAO,kBACT,CAGF,OAAO,OAAO,KAAKA,CAAK,EACrB,KAAK,EACL,OACC,CAACC,EAAiCC,KAChCD,EAAOC,CAAG,EAAIF,EAAME,CAAG,EAChBD,GAET,CAAC,CACH,CACJ,CAAC,CACH","names":["stringify_exports","__export","stringifyDeterministicForKeys","__toCommonJS","params","cache","_","value","result","key"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stringify.ts"],"sourcesContent":["/**\n * JSON stringify a value of any type, and returns an unsafe string. The string\n * is \"unsafe\" because you might not be able to restore the original object\n * using the serialized JSON. This is specifically used for query key generation\n * and is not suitable for more general uses.\n *\n * Note: The given value should not contain any functions because functions\n * cannot be serialized and deserialized properly.\n */\nexport function stringifyDeterministicForKeys(params: unknown): string {\n const cache = new Set();\n\n return JSON.stringify(params, (_, value) => {\n if (typeof value === \"function\") {\n throw new Error(`Functions should not be passed into query parameters`);\n }\n\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n\n if (cache.has(value)) {\n // Circular reference detected! Return a placeholder string.\n return \"[Circular]\";\n }\n\n cache.add(value);\n\n // Don't crash on circular references, but don't mark the top level object\n // as circular because we want to return as much string as possible.\n if (value !== params) {\n try {\n JSON.stringify(value);\n } catch {\n return \"[Unserializable]\";\n }\n }\n\n return Object.keys(value)\n .sort()\n .reduce(\n (result: Record<string, unknown>, key: string) => {\n result[key] = value[key];\n return result;\n },\n {} as Record<string, unknown>,\n );\n });\n}\n"],"mappings":"AASO,SAASA,EAA8BC,EAAyB,CACrE,IAAMC,EAAQ,IAAI,IAElB,OAAO,KAAK,UAAUD,EAAQ,CAACE,EAAGC,IAAU,CAC1C,GAAI,OAAOA,GAAU,WACnB,MAAM,IAAI,MAAM,sDAAsD,EAGxE,GAAI,CAACA,GAAS,OAAOA,GAAU,UAAY,MAAM,QAAQA,CAAK,EAC5D,OAAOA,EAGT,GAAIF,EAAM,IAAIE,CAAK,EAEjB,MAAO,aAOT,GAJAF,EAAM,IAAIE,CAAK,EAIXA,IAAUH,EACZ,GAAI,CACF,KAAK,UAAUG,CAAK,CACtB,MAAQ,CACN,MAAO,kBACT,CAGF,OAAO,OAAO,KAAKA,CAAK,EACrB,KAAK,EACL,OACC,CAACC,EAAiCC,KAChCD,EAAOC,CAAG,EAAIF,EAAME,CAAG,EAChBD,GAET,CAAC,CACH,CACJ,CAAC,CACH","names":["stringifyDeterministicForKeys","params","cache","_","value","result","key"]}
1
+ {"version":3,"sources":["../src/stringify.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * Implements special stringify for use in the shared queries. This will likely\n * not be reusable for your own use cases.\n *\n * Normally you will not need to use this module directly, but if you have a\n * need for it, feel free to use it.\n */\n\n/**\n * JSON stringify a value of any type, and returns an unsafe string. The string\n * is \"unsafe\" because you might not be able to restore the original object\n * using the serialized JSON. This is specifically used for query key generation\n * and is not suitable for more general uses.\n *\n * Note: The given value should not contain any functions because functions\n * cannot be serialized and deserialized properly.\n */\nexport function stringifyDeterministicForKeys(params: unknown): string {\n const cache = new Set();\n\n return JSON.stringify(params, (_, value) => {\n if (typeof value === \"function\") {\n throw new Error(`Functions should not be passed into query parameters`);\n }\n\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n\n if (cache.has(value)) {\n // Circular reference detected! Return a placeholder string.\n return \"[Circular]\";\n }\n\n cache.add(value);\n\n // Don't crash on circular references, but don't mark the top level object\n // as circular because we want to return as much string as possible.\n if (value !== params) {\n try {\n JSON.stringify(value);\n } catch {\n return \"[Unserializable]\";\n }\n }\n\n return Object.keys(value)\n .sort()\n .reduce(\n (result: Record<string, unknown>, key: string) => {\n result[key] = value[key];\n return result;\n },\n {} as Record<string, unknown>,\n );\n });\n}\n"],"mappings":"AAmBO,SAASA,EAA8BC,EAAyB,CACrE,IAAMC,EAAQ,IAAI,IAElB,OAAO,KAAK,UAAUD,EAAQ,CAACE,EAAGC,IAAU,CAC1C,GAAI,OAAOA,GAAU,WACnB,MAAM,IAAI,MAAM,sDAAsD,EAGxE,GAAI,CAACA,GAAS,OAAOA,GAAU,UAAY,MAAM,QAAQA,CAAK,EAC5D,OAAOA,EAGT,GAAIF,EAAM,IAAIE,CAAK,EAEjB,MAAO,aAOT,GAJAF,EAAM,IAAIE,CAAK,EAIXA,IAAUH,EACZ,GAAI,CACF,KAAK,UAAUG,CAAK,CACtB,MAAQ,CACN,MAAO,kBACT,CAGF,OAAO,OAAO,KAAKA,CAAK,EACrB,KAAK,EACL,OACC,CAACC,EAAiCC,KAChCD,EAAOC,CAAG,EAAIF,EAAME,CAAG,EAChBD,GAET,CAAC,CACH,CACJ,CAAC,CACH","names":["stringifyDeterministicForKeys","params","cache","_","value","result","key"]}
package/useDeepMemo.cjs CHANGED
@@ -38,7 +38,7 @@ var import_react = require("react");
38
38
  function useDeepMemo(value) {
39
39
  const [state, setState] = (0, import_react.useState)(value);
40
40
  return (0, import_react.useMemo)(() => {
41
- if (state === value || (0, import_isEqual.default)(state, value)) {
41
+ if ((0, import_isEqual.default)(state, value)) {
42
42
  return state;
43
43
  }
44
44
  setState(value);
package/useDeepMemo.d.mts CHANGED
@@ -1,3 +1,14 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * Provides a memoized value in React where the value is checked for deep
5
+ * equality. If the value has changed, but is deeply equal to the previous
6
+ * value, then useDeepMemo will return the same reference to the previous
7
+ * value and ignore the latest value.
8
+ *
9
+ * This is mainly used in shared queries to check for changes in the query
10
+ * arguments, but it might be useful for your own use cases.
11
+ */
1
12
  /**
2
13
  * Provides a stable value for T based on deep equality. The deep equality is
3
14
  * determined by the `isEqual()` function in lodash.
package/useDeepMemo.d.ts CHANGED
@@ -1,3 +1,14 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * Provides a memoized value in React where the value is checked for deep
5
+ * equality. If the value has changed, but is deeply equal to the previous
6
+ * value, then useDeepMemo will return the same reference to the previous
7
+ * value and ignore the latest value.
8
+ *
9
+ * This is mainly used in shared queries to check for changes in the query
10
+ * arguments, but it might be useful for your own use cases.
11
+ */
1
12
  /**
2
13
  * Provides a stable value for T based on deep equality. The deep equality is
3
14
  * determined by the `isEqual()` function in lodash.
@@ -1,2 +1,2 @@
1
- "use strict";var p=Object.create;var s=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var c=Object.getPrototypeOf,M=Object.prototype.hasOwnProperty;var S=(t,r)=>{for(var e in r)s(t,e,{get:r[e],enumerable:!0})},i=(t,r,e,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of u(r))!M.call(t,o)&&o!==e&&s(t,o,{get:()=>r[o],enumerable:!(n=T(r,o))||n.enumerable});return t};var q=(t,r,e)=>(e=t!=null?p(c(t)):{},i(r||!t||!t.__esModule?s(e,"default",{value:t,enumerable:!0}):e,t)),x=t=>i(s({},"__esModule",{value:!0}),t);var E={};S(E,{useDeepMemo:()=>D});module.exports=x(E);var f=q(require("lodash/isEqual")),m=require("react");function D(t){let[r,e]=(0,m.useState)(t);return(0,m.useMemo)(()=>r===t||(0,f.default)(r,t)?r:(e(t),t),[r,t])}0&&(module.exports={useDeepMemo});
1
+ "use strict";var p=Object.create;var s=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var c=Object.getPrototypeOf,M=Object.prototype.hasOwnProperty;var S=(t,e)=>{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},i=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of T(e))!M.call(t,o)&&o!==r&&s(t,o,{get:()=>e[o],enumerable:!(n=u(e,o))||n.enumerable});return t};var q=(t,e,r)=>(r=t!=null?p(c(t)):{},i(e||!t||!t.__esModule?s(r,"default",{value:t,enumerable:!0}):r,t)),x=t=>i(s({},"__esModule",{value:!0}),t);var E={};S(E,{useDeepMemo:()=>D});module.exports=x(E);var f=q(require("lodash/isEqual")),m=require("react");function D(t){let[e,r]=(0,m.useState)(t);return(0,m.useMemo)(()=>(0,f.default)(e,t)?e:(r(t),t),[e,t])}0&&(module.exports={useDeepMemo});
2
2
  //# sourceMappingURL=useDeepMemo.min.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/useDeepMemo.ts"],"sourcesContent":["import isEqual from \"lodash/isEqual\";\nimport { useMemo, useState } from \"react\";\n\n/**\n * Provides a stable value for T based on deep equality. The deep equality is\n * determined by the `isEqual()` function in lodash.\n */\nexport function useDeepMemo<T>(value: T): T {\n const [state, setState] = useState<T>(value);\n\n return useMemo(() => {\n if (state === value || isEqual(state, value)) {\n return state;\n }\n\n // We check equality, so this should be safe.\n // eslint-disable-next-line react-hooks/set-state-in-render\n setState(value);\n\n return value;\n }, [state, value]);\n}\n"],"mappings":"0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,iBAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAAoB,6BACpBC,EAAkC,iBAM3B,SAASH,EAAeI,EAAa,CAC1C,GAAM,CAACC,EAAOC,CAAQ,KAAI,YAAYF,CAAK,EAE3C,SAAO,WAAQ,IACTC,IAAUD,MAAS,EAAAG,SAAQF,EAAOD,CAAK,EAClCC,GAKTC,EAASF,CAAK,EAEPA,GACN,CAACC,EAAOD,CAAK,CAAC,CACnB","names":["useDeepMemo_exports","__export","useDeepMemo","__toCommonJS","import_isEqual","import_react","value","state","setState","isEqual"]}
1
+ {"version":3,"sources":["../src/useDeepMemo.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * Provides a memoized value in React where the value is checked for deep\n * equality. If the value has changed, but is deeply equal to the previous\n * value, then useDeepMemo will return the same reference to the previous\n * value and ignore the latest value.\n *\n * This is mainly used in shared queries to check for changes in the query\n * arguments, but it might be useful for your own use cases.\n */\n\nimport isEqual from \"lodash/isEqual\";\nimport { useMemo, useState } from \"react\";\n\n/**\n * Provides a stable value for T based on deep equality. The deep equality is\n * determined by the `isEqual()` function in lodash.\n */\nexport function useDeepMemo<T>(value: T): T {\n const [state, setState] = useState<T>(value);\n\n return useMemo(() => {\n if (isEqual(state, value)) {\n return state;\n }\n\n // We check equality, so this should be safe.\n // eslint-disable-next-line react-hooks/set-state-in-render\n setState(value);\n\n return value;\n }, [state, value]);\n}\n"],"mappings":"0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,iBAAAE,IAAA,eAAAC,EAAAH,GAYA,IAAAI,EAAoB,6BACpBC,EAAkC,iBAM3B,SAASH,EAAeI,EAAa,CAC1C,GAAM,CAACC,EAAOC,CAAQ,KAAI,YAAYF,CAAK,EAE3C,SAAO,WAAQ,OACT,EAAAG,SAAQF,EAAOD,CAAK,EACfC,GAKTC,EAASF,CAAK,EAEPA,GACN,CAACC,EAAOD,CAAK,CAAC,CACnB","names":["useDeepMemo_exports","__export","useDeepMemo","__toCommonJS","import_isEqual","import_react","value","state","setState","isEqual"]}
@@ -1,2 +1,2 @@
1
- import o from"lodash/isEqual";import{useMemo as s,useState as m}from"react";function f(t){let[r,e]=m(t);return s(()=>r===t||o(r,t)?r:(e(t),t),[r,t])}export{f as useDeepMemo};
1
+ import o from"lodash/isEqual";import{useMemo as s,useState as m}from"react";function f(t){let[e,r]=m(t);return s(()=>o(e,t)?e:(r(t),t),[e,t])}export{f as useDeepMemo};
2
2
  //# sourceMappingURL=useDeepMemo.min.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/useDeepMemo.ts"],"sourcesContent":["import isEqual from \"lodash/isEqual\";\nimport { useMemo, useState } from \"react\";\n\n/**\n * Provides a stable value for T based on deep equality. The deep equality is\n * determined by the `isEqual()` function in lodash.\n */\nexport function useDeepMemo<T>(value: T): T {\n const [state, setState] = useState<T>(value);\n\n return useMemo(() => {\n if (state === value || isEqual(state, value)) {\n return state;\n }\n\n // We check equality, so this should be safe.\n // eslint-disable-next-line react-hooks/set-state-in-render\n setState(value);\n\n return value;\n }, [state, value]);\n}\n"],"mappings":"AAAA,OAAOA,MAAa,iBACpB,OAAS,WAAAC,EAAS,YAAAC,MAAgB,QAM3B,SAASC,EAAeC,EAAa,CAC1C,GAAM,CAACC,EAAOC,CAAQ,EAAIJ,EAAYE,CAAK,EAE3C,OAAOH,EAAQ,IACTI,IAAUD,GAASJ,EAAQK,EAAOD,CAAK,EAClCC,GAKTC,EAASF,CAAK,EAEPA,GACN,CAACC,EAAOD,CAAK,CAAC,CACnB","names":["isEqual","useMemo","useState","useDeepMemo","value","state","setState"]}
1
+ {"version":3,"sources":["../src/useDeepMemo.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * Provides a memoized value in React where the value is checked for deep\n * equality. If the value has changed, but is deeply equal to the previous\n * value, then useDeepMemo will return the same reference to the previous\n * value and ignore the latest value.\n *\n * This is mainly used in shared queries to check for changes in the query\n * arguments, but it might be useful for your own use cases.\n */\n\nimport isEqual from \"lodash/isEqual\";\nimport { useMemo, useState } from \"react\";\n\n/**\n * Provides a stable value for T based on deep equality. The deep equality is\n * determined by the `isEqual()` function in lodash.\n */\nexport function useDeepMemo<T>(value: T): T {\n const [state, setState] = useState<T>(value);\n\n return useMemo(() => {\n if (isEqual(state, value)) {\n return state;\n }\n\n // We check equality, so this should be safe.\n // eslint-disable-next-line react-hooks/set-state-in-render\n setState(value);\n\n return value;\n }, [state, value]);\n}\n"],"mappings":"AAYA,OAAOA,MAAa,iBACpB,OAAS,WAAAC,EAAS,YAAAC,MAAgB,QAM3B,SAASC,EAAeC,EAAa,CAC1C,GAAM,CAACC,EAAOC,CAAQ,EAAIJ,EAAYE,CAAK,EAE3C,OAAOH,EAAQ,IACTD,EAAQK,EAAOD,CAAK,EACfC,GAKTC,EAASF,CAAK,EAEPA,GACN,CAACC,EAAOD,CAAK,CAAC,CACnB","names":["isEqual","useMemo","useState","useDeepMemo","value","state","setState"]}
package/useDeepMemo.mjs CHANGED
@@ -4,7 +4,7 @@ import { useMemo, useState } from "react";
4
4
  function useDeepMemo(value) {
5
5
  const [state, setState] = useState(value);
6
6
  return useMemo(() => {
7
- if (state === value || isEqual(state, value)) {
7
+ if (isEqual(state, value)) {
8
8
  return state;
9
9
  }
10
10
  setState(value);