@choksheak/react-utils 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/assets/highlight.css +49 -0
- package/docs/assets/search.js +1 -1
- package/docs/classes/sharedQuery.SharedQuery.html +11 -6
- package/docs/classes/sharedState.SharedState.html +2 -2
- package/docs/classes/utils_storage.InMemoryStorageAdapter.html +2 -2
- package/docs/classes/utils_storage.IndexedDbAdapter.html +2 -2
- package/docs/classes/utils_storage.LocalStorageAdapter.html +2 -2
- package/docs/functions/sharedQuery.sharedQuery.html +5 -1
- package/docs/functions/sharedQuery.useSharedQuery.html +5 -3
- package/docs/functions/sharedState.sharedState.html +1 -1
- package/docs/functions/sharedState.useSharedState.html +1 -1
- package/docs/functions/sharedState.useSharedStateSetter.html +1 -1
- package/docs/functions/sharedState.useSharedStateValue.html +1 -1
- package/docs/functions/utils_storage.getStorageAdapter.html +1 -1
- package/docs/functions/utils_stringify.stringifyDeterministicForKeys.html +1 -1
- package/docs/types/sharedQuery.FetchFn.html +1 -1
- package/docs/types/sharedQuery.PersistTo.html +1 -1
- package/docs/types/sharedQuery.QueryStateValue.html +5 -2
- package/docs/types/sharedQuery.SharedQueryOptions.html +1 -1
- package/docs/types/sharedQuery.SharedQueryState.html +1 -1
- package/docs/types/sharedQuery.UseQueryResult.html +1 -1
- package/docs/types/sharedState.SharedStateOptions.html +1 -1
- package/docs/types/utils_storage.StorageAdapter.html +2 -2
- package/docs/types/utils_storage.StorageOptions.html +2 -2
- package/docs/variables/fetcher.fetcher.html +1 -1
- package/docs/variables/fetcher.fetcherWithRetries.html +1 -1
- package/docs/variables/sharedQuery.SharedQueryDefaults.html +2 -2
- package/docs/variables/sharedState.SharedStateDefaults.html +1 -1
- package/package.json +33 -32
- package/sharedQuery.d.mts +30 -1
- package/sharedQuery.d.ts +30 -1
- package/sharedQuery.js +106 -5
- package/sharedQuery.mjs +96 -5
- package/src/sharedQuery.ts +159 -5
- package/src/utils/stringify.ts +1 -1
- package/utils/stringify.js +1 -1
- package/utils/stringify.mjs +1 -1
- package/src/utils/stringify.test.ts +0 -38
- package/utils/stringify.test.d.mts +0 -2
- package/utils/stringify.test.d.ts +0 -2
- package/utils/stringify.test.js +0 -64
- package/utils/stringify.test.mjs +0 -81
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>fetcher | Chok’s React Utilities</title><meta name="description" content="Documentation for Chok’s React Utilities"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">Chok’s React Utilities</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="../modules/fetcher.html">fetcher</a></li><li><a href="" aria-current="page">fetcher</a></li></ul><h1>Variable fetcher<code class="tsd-tag">Const</code></h1></div><div class="tsd-signature"><span class="tsd-kind-variable">fetcher</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">Wretch</span><span class="tsd-signature-symbol"><</span><span class="tsd-signature-type">unknown</span><span class="tsd-signature-symbol">,</span> <span class="tsd-signature-type">unknown</span><span class="tsd-signature-symbol">,</span> <span class="tsd-signature-type">undefined</span><span class="tsd-signature-symbol">,</span> <span class="tsd-signature-type">undefined</span><span class="tsd-signature-symbol">></span><span class="tsd-signature-symbol"> = ...</span></div><div class="tsd-comment tsd-typography"><p>Name this as "fetcher" to make it easier to understand.</p>
|
|
2
|
-
</div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/choksheak/react-utils/blob/
|
|
2
|
+
</div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/choksheak/react-utils/blob/6e51f83891b45c4e9690241acb26557b1dbcce3f/src/fetcher.ts#L5">fetcher.ts:5</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">Chok’s React Utilities</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>fetcherWithRetries | Chok’s React Utilities</title><meta name="description" content="Documentation for Chok’s React Utilities"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">Chok’s React Utilities</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="../modules/fetcher.html">fetcher</a></li><li><a href="" aria-current="page">fetcherWithRetries</a></li></ul><h1>Variable fetcherWithRetries<code class="tsd-tag">Const</code></h1></div><div class="tsd-signature"><span class="tsd-kind-variable">fetcherWithRetries</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">Wretch</span><span class="tsd-signature-symbol"><</span><span class="tsd-signature-type">unknown</span><span class="tsd-signature-symbol">,</span> <span class="tsd-signature-type">unknown</span><span class="tsd-signature-symbol">,</span> <span class="tsd-signature-type">undefined</span><span class="tsd-signature-symbol">,</span> <span class="tsd-signature-type">undefined</span><span class="tsd-signature-symbol">></span><span class="tsd-signature-symbol"> = ...</span></div><div class="tsd-comment tsd-typography"><p>Fetcher with default short retries.</p>
|
|
2
|
-
</div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/choksheak/react-utils/blob/
|
|
2
|
+
</div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/choksheak/react-utils/blob/6e51f83891b45c4e9690241acb26557b1dbcce3f/src/fetcher.ts#L8">fetcher.ts:8</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">Chok’s React Utilities</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>SharedQueryDefaults | Chok’s React Utilities</title><meta name="description" content="Documentation for Chok’s React Utilities"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">Chok’s React Utilities</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="../modules/sharedQuery.html">sharedQuery</a></li><li><a href="" aria-current="page">SharedQueryDefaults</a></li></ul><h1>Variable SharedQueryDefaults<code class="tsd-tag">Const</code></h1></div><div class="tsd-signature"><span class="tsd-kind-variable">SharedQueryDefaults</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">{</span><br/> <span class="tsd-kind-property">expiryMs</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">;</span><br/> <span class="tsd-kind-property">persistTo</span><span class="tsd-signature-symbol">:</span> <a href="../types/sharedQuery.PersistTo.html" class="tsd-signature-type tsd-kind-type-alias">PersistTo</a> <span class="tsd-signature-symbol">|</span> <span class="tsd-signature-type">undefined</span><span class="tsd-signature-symbol">;</span><br/> <span class="tsd-kind-property">staleMs</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">;</span><br/><span class="tsd-signature-symbol">}</span><span class="tsd-signature-symbol"> = ...</span></div><div class="tsd-comment tsd-typography"><p>Users can override these values globally.</p>
|
|
2
|
-
</div><div class="tsd-type-declaration"><h4>Type Declaration</h4><ul class="tsd-parameters"><li class="tsd-parameter"><h5 id="expiryms"><span class="tsd-kind-property">expiryMs</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span></h5></li><li class="tsd-parameter"><h5 id="persistto"><span class="tsd-kind-property">persistTo</span><span class="tsd-signature-symbol">: </span><a href="../types/sharedQuery.PersistTo.html" class="tsd-signature-type tsd-kind-type-alias">PersistTo</a> <span class="tsd-signature-symbol">|</span> <span class="tsd-signature-type">undefined</span></h5></li><li class="tsd-parameter"><h5 id="stalems"><span class="tsd-kind-property">staleMs</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span></h5></li></ul></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/choksheak/react-utils/blob/
|
|
1
|
+
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>SharedQueryDefaults | Chok’s React Utilities</title><meta name="description" content="Documentation for Chok’s React Utilities"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">Chok’s React Utilities</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="../modules/sharedQuery.html">sharedQuery</a></li><li><a href="" aria-current="page">SharedQueryDefaults</a></li></ul><h1>Variable SharedQueryDefaults<code class="tsd-tag">Const</code></h1></div><div class="tsd-signature"><span class="tsd-kind-variable">SharedQueryDefaults</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">{</span><br/> <span class="tsd-kind-property">expiryMs</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">;</span><br/> <span class="tsd-kind-property">maxBytes</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">;</span><br/> <span class="tsd-kind-property">maxSize</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">;</span><br/> <span class="tsd-kind-property">persistTo</span><span class="tsd-signature-symbol">:</span> <a href="../types/sharedQuery.PersistTo.html" class="tsd-signature-type tsd-kind-type-alias">PersistTo</a> <span class="tsd-signature-symbol">|</span> <span class="tsd-signature-type">undefined</span><span class="tsd-signature-symbol">;</span><br/> <span class="tsd-kind-property">staleMs</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">;</span><br/><span class="tsd-signature-symbol">}</span><span class="tsd-signature-symbol"> = ...</span></div><div class="tsd-comment tsd-typography"><p>Users can override these values globally.</p>
|
|
2
|
+
</div><div class="tsd-type-declaration"><h4>Type Declaration</h4><ul class="tsd-parameters"><li class="tsd-parameter"><h5 id="expiryms"><span class="tsd-kind-property">expiryMs</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span></h5></li><li class="tsd-parameter"><h5 id="maxbytes"><span class="tsd-kind-property">maxBytes</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span></h5></li><li class="tsd-parameter"><h5 id="maxsize"><span class="tsd-kind-property">maxSize</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span></h5></li><li class="tsd-parameter"><h5 id="persistto"><span class="tsd-kind-property">persistTo</span><span class="tsd-signature-symbol">: </span><a href="../types/sharedQuery.PersistTo.html" class="tsd-signature-type tsd-kind-type-alias">PersistTo</a> <span class="tsd-signature-symbol">|</span> <span class="tsd-signature-type">undefined</span></h5></li><li class="tsd-parameter"><h5 id="stalems"><span class="tsd-kind-property">staleMs</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span></h5></li></ul></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/choksheak/react-utils/blob/6e51f83891b45c4e9690241acb26557b1dbcce3f/src/sharedQuery.ts#L77">sharedQuery.ts:77</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">Chok’s React Utilities</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
the top level scope when the shared state is defined.</p>
|
|
4
4
|
</div></li><li class="tsd-parameter"><h5 id="storeexpiryms"><span class="tsd-kind-property">storeExpiryMs</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">number</span></h5><div class="tsd-comment tsd-typography"><p>Default duration for storage expiration in milliseconds. Initial value
|
|
5
5
|
is 30 days, but can be changed to anything.</p>
|
|
6
|
-
</div></li></ul></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/choksheak/react-utils/blob/
|
|
6
|
+
</div></li></ul></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/choksheak/react-utils/blob/6e51f83891b45c4e9690241acb26557b1dbcce3f/src/sharedState.ts#L28">sharedState.ts:28</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">Chok’s React Utilities</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@choksheak/react-utils",
|
|
3
3
|
"license": "The Unlicense",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.3",
|
|
5
5
|
"description": "Miscellaneous React+TypeScript utilities with support for full tree-shaking.",
|
|
6
6
|
"private": false,
|
|
7
7
|
"main": "index.js",
|
|
@@ -10,34 +10,6 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"**/*"
|
|
12
12
|
],
|
|
13
|
-
"exports": {
|
|
14
|
-
"./package.json": "./package.json",
|
|
15
|
-
"./fetcher": {
|
|
16
|
-
"types": "./fetcher.d.ts",
|
|
17
|
-
"import": "./fetcher.js"
|
|
18
|
-
},
|
|
19
|
-
"./sharedQuery": {
|
|
20
|
-
"types": "./sharedQuery.d.ts",
|
|
21
|
-
"import": "./sharedQuery.js"
|
|
22
|
-
},
|
|
23
|
-
"./sharedState": {
|
|
24
|
-
"types": "./sharedState.d.ts",
|
|
25
|
-
"import": "./sharedState.js"
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
"typesVersions": {
|
|
29
|
-
"*": {
|
|
30
|
-
"fetcher": [
|
|
31
|
-
"fetcher.d.ts"
|
|
32
|
-
],
|
|
33
|
-
"sharedQuery": [
|
|
34
|
-
"sharedQuery.d.ts"
|
|
35
|
-
],
|
|
36
|
-
"sharedState": [
|
|
37
|
-
"sharedState.d.ts"
|
|
38
|
-
]
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
13
|
"scripts": {
|
|
42
14
|
"lint": "eslint .",
|
|
43
15
|
"fix": "eslint . --fix",
|
|
@@ -50,6 +22,7 @@
|
|
|
50
22
|
"ls": "lint-staged",
|
|
51
23
|
"docs": "rm -rf docs && typedoc `find src -name '*.ts' ! -name '*.test.ts'` --out docs --name 'Chok’s React Utilities'",
|
|
52
24
|
"gen-types": "tsc --emitDeclarationOnly --declaration",
|
|
25
|
+
"gen-exports": "tsx scripts/gen-exports.ts",
|
|
53
26
|
"bump": "tsx scripts/bump-version.ts",
|
|
54
27
|
"bump:patch": "tsx scripts/bump-version.ts --patch",
|
|
55
28
|
"bump:minor": "tsx scripts/bump-version.ts --minor",
|
|
@@ -57,7 +30,7 @@
|
|
|
57
30
|
"pkg": "scripts/package.sh",
|
|
58
31
|
"pub": "npm publish dist/ --access=public",
|
|
59
32
|
"commit": "scripts/commit-release.sh",
|
|
60
|
-
"release": "npm run ci && npm run bump && npm run pkg && npm run pub && npm run commit",
|
|
33
|
+
"release": "npm run ci && npm run bump && npm i && npm run pkg && npm run pub && npm run commit",
|
|
61
34
|
"postinstall": "simple-git-hooks"
|
|
62
35
|
},
|
|
63
36
|
"simple-git-hooks": {
|
|
@@ -90,7 +63,6 @@
|
|
|
90
63
|
"devDependencies": {
|
|
91
64
|
"@eslint/compat": "^1.4.0",
|
|
92
65
|
"@eslint/js": "^9.38.0",
|
|
93
|
-
"@tanstack/react-query": "^5.90.5",
|
|
94
66
|
"@types/jest": "^30.0.0",
|
|
95
67
|
"@types/react": "^19.2.2",
|
|
96
68
|
"@types/react-dom": "^19.2.2",
|
|
@@ -107,6 +79,7 @@
|
|
|
107
79
|
"globals": "^16.4.0",
|
|
108
80
|
"jiti": "^2.6.1",
|
|
109
81
|
"lint-staged": "^16.2.6",
|
|
82
|
+
"object-sizeof": "^2.6.5",
|
|
110
83
|
"prettier": "^3.6.2",
|
|
111
84
|
"react": "^19.2.0",
|
|
112
85
|
"react-dom": "^19.2.0",
|
|
@@ -121,8 +94,36 @@
|
|
|
121
94
|
},
|
|
122
95
|
"peerDependencies": {
|
|
123
96
|
"@choksheak/ts-utils": ">=0.2.9",
|
|
124
|
-
"
|
|
97
|
+
"object-sizeof": ">=2.6.5",
|
|
125
98
|
"react": ">=16",
|
|
126
99
|
"wretch": ">=3"
|
|
100
|
+
},
|
|
101
|
+
"exports": {
|
|
102
|
+
"./package.json": "./package.json",
|
|
103
|
+
"./fetcher": {
|
|
104
|
+
"types": "./fetcher.d.ts",
|
|
105
|
+
"import": "./fetcher.js"
|
|
106
|
+
},
|
|
107
|
+
"./sharedQuery": {
|
|
108
|
+
"types": "./sharedQuery.d.ts",
|
|
109
|
+
"import": "./sharedQuery.js"
|
|
110
|
+
},
|
|
111
|
+
"./sharedState": {
|
|
112
|
+
"types": "./sharedState.d.ts",
|
|
113
|
+
"import": "./sharedState.js"
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"typesVersions": {
|
|
117
|
+
"*": {
|
|
118
|
+
"fetcher": [
|
|
119
|
+
"./fetcher.d.ts"
|
|
120
|
+
],
|
|
121
|
+
"sharedQuery": [
|
|
122
|
+
"./sharedQuery.d.ts"
|
|
123
|
+
],
|
|
124
|
+
"sharedState": [
|
|
125
|
+
"./sharedState.d.ts"
|
|
126
|
+
]
|
|
127
|
+
}
|
|
127
128
|
}
|
|
128
129
|
}
|
package/sharedQuery.d.mts
CHANGED
|
@@ -3,6 +3,11 @@ import './utils/storage.mjs';
|
|
|
3
3
|
|
|
4
4
|
type FetchFn<TArgs extends unknown[], TData> = (...args: TArgs) => Promise<TData> | TData;
|
|
5
5
|
type QueryStateValue<TData> = {
|
|
6
|
+
/**
|
|
7
|
+
* When this record was last updated. Used for LRU determination. If you want
|
|
8
|
+
* the data age, please use `dataUpdatedMs` instead.
|
|
9
|
+
*/
|
|
10
|
+
lastUpdatedMs: number;
|
|
6
11
|
loading: boolean;
|
|
7
12
|
data?: TData;
|
|
8
13
|
dataUpdatedMs?: number;
|
|
@@ -27,12 +32,16 @@ type SharedQueryOptions<TArgs extends unknown[], TData> = {
|
|
|
27
32
|
expiryMs?: number;
|
|
28
33
|
refetchOnStale?: boolean;
|
|
29
34
|
persistTo?: PersistTo;
|
|
35
|
+
maxSize?: number;
|
|
36
|
+
maxBytes?: number;
|
|
30
37
|
} & SharedStateOptions<SharedQueryState<TData>>;
|
|
31
38
|
/** Users can override these values globally. */
|
|
32
39
|
declare const SharedQueryDefaults: {
|
|
33
40
|
staleMs: number;
|
|
34
41
|
expiryMs: number;
|
|
35
42
|
persistTo: PersistTo | undefined;
|
|
43
|
+
maxSize: number;
|
|
44
|
+
maxBytes: number;
|
|
36
45
|
};
|
|
37
46
|
declare class SharedQuery<TArgs extends unknown[], TData> {
|
|
38
47
|
private readonly inflightPromises;
|
|
@@ -42,6 +51,8 @@ declare class SharedQuery<TArgs extends unknown[], TData> {
|
|
|
42
51
|
readonly expiryMs: number;
|
|
43
52
|
readonly staleMs: number;
|
|
44
53
|
readonly refetchOnStale: boolean;
|
|
54
|
+
readonly maxSize: number;
|
|
55
|
+
readonly maxBytes: number;
|
|
45
56
|
constructor(options: SharedQueryOptions<TArgs, TData>);
|
|
46
57
|
getQueryKey(args: TArgs): string;
|
|
47
58
|
private isStale;
|
|
@@ -57,6 +68,11 @@ declare class SharedQuery<TArgs extends unknown[], TData> {
|
|
|
57
68
|
deleteData(args: TArgs): void;
|
|
58
69
|
/** Delete all currently cached data & all inflight promises. */
|
|
59
70
|
clear(): void;
|
|
71
|
+
/**
|
|
72
|
+
* Discard the oldest entries if the size exceeds the limit. The last
|
|
73
|
+
* remaining record cannot be deleted no matter what the limit is.
|
|
74
|
+
*/
|
|
75
|
+
enforceSizeLimit(): void;
|
|
60
76
|
}
|
|
61
77
|
/**
|
|
62
78
|
* Create a reusable shared query object that can be used to auto de-duplicate
|
|
@@ -64,12 +80,25 @@ declare class SharedQuery<TArgs extends unknown[], TData> {
|
|
|
64
80
|
*
|
|
65
81
|
* Each `queryName` must be unique, and can only be declared once, most often
|
|
66
82
|
* in the top level scope. The queryName is used for logging only.
|
|
83
|
+
*
|
|
84
|
+
* Example:
|
|
85
|
+
* ```
|
|
86
|
+
* export const usersQuery = sharedQuery({
|
|
87
|
+
* queryName: "users",
|
|
88
|
+
* queryFn: listUsers,
|
|
89
|
+
* persistTo: "indexedDb",
|
|
90
|
+
* staleMs: MS_PER_DAY,
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
67
93
|
*/
|
|
68
94
|
declare function sharedQuery<TArgs extends unknown[], TData>(options: SharedQueryOptions<TArgs, TData>): SharedQuery<TArgs, TData>;
|
|
69
95
|
/**
|
|
70
96
|
* React hook to make use of a shared query inside any React component.
|
|
71
97
|
*
|
|
72
|
-
*
|
|
98
|
+
* Example:
|
|
99
|
+
* ```
|
|
100
|
+
* const users = useSharedQuery(usersQuery, ["123"]);
|
|
101
|
+
* ```
|
|
73
102
|
*/
|
|
74
103
|
declare function useSharedQuery<TArgs extends unknown[], TData>(query: SharedQuery<TArgs, TData>, args?: TArgs): UseQueryResult<TData>;
|
|
75
104
|
|
package/sharedQuery.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { SharedState, SharedStateOptions } from "./sharedState";
|
|
2
2
|
export type FetchFn<TArgs extends unknown[], TData> = (...args: TArgs) => Promise<TData> | TData;
|
|
3
3
|
export type QueryStateValue<TData> = {
|
|
4
|
+
/**
|
|
5
|
+
* When this record was last updated. Used for LRU determination. If you want
|
|
6
|
+
* the data age, please use `dataUpdatedMs` instead.
|
|
7
|
+
*/
|
|
8
|
+
lastUpdatedMs: number;
|
|
4
9
|
loading: boolean;
|
|
5
10
|
data?: TData;
|
|
6
11
|
dataUpdatedMs?: number;
|
|
@@ -25,12 +30,16 @@ export type SharedQueryOptions<TArgs extends unknown[], TData> = {
|
|
|
25
30
|
expiryMs?: number;
|
|
26
31
|
refetchOnStale?: boolean;
|
|
27
32
|
persistTo?: PersistTo;
|
|
33
|
+
maxSize?: number;
|
|
34
|
+
maxBytes?: number;
|
|
28
35
|
} & SharedStateOptions<SharedQueryState<TData>>;
|
|
29
36
|
/** Users can override these values globally. */
|
|
30
37
|
export declare const SharedQueryDefaults: {
|
|
31
38
|
staleMs: number;
|
|
32
39
|
expiryMs: number;
|
|
33
40
|
persistTo: PersistTo | undefined;
|
|
41
|
+
maxSize: number;
|
|
42
|
+
maxBytes: number;
|
|
34
43
|
};
|
|
35
44
|
export declare class SharedQuery<TArgs extends unknown[], TData> {
|
|
36
45
|
private readonly inflightPromises;
|
|
@@ -40,6 +49,8 @@ export declare class SharedQuery<TArgs extends unknown[], TData> {
|
|
|
40
49
|
readonly expiryMs: number;
|
|
41
50
|
readonly staleMs: number;
|
|
42
51
|
readonly refetchOnStale: boolean;
|
|
52
|
+
readonly maxSize: number;
|
|
53
|
+
readonly maxBytes: number;
|
|
43
54
|
constructor(options: SharedQueryOptions<TArgs, TData>);
|
|
44
55
|
getQueryKey(args: TArgs): string;
|
|
45
56
|
private isStale;
|
|
@@ -55,6 +66,11 @@ export declare class SharedQuery<TArgs extends unknown[], TData> {
|
|
|
55
66
|
deleteData(args: TArgs): void;
|
|
56
67
|
/** Delete all currently cached data & all inflight promises. */
|
|
57
68
|
clear(): void;
|
|
69
|
+
/**
|
|
70
|
+
* Discard the oldest entries if the size exceeds the limit. The last
|
|
71
|
+
* remaining record cannot be deleted no matter what the limit is.
|
|
72
|
+
*/
|
|
73
|
+
enforceSizeLimit(): void;
|
|
58
74
|
}
|
|
59
75
|
/**
|
|
60
76
|
* Create a reusable shared query object that can be used to auto de-duplicate
|
|
@@ -62,11 +78,24 @@ export declare class SharedQuery<TArgs extends unknown[], TData> {
|
|
|
62
78
|
*
|
|
63
79
|
* Each `queryName` must be unique, and can only be declared once, most often
|
|
64
80
|
* in the top level scope. The queryName is used for logging only.
|
|
81
|
+
*
|
|
82
|
+
* Example:
|
|
83
|
+
* ```
|
|
84
|
+
* export const usersQuery = sharedQuery({
|
|
85
|
+
* queryName: "users",
|
|
86
|
+
* queryFn: listUsers,
|
|
87
|
+
* persistTo: "indexedDb",
|
|
88
|
+
* staleMs: MS_PER_DAY,
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
65
91
|
*/
|
|
66
92
|
export declare function sharedQuery<TArgs extends unknown[], TData>(options: SharedQueryOptions<TArgs, TData>): SharedQuery<TArgs, TData>;
|
|
67
93
|
/**
|
|
68
94
|
* React hook to make use of a shared query inside any React component.
|
|
69
95
|
*
|
|
70
|
-
*
|
|
96
|
+
* Example:
|
|
97
|
+
* ```
|
|
98
|
+
* const users = useSharedQuery(usersQuery, ["123"]);
|
|
99
|
+
* ```
|
|
71
100
|
*/
|
|
72
101
|
export declare function useSharedQuery<TArgs extends unknown[], TData>(query: SharedQuery<TArgs, TData>, args?: TArgs): UseQueryResult<TData>;
|
package/sharedQuery.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/sharedQuery.ts
|
|
@@ -27,6 +37,7 @@ __export(sharedQuery_exports, {
|
|
|
27
37
|
});
|
|
28
38
|
module.exports = __toCommonJS(sharedQuery_exports);
|
|
29
39
|
var import_timeConstants2 = require("@choksheak/ts-utils/timeConstants");
|
|
40
|
+
var import_object_sizeof = __toESM(require("object-sizeof"));
|
|
30
41
|
var import_react2 = require("react");
|
|
31
42
|
|
|
32
43
|
// src/sharedState.ts
|
|
@@ -268,7 +279,7 @@ function stringifyDeterministicForKeys(params) {
|
|
|
268
279
|
if (typeof value === "function") {
|
|
269
280
|
throw new Error(`Functions should not be passed into query parameters`);
|
|
270
281
|
}
|
|
271
|
-
if (!value || typeof value !== "object") {
|
|
282
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
272
283
|
return value;
|
|
273
284
|
}
|
|
274
285
|
if (cache.has(value)) {
|
|
@@ -296,7 +307,11 @@ function stringifyDeterministicForKeys(params) {
|
|
|
296
307
|
var SharedQueryDefaults = {
|
|
297
308
|
staleMs: 0,
|
|
298
309
|
expiryMs: 30 * import_timeConstants2.MS_PER_DAY,
|
|
299
|
-
persistTo: void 0
|
|
310
|
+
persistTo: void 0,
|
|
311
|
+
maxSize: 100,
|
|
312
|
+
// 100 is not too large, but please tweak accordingly
|
|
313
|
+
maxBytes: 1e5
|
|
314
|
+
// 100kb before GC
|
|
300
315
|
};
|
|
301
316
|
var SharedQuery = class {
|
|
302
317
|
inflightPromises = /* @__PURE__ */ new Map();
|
|
@@ -306,6 +321,8 @@ var SharedQuery = class {
|
|
|
306
321
|
expiryMs;
|
|
307
322
|
staleMs;
|
|
308
323
|
refetchOnStale;
|
|
324
|
+
maxSize;
|
|
325
|
+
maxBytes;
|
|
309
326
|
constructor(options) {
|
|
310
327
|
this.queryName = options.queryName;
|
|
311
328
|
this.queryFn = options.queryFn;
|
|
@@ -318,6 +335,8 @@ var SharedQuery = class {
|
|
|
318
335
|
} else if (persistTo === "indexedDb") {
|
|
319
336
|
options.indexedDbKey = options.queryName;
|
|
320
337
|
}
|
|
338
|
+
this.maxSize = options?.maxSize ?? SharedQueryDefaults.maxSize;
|
|
339
|
+
this.maxBytes = options?.maxBytes ?? SharedQueryDefaults.maxBytes;
|
|
321
340
|
this.queryState = sharedState(
|
|
322
341
|
{},
|
|
323
342
|
{
|
|
@@ -386,11 +405,13 @@ var SharedQuery = class {
|
|
|
386
405
|
/** Set the data directly if the user obtained it from somewhere else. */
|
|
387
406
|
async setData(queryKey, data, dataUpdatedMs = Date.now()) {
|
|
388
407
|
const entry = {
|
|
408
|
+
lastUpdatedMs: Date.now(),
|
|
389
409
|
loading: false,
|
|
390
410
|
data,
|
|
391
411
|
dataUpdatedMs
|
|
392
412
|
};
|
|
393
413
|
this.queryState.setValue((prev) => ({ ...prev, [queryKey]: entry }));
|
|
414
|
+
this.enforceSizeLimit();
|
|
394
415
|
}
|
|
395
416
|
/** Do a new fetch even when the data is already cached. */
|
|
396
417
|
async updateFromSource(...args) {
|
|
@@ -411,6 +432,78 @@ var SharedQuery = class {
|
|
|
411
432
|
this.queryState.delete();
|
|
412
433
|
this.inflightPromises.clear();
|
|
413
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* Discard the oldest entries if the size exceeds the limit. The last
|
|
437
|
+
* remaining record cannot be deleted no matter what the limit is.
|
|
438
|
+
*/
|
|
439
|
+
enforceSizeLimit() {
|
|
440
|
+
if (!this.maxSize && !this.maxBytes) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
const oldState = this.queryState.getSnapshot();
|
|
444
|
+
const oldSize = Object.keys(oldState).length;
|
|
445
|
+
if (oldSize <= 1) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const oldByteSize = (0, import_object_sizeof.default)(oldState);
|
|
449
|
+
let newState = oldState;
|
|
450
|
+
let needUpdate = false;
|
|
451
|
+
if (this.maxSize) {
|
|
452
|
+
const numToCut = oldSize - this.maxSize;
|
|
453
|
+
if (numToCut > 0) {
|
|
454
|
+
console.log(
|
|
455
|
+
`enforceSizeLimit for ${this.queryName} needed due to size ${oldSize} > ${this.maxSize}`
|
|
456
|
+
);
|
|
457
|
+
newState = { ...newState };
|
|
458
|
+
needUpdate = true;
|
|
459
|
+
Object.entries(newState).sort(
|
|
460
|
+
(entry1, entry2) => (
|
|
461
|
+
// Sort descending.
|
|
462
|
+
entry2[1].lastUpdatedMs - entry1[1].lastUpdatedMs
|
|
463
|
+
)
|
|
464
|
+
).slice(-numToCut).forEach(([key]) => {
|
|
465
|
+
delete newState[key];
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
if (this.maxBytes && Object.keys(newState).length > 1) {
|
|
470
|
+
const currentByteSize = needUpdate ? (0, import_object_sizeof.default)(newState) : oldByteSize;
|
|
471
|
+
let bytesToCut = currentByteSize - this.maxBytes;
|
|
472
|
+
if (bytesToCut > 0) {
|
|
473
|
+
console.log(
|
|
474
|
+
`enforceSizeLimit for ${this.queryName} needed due to byte size ${currentByteSize.toLocaleString()} > ${this.maxBytes.toLocaleString()}`
|
|
475
|
+
);
|
|
476
|
+
if (!needUpdate) {
|
|
477
|
+
newState = { ...newState };
|
|
478
|
+
needUpdate = true;
|
|
479
|
+
}
|
|
480
|
+
const entriesByTimeAscending = Object.entries(newState).sort(
|
|
481
|
+
(entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
|
|
482
|
+
);
|
|
483
|
+
for (
|
|
484
|
+
let i = 0;
|
|
485
|
+
// Leave the last record entriesByTimeAscending[len-1] untouched.
|
|
486
|
+
i < entriesByTimeAscending.length - 1 && bytesToCut > 0;
|
|
487
|
+
i++
|
|
488
|
+
) {
|
|
489
|
+
const key = entriesByTimeAscending[i][0];
|
|
490
|
+
const thisSize = (0, import_object_sizeof.default)(key) + (0, import_object_sizeof.default)(newState[key]);
|
|
491
|
+
delete newState[key];
|
|
492
|
+
bytesToCut -= thisSize;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
if (needUpdate) {
|
|
497
|
+
this.queryState.setValue(newState);
|
|
498
|
+
console.log(
|
|
499
|
+
`Trimmed data for ${this.queryName}: size=(${oldSize} -> ${Object.keys(newState).length}) (limit=${this.maxSize}), byteSize=(${oldByteSize.toLocaleString()} -> ${(0, import_object_sizeof.default)(newState).toLocaleString()}) (limit=${this.maxBytes.toLocaleString()})`
|
|
500
|
+
);
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
console.log(
|
|
504
|
+
`No need to trim data for ${this.queryName}: size=${oldSize} (limit=${this.maxSize}), byteSize=${oldByteSize.toLocaleString()} (limit=${this.maxBytes.toLocaleString()})`
|
|
505
|
+
);
|
|
506
|
+
}
|
|
414
507
|
};
|
|
415
508
|
var seenQueryNames = /* @__PURE__ */ new Set();
|
|
416
509
|
function sharedQuery(options) {
|
|
@@ -420,7 +513,10 @@ function sharedQuery(options) {
|
|
|
420
513
|
seenQueryNames.add(options.queryName);
|
|
421
514
|
return new SharedQuery(options);
|
|
422
515
|
}
|
|
423
|
-
var DEFAULT_QUERY_STATE_ENTRY = {
|
|
516
|
+
var DEFAULT_QUERY_STATE_ENTRY = {
|
|
517
|
+
lastUpdatedMs: 0,
|
|
518
|
+
loading: true
|
|
519
|
+
};
|
|
424
520
|
function useSharedQuery(query, args = []) {
|
|
425
521
|
const [queryState, setQueryState] = useSharedState(query.queryState);
|
|
426
522
|
const isMounted = (0, import_react2.useRef)(true);
|
|
@@ -431,6 +527,7 @@ function useSharedQuery(query, args = []) {
|
|
|
431
527
|
const clone = { ...prev };
|
|
432
528
|
clone[queryKey] = {
|
|
433
529
|
...clone[queryKey] ?? {},
|
|
530
|
+
lastUpdatedMs: Date.now(),
|
|
434
531
|
loading: true
|
|
435
532
|
};
|
|
436
533
|
return clone;
|
|
@@ -440,11 +537,13 @@ function useSharedQuery(query, args = []) {
|
|
|
440
537
|
if (isMounted.current) {
|
|
441
538
|
setQueryState((prev) => {
|
|
442
539
|
const clone = { ...prev };
|
|
540
|
+
const now = Date.now();
|
|
443
541
|
clone[queryKey] = {
|
|
444
542
|
// Don't keep old error.
|
|
543
|
+
lastUpdatedMs: now,
|
|
445
544
|
loading: false,
|
|
446
545
|
data,
|
|
447
|
-
dataUpdatedMs:
|
|
546
|
+
dataUpdatedMs: now
|
|
448
547
|
};
|
|
449
548
|
return clone;
|
|
450
549
|
});
|
|
@@ -454,12 +553,14 @@ function useSharedQuery(query, args = []) {
|
|
|
454
553
|
if (isMounted.current) {
|
|
455
554
|
setQueryState((prev) => {
|
|
456
555
|
const clone = { ...prev };
|
|
556
|
+
const now = Date.now();
|
|
457
557
|
clone[queryKey] = {
|
|
458
558
|
// Keep old data.
|
|
459
559
|
...clone[queryKey] ?? {},
|
|
560
|
+
lastUpdatedMs: now,
|
|
460
561
|
loading: false,
|
|
461
562
|
error,
|
|
462
|
-
errorUpdatedMs:
|
|
563
|
+
errorUpdatedMs: now
|
|
463
564
|
};
|
|
464
565
|
return clone;
|
|
465
566
|
});
|