@cimplify/sdk 0.22.0 → 0.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.mjs CHANGED
@@ -3,7 +3,7 @@ import { getVariantDisplayName, createCimplifyClient } from './chunk-W3DMONZR.mj
3
3
  export { getVariantDisplayName } from './chunk-W3DMONZR.mjs';
4
4
  import { ELEMENT_TYPES, EVENT_TYPES } from './chunk-R4EYMPSN.mjs';
5
5
  import { isSupportedCurrency, formatPrice, parsePrice, isOnSale, getDiscountPercentage, getBasePrice } from './chunk-JFT63H34.mjs';
6
- import React3, { createContext, useContext, useState, useEffect, useRef, useMemo, useSyncExternalStore, useCallback, useId } from 'react';
6
+ import React3, { createContext, useRef, useState, useCallback, useEffect, useContext, useMemo, useSyncExternalStore, useId } from 'react';
7
7
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
8
8
  import { NumberField } from '@base-ui/react/number-field';
9
9
  import { clsx } from 'clsx';
@@ -1679,41 +1679,130 @@ function Price({ amount, className, prefix }) {
1679
1679
  formatPrice(convertPrice(amount), displayCurrency)
1680
1680
  ] });
1681
1681
  }
1682
- var productsCache = /* @__PURE__ */ new Map();
1683
- var productsInflight = /* @__PURE__ */ new Map();
1684
- function buildProductsCacheKey(client, locationId, options) {
1685
- return [
1686
- client.getPublicKey(),
1687
- locationId ?? "",
1688
- options.category ?? "",
1689
- options.taxonomy ?? "",
1690
- options.search ?? "",
1691
- options.featured ?? "",
1692
- options.limit ?? "",
1693
- options.sort_by ?? "",
1694
- options.sort_order ?? "",
1695
- options.tags?.join(",") ?? "",
1696
- options.in_stock ?? "",
1697
- options.min_price ?? "",
1698
- options.max_price ?? "",
1699
- options.page ?? "",
1700
- options.properties ? JSON.stringify(options.properties) : ""
1701
- ].join("|");
1702
- }
1703
- function useProducts(options = {}) {
1704
- const context = useOptionalCimplifyClient();
1705
- const client = options.client ?? context?.client;
1706
- if (!client) {
1707
- throw new Error("useProducts must be used within CimplifyProvider or passed { client }.");
1682
+ function createCachedQuery(config) {
1683
+ const cache = /* @__PURE__ */ new Map();
1684
+ const inflight = /* @__PURE__ */ new Map();
1685
+ const gcMaxAge = config.gcMaxAge ?? 3e5;
1686
+ let lastSweep = 0;
1687
+ function sweep() {
1688
+ const now = Date.now();
1689
+ if (now - lastSweep < 6e4) return;
1690
+ lastSweep = now;
1691
+ const cutoff = now - gcMaxAge;
1692
+ for (const [key, entry] of cache) {
1693
+ if (entry.ts < cutoff) cache.delete(key);
1694
+ }
1708
1695
  }
1709
- const enabled = options.enabled ?? true;
1710
- const locationId = client.getLocationId();
1711
- const previousLocationIdRef = useRef(locationId);
1712
- const requestIdRef = useRef(0);
1713
- const tagsSignature = options.tags?.join(",") ?? "";
1714
- const propertiesSignature = options.properties ? JSON.stringify(options.properties) : "";
1715
- const queryOptions = useMemo(
1716
- () => ({
1696
+ function useCachedQuery(options = {}) {
1697
+ const context = useOptionalCimplifyClient();
1698
+ const client = options.client ?? context?.client;
1699
+ if (!client) {
1700
+ throw new Error(
1701
+ `${config.name} must be used within CimplifyProvider or passed { client }.`
1702
+ );
1703
+ }
1704
+ const enabled = options.enabled ?? true;
1705
+ const locationId = client.getLocationId();
1706
+ const previousLocationRef = useRef(locationId);
1707
+ const requestIdRef = useRef(0);
1708
+ const optionsRef = useRef(options);
1709
+ optionsRef.current = options;
1710
+ if (config.locationSensitive && previousLocationRef.current !== locationId) {
1711
+ cache.clear();
1712
+ inflight.clear();
1713
+ previousLocationRef.current = locationId;
1714
+ }
1715
+ sweep();
1716
+ const cacheKey2 = config.key(client, options);
1717
+ const cached = cache.get(cacheKey2);
1718
+ const [data, setData] = useState(cached?.data ?? null);
1719
+ const [isLoading, setIsLoading] = useState(enabled && !cached);
1720
+ const [error, setError] = useState(null);
1721
+ const load = useCallback(
1722
+ async (force = false) => {
1723
+ if (!enabled) {
1724
+ setIsLoading(false);
1725
+ return;
1726
+ }
1727
+ const nextRequestId = ++requestIdRef.current;
1728
+ setError(null);
1729
+ if (!force) {
1730
+ const hit = cache.get(cacheKey2);
1731
+ if (hit) {
1732
+ setData(hit.data);
1733
+ setIsLoading(false);
1734
+ return;
1735
+ }
1736
+ }
1737
+ setIsLoading(true);
1738
+ try {
1739
+ const existing = inflight.get(cacheKey2);
1740
+ const promise = existing ?? (async () => config.fetch(client, optionsRef.current))();
1741
+ if (!existing) {
1742
+ inflight.set(cacheKey2, promise);
1743
+ promise.finally(() => inflight.delete(cacheKey2)).catch(() => {
1744
+ });
1745
+ }
1746
+ const value = await promise;
1747
+ cache.set(cacheKey2, { data: value, ts: Date.now() });
1748
+ if (nextRequestId === requestIdRef.current) {
1749
+ setData(value);
1750
+ setError(null);
1751
+ }
1752
+ } catch (loadError) {
1753
+ if (nextRequestId === requestIdRef.current) {
1754
+ setError(loadError);
1755
+ }
1756
+ } finally {
1757
+ if (nextRequestId === requestIdRef.current) {
1758
+ setIsLoading(false);
1759
+ }
1760
+ }
1761
+ },
1762
+ [cacheKey2, client, enabled]
1763
+ );
1764
+ useEffect(() => {
1765
+ void load(false);
1766
+ }, [load]);
1767
+ const refetch = useCallback(async () => {
1768
+ cache.delete(cacheKey2);
1769
+ await load(true);
1770
+ }, [cacheKey2, load]);
1771
+ return { data, isLoading, error, refetch };
1772
+ }
1773
+ useCachedQuery.clear = () => {
1774
+ cache.clear();
1775
+ inflight.clear();
1776
+ };
1777
+ return useCachedQuery;
1778
+ }
1779
+ function cacheKey(...parts) {
1780
+ return parts.map((p) => String(p ?? "")).join("|");
1781
+ }
1782
+
1783
+ // src/react/hooks/use-products.ts
1784
+ var productsQuery = createCachedQuery({
1785
+ name: "useProducts",
1786
+ locationSensitive: true,
1787
+ key: (client, options) => cacheKey(
1788
+ client.getPublicKey(),
1789
+ client.getLocationId(),
1790
+ options.category,
1791
+ options.taxonomy,
1792
+ options.search,
1793
+ options.featured,
1794
+ options.limit,
1795
+ options.sort_by,
1796
+ options.sort_order,
1797
+ options.tags?.join(","),
1798
+ options.in_stock,
1799
+ options.min_price,
1800
+ options.max_price,
1801
+ options.page,
1802
+ options.properties ? JSON.stringify(options.properties) : void 0
1803
+ ),
1804
+ fetch: async (client, options) => {
1805
+ const result = await client.catalogue.getProducts({
1717
1806
  category: options.category,
1718
1807
  taxonomy: options.taxonomy,
1719
1808
  search: options.search,
@@ -1727,301 +1816,71 @@ function useProducts(options = {}) {
1727
1816
  max_price: options.max_price,
1728
1817
  page: options.page,
1729
1818
  properties: options.properties
1730
- }),
1731
- [
1732
- options.category,
1733
- options.taxonomy,
1734
- options.search,
1735
- options.featured,
1736
- options.limit,
1737
- options.sort_by,
1738
- options.sort_order,
1739
- tagsSignature,
1740
- options.in_stock,
1741
- options.min_price,
1742
- options.max_price,
1743
- options.page,
1744
- propertiesSignature
1745
- ]
1746
- );
1747
- const cacheKey = useMemo(
1748
- () => buildProductsCacheKey(client, locationId, queryOptions),
1749
- [client, locationId, queryOptions]
1750
- );
1751
- const cached = productsCache.get(cacheKey);
1752
- const [products, setProducts] = useState(cached?.products ?? []);
1753
- const [isComplete, setIsComplete] = useState(cached?.is_complete ?? true);
1754
- const [totalAvailable, setTotalAvailable] = useState(cached?.total_available);
1755
- const [pagination, setPagination] = useState(cached?.pagination);
1756
- const [isLoading, setIsLoading] = useState(enabled && !cached);
1757
- const [error, setError] = useState(null);
1758
- useEffect(() => {
1759
- if (previousLocationIdRef.current !== locationId) {
1760
- productsCache.clear();
1761
- productsInflight.clear();
1762
- previousLocationIdRef.current = locationId;
1763
- }
1764
- }, [locationId]);
1765
- const load = useCallback(
1766
- async (force = false) => {
1767
- if (!enabled) {
1768
- setIsLoading(false);
1769
- return;
1770
- }
1771
- const nextRequestId = ++requestIdRef.current;
1772
- setError(null);
1773
- if (!force) {
1774
- const cacheEntry = productsCache.get(cacheKey);
1775
- if (cacheEntry) {
1776
- setProducts(cacheEntry.products);
1777
- setIsComplete(cacheEntry.is_complete);
1778
- setTotalAvailable(cacheEntry.total_available);
1779
- setPagination(cacheEntry.pagination);
1780
- setIsLoading(false);
1781
- return;
1782
- }
1783
- }
1784
- setIsLoading(true);
1785
- try {
1786
- const existing = productsInflight.get(cacheKey);
1787
- const promise = existing ?? (async () => {
1788
- const result = await client.catalogue.getProducts(queryOptions);
1789
- if (!result.ok) {
1790
- throw result.error;
1791
- }
1792
- return result.value;
1793
- })();
1794
- if (!existing) {
1795
- productsInflight.set(
1796
- cacheKey,
1797
- promise.finally(() => {
1798
- productsInflight.delete(cacheKey);
1799
- })
1800
- );
1801
- }
1802
- const value = await promise;
1803
- productsCache.set(cacheKey, {
1804
- products: value.items,
1805
- is_complete: value.is_complete,
1806
- total_available: value.total_available,
1807
- pagination: value.pagination
1808
- });
1809
- if (nextRequestId === requestIdRef.current) {
1810
- setProducts(value.items);
1811
- setIsComplete(value.is_complete);
1812
- setTotalAvailable(value.total_available);
1813
- setPagination(value.pagination);
1814
- setError(null);
1815
- }
1816
- } catch (loadError) {
1817
- if (nextRequestId === requestIdRef.current) {
1818
- setError(loadError);
1819
- }
1820
- } finally {
1821
- if (nextRequestId === requestIdRef.current) {
1822
- setIsLoading(false);
1823
- }
1824
- }
1825
- },
1826
- [cacheKey, client, enabled, queryOptions]
1827
- );
1828
- useEffect(() => {
1829
- void load(false);
1830
- }, [load]);
1831
- const refetch = useCallback(async () => {
1832
- productsCache.delete(cacheKey);
1833
- await load(true);
1834
- }, [cacheKey, load]);
1819
+ });
1820
+ if (!result.ok) throw result.error;
1821
+ return {
1822
+ products: result.value.items,
1823
+ is_complete: result.value.is_complete,
1824
+ total_available: result.value.total_available,
1825
+ pagination: result.value.pagination
1826
+ };
1827
+ }
1828
+ });
1829
+ function useProducts(options = {}) {
1830
+ const { data, isLoading, error, refetch } = productsQuery(options);
1835
1831
  return {
1836
- products,
1837
- is_complete: isComplete,
1838
- total_available: totalAvailable,
1839
- pagination,
1832
+ products: data?.products ?? [],
1833
+ is_complete: data?.is_complete ?? true,
1834
+ total_available: data?.total_available,
1835
+ pagination: data?.pagination,
1840
1836
  isLoading,
1841
1837
  error,
1842
1838
  refetch
1843
1839
  };
1844
1840
  }
1845
- var productCache = /* @__PURE__ */ new Map();
1846
- var productInflight = /* @__PURE__ */ new Map();
1841
+
1842
+ // src/react/hooks/use-product.ts
1847
1843
  function isLikelySlug(value) {
1848
1844
  return /^[a-z0-9-]+$/.test(value);
1849
1845
  }
1850
- function buildProductCacheKey(client, locationId, slugOrId) {
1851
- return JSON.stringify({
1852
- key: client.getPublicKey(),
1853
- location_id: locationId || "__none__",
1854
- slug_or_id: slugOrId
1846
+ var productQuery = createCachedQuery({
1847
+ name: "useProduct",
1848
+ locationSensitive: true,
1849
+ key: (client, options) => cacheKey(client.getPublicKey(), client.getLocationId(), options.slugOrId),
1850
+ fetch: async (client, options) => {
1851
+ const result = isLikelySlug(options.slugOrId) ? await client.catalogue.getProductBySlug(options.slugOrId) : await client.catalogue.getProduct(options.slugOrId);
1852
+ if (!result.ok) throw result.error;
1853
+ client.activity.trackProductView(result.value.id, {
1854
+ productName: result.value.name,
1855
+ categoryId: result.value.category_id,
1856
+ price: String(result.value.default_price)
1857
+ });
1858
+ return result.value;
1859
+ }
1860
+ });
1861
+ function useProduct(slugOrId, options = {}) {
1862
+ const normalized = (slugOrId || "").trim();
1863
+ const { data, isLoading, error, refetch } = productQuery({
1864
+ ...options,
1865
+ slugOrId: normalized,
1866
+ enabled: (options.enabled ?? true) && normalized.length > 0
1855
1867
  });
1868
+ return { product: data, isLoading, error, refetch };
1856
1869
  }
1857
- function useProduct(slugOrId, options = {}) {
1858
- const context = useOptionalCimplifyClient();
1859
- const client = options.client ?? context?.client;
1860
- if (!client) {
1861
- throw new Error("useProduct must be used within CimplifyProvider or passed { client }.");
1870
+
1871
+ // src/react/hooks/use-categories.ts
1872
+ var categoriesQuery = createCachedQuery({
1873
+ name: "useCategories",
1874
+ key: (client) => client.getPublicKey() || "__demo__",
1875
+ fetch: async (client) => {
1876
+ const result = await client.catalogue.getCategories();
1877
+ if (!result.ok) throw result.error;
1878
+ return result.value;
1862
1879
  }
1863
- const enabled = options.enabled ?? true;
1864
- const locationId = client.getLocationId();
1865
- const previousLocationIdRef = useRef(locationId);
1866
- const requestIdRef = useRef(0);
1867
- const trackedProductRef = useRef(null);
1868
- const normalizedSlugOrId = useMemo(() => (slugOrId || "").trim(), [slugOrId]);
1869
- const cacheKey = useMemo(
1870
- () => buildProductCacheKey(client, locationId, normalizedSlugOrId),
1871
- [client, locationId, normalizedSlugOrId]
1872
- );
1873
- const cached = productCache.get(cacheKey);
1874
- const [product, setProduct] = useState(cached?.product ?? null);
1875
- const [isLoading, setIsLoading] = useState(
1876
- enabled && normalizedSlugOrId.length > 0 && !cached
1877
- );
1878
- const [error, setError] = useState(null);
1879
- useEffect(() => {
1880
- if (previousLocationIdRef.current !== locationId) {
1881
- productCache.clear();
1882
- productInflight.clear();
1883
- previousLocationIdRef.current = locationId;
1884
- }
1885
- }, [locationId]);
1886
- const load = useCallback(
1887
- async (force = false) => {
1888
- if (!enabled || normalizedSlugOrId.length === 0) {
1889
- setProduct(null);
1890
- setIsLoading(false);
1891
- return;
1892
- }
1893
- const nextRequestId = ++requestIdRef.current;
1894
- setError(null);
1895
- if (!force) {
1896
- const cacheEntry = productCache.get(cacheKey);
1897
- if (cacheEntry) {
1898
- setProduct(cacheEntry.product);
1899
- setIsLoading(false);
1900
- return;
1901
- }
1902
- }
1903
- setIsLoading(true);
1904
- try {
1905
- const existing = productInflight.get(cacheKey);
1906
- const promise = existing ?? (async () => {
1907
- const result = isLikelySlug(normalizedSlugOrId) ? await client.catalogue.getProductBySlug(normalizedSlugOrId) : await client.catalogue.getProduct(normalizedSlugOrId);
1908
- if (!result.ok) {
1909
- throw result.error;
1910
- }
1911
- return result.value;
1912
- })();
1913
- if (!existing) {
1914
- productInflight.set(
1915
- cacheKey,
1916
- promise.finally(() => {
1917
- productInflight.delete(cacheKey);
1918
- })
1919
- );
1920
- }
1921
- const value = await promise;
1922
- productCache.set(cacheKey, { product: value });
1923
- if (nextRequestId === requestIdRef.current) {
1924
- setProduct(value);
1925
- setError(null);
1926
- if (value && trackedProductRef.current !== value.id) {
1927
- trackedProductRef.current = value.id;
1928
- client.activity.trackProductView(value.id, {
1929
- productName: value.name,
1930
- categoryId: value.category_id,
1931
- price: String(value.default_price)
1932
- });
1933
- }
1934
- }
1935
- } catch (loadError) {
1936
- if (nextRequestId === requestIdRef.current) {
1937
- setError(loadError);
1938
- }
1939
- } finally {
1940
- if (nextRequestId === requestIdRef.current) {
1941
- setIsLoading(false);
1942
- }
1943
- }
1944
- },
1945
- [cacheKey, client, enabled, normalizedSlugOrId]
1946
- );
1947
- useEffect(() => {
1948
- void load(false);
1949
- }, [load]);
1950
- const refetch = useCallback(async () => {
1951
- productCache.delete(cacheKey);
1952
- await load(true);
1953
- }, [cacheKey, load]);
1954
- return { product, isLoading, error, refetch };
1955
- }
1956
- var categoriesCache = /* @__PURE__ */ new Map();
1957
- var categoriesInflight = /* @__PURE__ */ new Map();
1958
- function buildCategoriesCacheKey(client) {
1959
- return client.getPublicKey() || "__demo__";
1960
- }
1880
+ });
1961
1881
  function useCategories(options = {}) {
1962
- const context = useOptionalCimplifyClient();
1963
- const client = options.client ?? context?.client;
1964
- if (!client) {
1965
- throw new Error("useCategories must be used within CimplifyProvider or passed { client }.");
1966
- }
1967
- const enabled = options.enabled ?? true;
1968
- const cacheKey = useMemo(() => buildCategoriesCacheKey(client), [client]);
1969
- const cached = categoriesCache.get(cacheKey);
1970
- const [categories, setCategories] = useState(cached ?? []);
1971
- const [isLoading, setIsLoading] = useState(enabled && !cached);
1972
- const [error, setError] = useState(null);
1973
- const load = useCallback(
1974
- async (force = false) => {
1975
- if (!enabled) {
1976
- setIsLoading(false);
1977
- return;
1978
- }
1979
- setError(null);
1980
- if (!force) {
1981
- const cachedCategories = categoriesCache.get(cacheKey);
1982
- if (cachedCategories) {
1983
- setCategories(cachedCategories);
1984
- setIsLoading(false);
1985
- return;
1986
- }
1987
- }
1988
- setIsLoading(true);
1989
- try {
1990
- const existing = categoriesInflight.get(cacheKey);
1991
- const promise = existing ?? (async () => {
1992
- const result = await client.catalogue.getCategories();
1993
- if (!result.ok) {
1994
- throw result.error;
1995
- }
1996
- return result.value;
1997
- })();
1998
- if (!existing) {
1999
- categoriesInflight.set(
2000
- cacheKey,
2001
- promise.finally(() => {
2002
- categoriesInflight.delete(cacheKey);
2003
- })
2004
- );
2005
- }
2006
- const value = await promise;
2007
- categoriesCache.set(cacheKey, value);
2008
- setCategories(value);
2009
- } catch (loadError) {
2010
- setError(loadError);
2011
- } finally {
2012
- setIsLoading(false);
2013
- }
2014
- },
2015
- [cacheKey, client, enabled]
2016
- );
2017
- useEffect(() => {
2018
- void load(false);
2019
- }, [load]);
2020
- const refetch = useCallback(async () => {
2021
- categoriesCache.delete(cacheKey);
2022
- await load(true);
2023
- }, [cacheKey, load]);
2024
- return { categories, isLoading, error, refetch };
1882
+ const { data, isLoading, error, refetch } = categoriesQuery(options);
1883
+ return { categories: data ?? [], isLoading, error, refetch };
2025
1884
  }
2026
1885
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "cancelled", "refunded"]);
2027
1886
  var orderCache = /* @__PURE__ */ new Map();
@@ -2043,11 +1902,11 @@ function useOrder(orderId, options = {}) {
2043
1902
  const previousStatusRef = useRef(null);
2044
1903
  const onStatusChangeRef = useRef(options.onStatusChange);
2045
1904
  onStatusChangeRef.current = options.onStatusChange;
2046
- const cacheKey = useMemo(
1905
+ const cacheKey2 = useMemo(
2047
1906
  () => buildOrderCacheKey(client, normalizedOrderId),
2048
1907
  [client, normalizedOrderId]
2049
1908
  );
2050
- const cached = orderCache.get(cacheKey);
1909
+ const cached = orderCache.get(cacheKey2);
2051
1910
  const [order, setOrder] = useState(cached?.order ?? null);
2052
1911
  const [isLoading, setIsLoading] = useState(
2053
1912
  enabled && normalizedOrderId.length > 0 && !cached
@@ -2063,7 +1922,7 @@ function useOrder(orderId, options = {}) {
2063
1922
  const nextRequestId = ++requestIdRef.current;
2064
1923
  setError(null);
2065
1924
  if (!force) {
2066
- const cacheEntry = orderCache.get(cacheKey);
1925
+ const cacheEntry = orderCache.get(cacheKey2);
2067
1926
  if (cacheEntry) {
2068
1927
  setOrder(cacheEntry.order);
2069
1928
  setIsLoading(false);
@@ -2072,7 +1931,7 @@ function useOrder(orderId, options = {}) {
2072
1931
  }
2073
1932
  setIsLoading(true);
2074
1933
  try {
2075
- const existing = orderInflight.get(cacheKey);
1934
+ const existing = orderInflight.get(cacheKey2);
2076
1935
  const promise = existing ?? (async () => {
2077
1936
  const result = await client.orders.get(normalizedOrderId);
2078
1937
  if (!result.ok) {
@@ -2082,14 +1941,14 @@ function useOrder(orderId, options = {}) {
2082
1941
  })();
2083
1942
  if (!existing) {
2084
1943
  orderInflight.set(
2085
- cacheKey,
1944
+ cacheKey2,
2086
1945
  promise.finally(() => {
2087
- orderInflight.delete(cacheKey);
1946
+ orderInflight.delete(cacheKey2);
2088
1947
  })
2089
1948
  );
2090
1949
  }
2091
1950
  const value = await promise;
2092
- orderCache.set(cacheKey, { order: value });
1951
+ orderCache.set(cacheKey2, { order: value });
2093
1952
  if (nextRequestId === requestIdRef.current) {
2094
1953
  setOrder(value);
2095
1954
  setError(null);
@@ -2110,7 +1969,7 @@ function useOrder(orderId, options = {}) {
2110
1969
  }
2111
1970
  }
2112
1971
  },
2113
- [cacheKey, client, enabled, normalizedOrderId]
1972
+ [cacheKey2, client, enabled, normalizedOrderId]
2114
1973
  );
2115
1974
  useEffect(() => {
2116
1975
  void load(false);
@@ -2128,9 +1987,9 @@ function useOrder(orderId, options = {}) {
2128
1987
  };
2129
1988
  }, [enabled, isTerminal, load, normalizedOrderId, poll, pollInterval]);
2130
1989
  const refetch = useCallback(async () => {
2131
- orderCache.delete(cacheKey);
1990
+ orderCache.delete(cacheKey2);
2132
1991
  await load(true);
2133
- }, [cacheKey, load]);
1992
+ }, [cacheKey2, load]);
2134
1993
  return { order, isLoading, error, refetch, isTerminal };
2135
1994
  }
2136
1995
  var LOCATION_STORAGE_KEY2 = "cimplify_location_id";
@@ -2233,216 +2092,64 @@ function useLocations(options = {}) {
2233
2092
  isLoading
2234
2093
  };
2235
2094
  }
2236
- var collectionsCache = /* @__PURE__ */ new Map();
2237
- var collectionsInflight = /* @__PURE__ */ new Map();
2238
- function buildCollectionsCacheKey(client, locationId) {
2239
- return JSON.stringify({
2240
- key: client.getPublicKey(),
2241
- location_id: locationId || "__none__"
2095
+
2096
+ // src/react/hooks/use-collections.ts
2097
+ var collectionsQuery = createCachedQuery({
2098
+ name: "useCollections",
2099
+ locationSensitive: true,
2100
+ key: (client) => cacheKey(client.getPublicKey(), client.getLocationId()),
2101
+ fetch: async (client) => {
2102
+ const result = await client.catalogue.getCollections();
2103
+ if (!result.ok) throw result.error;
2104
+ return result.value;
2105
+ }
2106
+ });
2107
+ function useCollections(options = {}) {
2108
+ const { data, isLoading, error, refetch } = collectionsQuery(options);
2109
+ return { collections: data ?? [], isLoading, error, refetch };
2110
+ }
2111
+
2112
+ // src/react/hooks/use-collection.ts
2113
+ function isLikelySlug2(value) {
2114
+ return /^[a-z0-9-]+$/.test(value);
2115
+ }
2116
+ var collectionQuery = createCachedQuery({
2117
+ name: "useCollection",
2118
+ locationSensitive: true,
2119
+ key: (client, options) => cacheKey(client.getPublicKey(), client.getLocationId(), options.idOrSlug),
2120
+ fetch: async (client, options) => {
2121
+ const collectionResult = isLikelySlug2(options.idOrSlug) ? await client.catalogue.getCollectionBySlug(options.idOrSlug) : await client.catalogue.getCollection(options.idOrSlug);
2122
+ if (!collectionResult.ok) throw collectionResult.error;
2123
+ const productsResult = await client.catalogue.getCollectionProducts(
2124
+ collectionResult.value.id
2125
+ );
2126
+ if (!productsResult.ok) throw productsResult.error;
2127
+ return {
2128
+ collection: collectionResult.value,
2129
+ products: productsResult.value
2130
+ };
2131
+ }
2132
+ });
2133
+ function useCollection(idOrSlug, options = {}) {
2134
+ const normalized = (idOrSlug || "").trim();
2135
+ const { data, isLoading, error, refetch } = collectionQuery({
2136
+ ...options,
2137
+ idOrSlug: normalized,
2138
+ enabled: (options.enabled ?? true) && normalized.length > 0
2242
2139
  });
2140
+ return {
2141
+ collection: data?.collection ?? null,
2142
+ products: data?.products ?? [],
2143
+ isLoading,
2144
+ error,
2145
+ refetch
2146
+ };
2243
2147
  }
2244
- function useCollections(options = {}) {
2148
+ function useSearch(options = {}) {
2245
2149
  const context = useOptionalCimplifyClient();
2246
2150
  const client = options.client ?? context?.client;
2247
2151
  if (!client) {
2248
- throw new Error("useCollections must be used within CimplifyProvider or passed { client }.");
2249
- }
2250
- const enabled = options.enabled ?? true;
2251
- const locationId = client.getLocationId();
2252
- const previousLocationIdRef = useRef(locationId);
2253
- const requestIdRef = useRef(0);
2254
- const cacheKey = useMemo(
2255
- () => buildCollectionsCacheKey(client, locationId),
2256
- [client, locationId]
2257
- );
2258
- const cached = collectionsCache.get(cacheKey);
2259
- const [collections, setCollections] = useState(cached?.collections ?? []);
2260
- const [isLoading, setIsLoading] = useState(enabled && !cached);
2261
- const [error, setError] = useState(null);
2262
- useEffect(() => {
2263
- if (previousLocationIdRef.current !== locationId) {
2264
- collectionsCache.clear();
2265
- collectionsInflight.clear();
2266
- previousLocationIdRef.current = locationId;
2267
- }
2268
- }, [locationId]);
2269
- const load = useCallback(
2270
- async (force = false) => {
2271
- if (!enabled) {
2272
- setIsLoading(false);
2273
- return;
2274
- }
2275
- const nextRequestId = ++requestIdRef.current;
2276
- setError(null);
2277
- if (!force) {
2278
- const cacheEntry = collectionsCache.get(cacheKey);
2279
- if (cacheEntry) {
2280
- setCollections(cacheEntry.collections);
2281
- setIsLoading(false);
2282
- return;
2283
- }
2284
- }
2285
- setIsLoading(true);
2286
- try {
2287
- const existing = collectionsInflight.get(cacheKey);
2288
- const promise = existing ?? (async () => {
2289
- const result = await client.catalogue.getCollections();
2290
- if (!result.ok) {
2291
- throw result.error;
2292
- }
2293
- return result.value;
2294
- })();
2295
- if (!existing) {
2296
- collectionsInflight.set(cacheKey, promise);
2297
- promise.finally(() => {
2298
- collectionsInflight.delete(cacheKey);
2299
- }).catch(() => void 0);
2300
- }
2301
- const value = await promise;
2302
- collectionsCache.set(cacheKey, { collections: value });
2303
- if (nextRequestId === requestIdRef.current) {
2304
- setCollections(value);
2305
- setError(null);
2306
- }
2307
- } catch (loadError) {
2308
- if (nextRequestId === requestIdRef.current) {
2309
- setError(loadError);
2310
- }
2311
- } finally {
2312
- if (nextRequestId === requestIdRef.current) {
2313
- setIsLoading(false);
2314
- }
2315
- }
2316
- },
2317
- [cacheKey, client, enabled]
2318
- );
2319
- useEffect(() => {
2320
- void load(false);
2321
- }, [load]);
2322
- const refetch = useCallback(async () => {
2323
- collectionsCache.delete(cacheKey);
2324
- await load(true);
2325
- }, [cacheKey, load]);
2326
- return { collections, isLoading, error, refetch };
2327
- }
2328
- var collectionCache = /* @__PURE__ */ new Map();
2329
- var collectionInflight = /* @__PURE__ */ new Map();
2330
- function isLikelySlug2(value) {
2331
- return /^[a-z0-9-]+$/.test(value);
2332
- }
2333
- function buildCollectionCacheKey(client, locationId, idOrSlug) {
2334
- return JSON.stringify({
2335
- key: client.getPublicKey(),
2336
- location_id: locationId || "__none__",
2337
- collection: idOrSlug
2338
- });
2339
- }
2340
- function useCollection(idOrSlug, options = {}) {
2341
- const context = useOptionalCimplifyClient();
2342
- const client = options.client ?? context?.client;
2343
- if (!client) {
2344
- throw new Error("useCollection must be used within CimplifyProvider or passed { client }.");
2345
- }
2346
- const enabled = options.enabled ?? true;
2347
- const locationId = client.getLocationId();
2348
- const previousLocationIdRef = useRef(locationId);
2349
- const requestIdRef = useRef(0);
2350
- const normalizedIdOrSlug = useMemo(() => (idOrSlug || "").trim(), [idOrSlug]);
2351
- const cacheKey = useMemo(
2352
- () => buildCollectionCacheKey(client, locationId, normalizedIdOrSlug),
2353
- [client, locationId, normalizedIdOrSlug]
2354
- );
2355
- const cached = collectionCache.get(cacheKey);
2356
- const [collection, setCollection] = useState(cached?.collection ?? null);
2357
- const [products, setProducts] = useState(cached?.products ?? []);
2358
- const [isLoading, setIsLoading] = useState(
2359
- enabled && normalizedIdOrSlug.length > 0 && !cached
2360
- );
2361
- const [error, setError] = useState(null);
2362
- useEffect(() => {
2363
- if (previousLocationIdRef.current !== locationId) {
2364
- collectionCache.clear();
2365
- collectionInflight.clear();
2366
- previousLocationIdRef.current = locationId;
2367
- }
2368
- }, [locationId]);
2369
- const load = useCallback(
2370
- async (force = false) => {
2371
- if (!enabled || normalizedIdOrSlug.length === 0) {
2372
- setCollection(null);
2373
- setProducts([]);
2374
- setIsLoading(false);
2375
- return;
2376
- }
2377
- const nextRequestId = ++requestIdRef.current;
2378
- setError(null);
2379
- if (!force) {
2380
- const cacheEntry = collectionCache.get(cacheKey);
2381
- if (cacheEntry) {
2382
- setCollection(cacheEntry.collection);
2383
- setProducts(cacheEntry.products);
2384
- setIsLoading(false);
2385
- return;
2386
- }
2387
- }
2388
- setIsLoading(true);
2389
- try {
2390
- const existing = collectionInflight.get(cacheKey);
2391
- const promise = existing ?? (async () => {
2392
- const collectionResult = isLikelySlug2(normalizedIdOrSlug) ? await client.catalogue.getCollectionBySlug(normalizedIdOrSlug) : await client.catalogue.getCollection(normalizedIdOrSlug);
2393
- if (!collectionResult.ok) {
2394
- throw collectionResult.error;
2395
- }
2396
- const productsResult = await client.catalogue.getCollectionProducts(
2397
- collectionResult.value.id
2398
- );
2399
- if (!productsResult.ok) {
2400
- throw productsResult.error;
2401
- }
2402
- return {
2403
- collection: collectionResult.value,
2404
- products: productsResult.value
2405
- };
2406
- })();
2407
- if (!existing) {
2408
- collectionInflight.set(cacheKey, promise);
2409
- promise.finally(() => {
2410
- collectionInflight.delete(cacheKey);
2411
- }).catch(() => void 0);
2412
- }
2413
- const value = await promise;
2414
- collectionCache.set(cacheKey, value);
2415
- if (nextRequestId === requestIdRef.current) {
2416
- setCollection(value.collection);
2417
- setProducts(value.products);
2418
- setError(null);
2419
- }
2420
- } catch (loadError) {
2421
- if (nextRequestId === requestIdRef.current) {
2422
- setError(loadError);
2423
- }
2424
- } finally {
2425
- if (nextRequestId === requestIdRef.current) {
2426
- setIsLoading(false);
2427
- }
2428
- }
2429
- },
2430
- [cacheKey, client, enabled, normalizedIdOrSlug]
2431
- );
2432
- useEffect(() => {
2433
- void load(false);
2434
- }, [load]);
2435
- const refetch = useCallback(async () => {
2436
- collectionCache.delete(cacheKey);
2437
- await load(true);
2438
- }, [cacheKey, load]);
2439
- return { collection, products, isLoading, error, refetch };
2440
- }
2441
- function useSearch(options = {}) {
2442
- const context = useOptionalCimplifyClient();
2443
- const client = options.client ?? context?.client;
2444
- if (!client) {
2445
- throw new Error("useSearch must be used within CimplifyProvider or passed { client }.");
2152
+ throw new Error("useSearch must be used within CimplifyProvider or passed { client }.");
2446
2153
  }
2447
2154
  const minLength = Math.max(0, options.minLength ?? 2);
2448
2155
  const debounceMs = Math.max(0, options.debounceMs ?? 300);
@@ -2613,11 +2320,11 @@ function useQuote(input, options = {}) {
2613
2320
  const normalized = normalizeInput(input, locationId);
2614
2321
  return normalized.product_id.length > 0 ? normalized : null;
2615
2322
  }, [inputSignature, locationId]);
2616
- const cacheKey = useMemo(
2323
+ const cacheKey2 = useMemo(
2617
2324
  () => buildQuoteCacheKey(client, locationId, inputSignature),
2618
2325
  [client, inputSignature, locationId]
2619
2326
  );
2620
- const cached = quoteCache.get(cacheKey);
2327
+ const cached = quoteCache.get(cacheKey2);
2621
2328
  const [quote, setQuote] = useState(cached?.quote ?? null);
2622
2329
  const [isLoading, setIsLoading] = useState(enabled && normalizedInput !== null && !cached);
2623
2330
  const [error, setError] = useState(null);
@@ -2643,7 +2350,7 @@ function useQuote(input, options = {}) {
2643
2350
  const nextRequestId = ++requestIdRef.current;
2644
2351
  setError(null);
2645
2352
  if (!force) {
2646
- const cacheEntry = quoteCache.get(cacheKey);
2353
+ const cacheEntry = quoteCache.get(cacheKey2);
2647
2354
  if (cacheEntry) {
2648
2355
  setQuote(cacheEntry.quote);
2649
2356
  setMessages(cacheEntry.quote?.ui_messages ?? []);
@@ -2656,7 +2363,7 @@ function useQuote(input, options = {}) {
2656
2363
  setQuote(null);
2657
2364
  setMessages([]);
2658
2365
  try {
2659
- const existing = quoteInflight.get(cacheKey);
2366
+ const existing = quoteInflight.get(cacheKey2);
2660
2367
  const promise = existing ?? (async () => {
2661
2368
  const result = await client.catalogue.fetchQuote(normalizedInput);
2662
2369
  if (!result.ok) {
@@ -2665,13 +2372,13 @@ function useQuote(input, options = {}) {
2665
2372
  return result.value;
2666
2373
  })();
2667
2374
  if (!existing) {
2668
- quoteInflight.set(cacheKey, promise);
2375
+ quoteInflight.set(cacheKey2, promise);
2669
2376
  promise.finally(() => {
2670
- quoteInflight.delete(cacheKey);
2377
+ quoteInflight.delete(cacheKey2);
2671
2378
  }).catch(() => void 0);
2672
2379
  }
2673
2380
  const value = await promise;
2674
- quoteCache.set(cacheKey, { quote: value });
2381
+ quoteCache.set(cacheKey2, { quote: value });
2675
2382
  if (nextRequestId === requestIdRef.current) {
2676
2383
  setQuote(value);
2677
2384
  setMessages(value.ui_messages ?? []);
@@ -2688,13 +2395,13 @@ function useQuote(input, options = {}) {
2688
2395
  }
2689
2396
  }
2690
2397
  },
2691
- [cacheKey, client, enabled, normalizedInput]
2398
+ [cacheKey2, client, enabled, normalizedInput]
2692
2399
  );
2693
2400
  useEffect(() => {
2694
2401
  if (debounceTimerRef.current) {
2695
2402
  clearTimeout(debounceTimerRef.current);
2696
2403
  }
2697
- const hasCached = quoteCache.has(cacheKey);
2404
+ const hasCached = quoteCache.has(cacheKey2);
2698
2405
  if (hasCached || !enabled || !normalizedInput) {
2699
2406
  void load(false);
2700
2407
  } else {
@@ -2708,7 +2415,7 @@ function useQuote(input, options = {}) {
2708
2415
  debounceTimerRef.current = null;
2709
2416
  }
2710
2417
  };
2711
- }, [load, cacheKey, enabled, normalizedInput]);
2418
+ }, [load, cacheKey2, enabled, normalizedInput]);
2712
2419
  const refresh = useCallback(async () => {
2713
2420
  if (!enabled || !normalizedInput) {
2714
2421
  return;
@@ -2729,7 +2436,7 @@ function useQuote(input, options = {}) {
2729
2436
  throw result.error;
2730
2437
  }
2731
2438
  const refreshed = result.value.quote;
2732
- quoteCache.set(cacheKey, { quote: refreshed });
2439
+ quoteCache.set(cacheKey2, { quote: refreshed });
2733
2440
  if (nextRequestId === requestIdRef.current) {
2734
2441
  setQuote(refreshed);
2735
2442
  setMessages(refreshed.ui_messages ?? []);
@@ -2745,7 +2452,7 @@ function useQuote(input, options = {}) {
2745
2452
  setIsLoading(false);
2746
2453
  }
2747
2454
  }
2748
- }, [cacheKey, client, enabled, load, normalizedInput, quote]);
2455
+ }, [cacheKey2, client, enabled, load, normalizedInput, quote]);
2749
2456
  useEffect(() => {
2750
2457
  if (!Number.isFinite(quoteExpiryTimestamp)) {
2751
2458
  setIsExpired(false);
@@ -2777,1402 +2484,391 @@ function useQuote(input, options = {}) {
2777
2484
  }, [autoRefresh, enabled, quoteExpiryTimestamp, refresh, refreshBeforeExpiryMs]);
2778
2485
  return { quote, isLoading, error, refresh, isExpired, messages };
2779
2486
  }
2780
- var taxonomiesCache = /* @__PURE__ */ new Map();
2781
- var taxonomiesInflight = /* @__PURE__ */ new Map();
2782
- function buildTaxonomiesCacheKey(client, parentId) {
2783
- return JSON.stringify({
2784
- key: client.getPublicKey(),
2785
- parent_id: parentId || "__root__"
2786
- });
2787
- }
2487
+
2488
+ // src/react/hooks/use-taxonomies.ts
2489
+ var taxonomiesQuery = createCachedQuery({
2490
+ name: "useTaxonomies",
2491
+ key: (client, options) => cacheKey(client.getPublicKey(), options.parentId ?? "__root__"),
2492
+ fetch: async (client, options) => {
2493
+ const result = await client.catalogue.getTaxonomies(options.parentId);
2494
+ if (!result.ok) throw result.error;
2495
+ return result.value;
2496
+ }
2497
+ });
2788
2498
  function useTaxonomies(options = {}) {
2499
+ const { data, isLoading, error, refetch } = taxonomiesQuery(options);
2500
+ return { taxonomies: data ?? [], isLoading, error, refetch };
2501
+ }
2502
+
2503
+ // src/react/hooks/use-taxonomy.ts
2504
+ var taxonomyQuery = createCachedQuery({
2505
+ name: "useTaxonomy",
2506
+ key: (client, options) => cacheKey(client.getPublicKey(), options.id),
2507
+ fetch: async (client, options) => {
2508
+ const result = await client.catalogue.getTaxonomy(options.id);
2509
+ if (!result.ok) throw result.error;
2510
+ client.activity.trackCategoryView(result.value.id, {
2511
+ categoryName: result.value.name
2512
+ });
2513
+ return result.value;
2514
+ }
2515
+ });
2516
+ function useTaxonomy(id, options = {}) {
2517
+ const { data, isLoading, error, refetch } = taxonomyQuery({ ...options, id });
2518
+ return { taxonomy: data, isLoading, error, refetch };
2519
+ }
2520
+
2521
+ // src/react/hooks/use-taxonomy-path.ts
2522
+ var taxonomyPathQuery = createCachedQuery({
2523
+ name: "useTaxonomyPath",
2524
+ key: (client, options) => cacheKey(client.getPublicKey(), options.id),
2525
+ fetch: async (client, options) => {
2526
+ const result = await client.catalogue.getTaxonomyPath(options.id);
2527
+ if (!result.ok) throw result.error;
2528
+ return result.value;
2529
+ }
2530
+ });
2531
+ function useTaxonomyPath(id, options = {}) {
2532
+ const { data, isLoading, error, refetch } = taxonomyPathQuery({ ...options, id });
2533
+ return { path: data ?? [], isLoading, error, refetch };
2534
+ }
2535
+
2536
+ // src/react/hooks/use-product-schedules.ts
2537
+ var productSchedulesQuery = createCachedQuery({
2538
+ name: "useProductSchedules",
2539
+ key: (client, options) => cacheKey(client.getPublicKey(), options.productId),
2540
+ fetch: async (client, options) => {
2541
+ const result = await client.catalogue.getProductSchedules(options.productId);
2542
+ if (!result.ok) throw result.error;
2543
+ return result.value;
2544
+ }
2545
+ });
2546
+ function useProductSchedules(productId, options = {}) {
2547
+ const { data, isLoading, error, refetch } = productSchedulesQuery({ ...options, productId });
2548
+ return { schedules: data ?? [], isLoading, error, refetch };
2549
+ }
2550
+
2551
+ // src/react/hooks/use-product-availability.ts
2552
+ var productAvailabilityQuery = createCachedQuery({
2553
+ name: "useProductAvailability",
2554
+ locationSensitive: true,
2555
+ key: (client, options) => {
2556
+ const locationId = options.locationId ?? client.getLocationId();
2557
+ return cacheKey(client.getPublicKey(), options.productId, locationId);
2558
+ },
2559
+ fetch: async (client, options) => {
2560
+ const locationId = options.locationId ?? client.getLocationId();
2561
+ if (!locationId) return null;
2562
+ const result = await client.catalogue.checkProductAvailableNow(options.productId, locationId);
2563
+ if (!result.ok) throw result.error;
2564
+ return result.value;
2565
+ }
2566
+ });
2567
+ function useProductAvailability(productId, options = {}) {
2568
+ const { data, isLoading, error, refetch } = productAvailabilityQuery({ ...options, productId });
2569
+ return {
2570
+ isAvailable: data?.is_available ?? null,
2571
+ schedulesToday: data?.schedules_today ?? [],
2572
+ isLoading,
2573
+ error,
2574
+ refetch
2575
+ };
2576
+ }
2577
+
2578
+ // src/react/hooks/use-deals.ts
2579
+ function resolveLocationId(client, options) {
2580
+ return options.locationId ?? client.getLocationId() ?? void 0;
2581
+ }
2582
+ var dealsQuery = createCachedQuery({
2583
+ name: "useDeals",
2584
+ locationSensitive: true,
2585
+ key: (client, options) => cacheKey(client.getPublicKey(), resolveLocationId(client, options)),
2586
+ fetch: async (client, options) => {
2587
+ const result = await client.catalogue.getDeals(resolveLocationId(client, options));
2588
+ if (!result.ok) throw result.error;
2589
+ return result.value;
2590
+ }
2591
+ });
2592
+ function useDeals(options = {}) {
2593
+ const { data, isLoading, error, refetch } = dealsQuery(options);
2594
+ return { deals: data ?? [], isLoading, error, refetch };
2595
+ }
2596
+
2597
+ // src/react/hooks/use-products-on-sale.ts
2598
+ var productsOnSaleQuery = createCachedQuery({
2599
+ name: "useProductsOnSale",
2600
+ key: (client) => client.getPublicKey() || "__demo__",
2601
+ fetch: async (client) => {
2602
+ const result = await client.catalogue.getProductsOnSale();
2603
+ if (!result.ok) throw result.error;
2604
+ return result.value;
2605
+ }
2606
+ });
2607
+ function useProductsOnSale(options = {}) {
2608
+ const { data, isLoading, error, refetch } = productsOnSaleQuery(options);
2609
+ return { products: data ?? [], isLoading, error, refetch };
2610
+ }
2611
+
2612
+ // src/react/hooks/use-product-deals.ts
2613
+ var productDealsQuery = createCachedQuery({
2614
+ name: "useProductDeals",
2615
+ key: (client, options) => cacheKey(client.getPublicKey(), options.productId),
2616
+ fetch: async (client, options) => {
2617
+ const result = await client.catalogue.getProductDeals(options.productId);
2618
+ if (!result.ok) throw result.error;
2619
+ return result.value;
2620
+ }
2621
+ });
2622
+ function useProductDeals(productId, options = {}) {
2623
+ const { data, isLoading, error, refetch } = productDealsQuery({ ...options, productId });
2624
+ return { deals: data ?? [], isLoading, error, refetch };
2625
+ }
2626
+ function useValidateDiscount(options = {}) {
2789
2627
  const context = useOptionalCimplifyClient();
2790
2628
  const client = options.client ?? context?.client;
2791
2629
  if (!client) {
2792
- throw new Error("useTaxonomies must be used within CimplifyProvider or passed { client }.");
2630
+ throw new Error("useValidateDiscount must be used within CimplifyProvider or passed { client }.");
2793
2631
  }
2794
- const enabled = options.enabled ?? true;
2795
- const cacheKey = useMemo(
2796
- () => buildTaxonomiesCacheKey(client, options.parentId),
2797
- [client, options.parentId]
2798
- );
2799
- const cached = taxonomiesCache.get(cacheKey);
2800
- const [taxonomies, setTaxonomies] = useState(cached ?? []);
2801
- const [isLoading, setIsLoading] = useState(enabled && !cached);
2632
+ const [isValidating, setIsValidating] = useState(false);
2802
2633
  const [error, setError] = useState(null);
2803
- const parentId = options.parentId;
2804
- const load = useCallback(
2805
- async (force = false) => {
2806
- if (!enabled) {
2807
- setIsLoading(false);
2808
- return;
2809
- }
2634
+ const validate = useCallback(
2635
+ async (code, orderSubtotal, locationId) => {
2810
2636
  setError(null);
2811
- if (!force) {
2812
- const cachedTaxonomies = taxonomiesCache.get(cacheKey);
2813
- if (cachedTaxonomies) {
2814
- setTaxonomies(cachedTaxonomies);
2815
- setIsLoading(false);
2816
- return;
2817
- }
2818
- }
2819
- setIsLoading(true);
2637
+ setIsValidating(true);
2820
2638
  try {
2821
- const existing = taxonomiesInflight.get(cacheKey);
2822
- const promise = existing ?? (async () => {
2823
- const result = await client.catalogue.getTaxonomies(parentId);
2824
- if (!result.ok) {
2825
- throw result.error;
2826
- }
2827
- return result.value;
2828
- })();
2829
- if (!existing) {
2830
- taxonomiesInflight.set(
2831
- cacheKey,
2832
- promise.finally(() => {
2833
- taxonomiesInflight.delete(cacheKey);
2834
- })
2835
- );
2639
+ const result = await client.catalogue.validateDiscountCode(code, orderSubtotal, locationId);
2640
+ if (!result.ok) {
2641
+ setError(result.error);
2642
+ return null;
2836
2643
  }
2837
- const value = await promise;
2838
- taxonomiesCache.set(cacheKey, value);
2839
- setTaxonomies(value);
2840
- } catch (loadError) {
2841
- setError(loadError);
2644
+ return result.value;
2645
+ } catch (validateError) {
2646
+ setError(validateError);
2647
+ return null;
2842
2648
  } finally {
2843
- setIsLoading(false);
2649
+ setIsValidating(false);
2844
2650
  }
2845
2651
  },
2846
- [cacheKey, client, enabled, parentId]
2652
+ [client]
2847
2653
  );
2848
- useEffect(() => {
2849
- void load(false);
2850
- }, [load]);
2851
- const refetch = useCallback(async () => {
2852
- taxonomiesCache.delete(cacheKey);
2853
- await load(true);
2854
- }, [cacheKey, load]);
2855
- return { taxonomies, isLoading, error, refetch };
2856
- }
2857
- var taxonomyCache = /* @__PURE__ */ new Map();
2858
- var taxonomyInflight = /* @__PURE__ */ new Map();
2859
- function buildTaxonomyCacheKey(client, id) {
2860
- return JSON.stringify({
2861
- key: client.getPublicKey(),
2862
- id
2863
- });
2654
+ return { validate, isValidating, error };
2864
2655
  }
2865
- function useTaxonomy(id, options = {}) {
2866
- const context = useOptionalCimplifyClient();
2867
- const client = options.client ?? context?.client;
2868
- if (!client) {
2869
- throw new Error("useTaxonomy must be used within CimplifyProvider or passed { client }.");
2656
+
2657
+ // src/react/hooks/use-bundles.ts
2658
+ var bundlesQuery = createCachedQuery({
2659
+ name: "useBundles",
2660
+ locationSensitive: true,
2661
+ key: (client) => cacheKey(client.getPublicKey(), client.getLocationId()),
2662
+ fetch: async (client) => {
2663
+ const result = await client.catalogue.getBundles();
2664
+ if (!result.ok) throw result.error;
2665
+ return result.value;
2870
2666
  }
2871
- const enabled = options.enabled ?? true;
2872
- const cacheKey = useMemo(() => buildTaxonomyCacheKey(client, id), [client, id]);
2873
- const cached = taxonomyCache.get(cacheKey);
2874
- const [taxonomy, setTaxonomy] = useState(cached ?? null);
2875
- const [isLoading, setIsLoading] = useState(enabled && !cached);
2876
- const [error, setError] = useState(null);
2877
- const trackedTaxonomyRef = useRef(null);
2878
- const load = useCallback(
2879
- async (force = false) => {
2880
- if (!enabled) {
2881
- setIsLoading(false);
2882
- return;
2883
- }
2884
- setError(null);
2885
- if (!force) {
2886
- const cachedTaxonomy = taxonomyCache.get(cacheKey);
2887
- if (cachedTaxonomy) {
2888
- setTaxonomy(cachedTaxonomy);
2889
- setIsLoading(false);
2890
- return;
2891
- }
2892
- }
2893
- setIsLoading(true);
2894
- try {
2895
- const existing = taxonomyInflight.get(cacheKey);
2896
- const promise = existing ?? (async () => {
2897
- const result = await client.catalogue.getTaxonomy(id);
2898
- if (!result.ok) {
2899
- throw result.error;
2900
- }
2901
- return result.value;
2902
- })();
2903
- if (!existing) {
2904
- taxonomyInflight.set(
2905
- cacheKey,
2906
- promise.finally(() => {
2907
- taxonomyInflight.delete(cacheKey);
2908
- })
2909
- );
2910
- }
2911
- const value = await promise;
2912
- taxonomyCache.set(cacheKey, value);
2913
- setTaxonomy(value);
2914
- if (value && trackedTaxonomyRef.current !== value.id) {
2915
- trackedTaxonomyRef.current = value.id;
2916
- client.activity.trackCategoryView(value.id, {
2917
- categoryName: value.name
2918
- });
2919
- }
2920
- } catch (loadError) {
2921
- setError(loadError);
2922
- } finally {
2923
- setIsLoading(false);
2924
- }
2925
- },
2926
- [cacheKey, client, enabled, id]
2927
- );
2928
- useEffect(() => {
2929
- void load(false);
2930
- }, [load]);
2931
- const refetch = useCallback(async () => {
2932
- taxonomyCache.delete(cacheKey);
2933
- await load(true);
2934
- }, [cacheKey, load]);
2935
- return { taxonomy, isLoading, error, refetch };
2936
- }
2937
- var taxonomyPathCache = /* @__PURE__ */ new Map();
2938
- var taxonomyPathInflight = /* @__PURE__ */ new Map();
2939
- function buildTaxonomyPathCacheKey(client, id) {
2940
- return JSON.stringify({
2941
- key: client.getPublicKey(),
2942
- id
2943
- });
2944
- }
2945
- function useTaxonomyPath(id, options = {}) {
2946
- const context = useOptionalCimplifyClient();
2947
- const client = options.client ?? context?.client;
2948
- if (!client) {
2949
- throw new Error("useTaxonomyPath must be used within CimplifyProvider or passed { client }.");
2950
- }
2951
- const enabled = options.enabled ?? true;
2952
- const cacheKey = useMemo(() => buildTaxonomyPathCacheKey(client, id), [client, id]);
2953
- const cached = taxonomyPathCache.get(cacheKey);
2954
- const [path, setPath] = useState(cached ?? []);
2955
- const [isLoading, setIsLoading] = useState(enabled && !cached);
2956
- const [error, setError] = useState(null);
2957
- const load = useCallback(
2958
- async (force = false) => {
2959
- if (!enabled) {
2960
- setIsLoading(false);
2961
- return;
2962
- }
2963
- setError(null);
2964
- if (!force) {
2965
- const cachedPath = taxonomyPathCache.get(cacheKey);
2966
- if (cachedPath) {
2967
- setPath(cachedPath);
2968
- setIsLoading(false);
2969
- return;
2970
- }
2971
- }
2972
- setIsLoading(true);
2973
- try {
2974
- const existing = taxonomyPathInflight.get(cacheKey);
2975
- const promise = existing ?? (async () => {
2976
- const result = await client.catalogue.getTaxonomyPath(id);
2977
- if (!result.ok) {
2978
- throw result.error;
2979
- }
2980
- return result.value;
2981
- })();
2982
- if (!existing) {
2983
- taxonomyPathInflight.set(
2984
- cacheKey,
2985
- promise.finally(() => {
2986
- taxonomyPathInflight.delete(cacheKey);
2987
- })
2988
- );
2989
- }
2990
- const value = await promise;
2991
- taxonomyPathCache.set(cacheKey, value);
2992
- setPath(value);
2993
- } catch (loadError) {
2994
- setError(loadError);
2995
- } finally {
2996
- setIsLoading(false);
2997
- }
2998
- },
2999
- [cacheKey, client, enabled, id]
3000
- );
3001
- useEffect(() => {
3002
- void load(false);
3003
- }, [load]);
3004
- const refetch = useCallback(async () => {
3005
- taxonomyPathCache.delete(cacheKey);
3006
- await load(true);
3007
- }, [cacheKey, load]);
3008
- return { path, isLoading, error, refetch };
3009
- }
3010
- var schedulesCache = /* @__PURE__ */ new Map();
3011
- var schedulesInflight = /* @__PURE__ */ new Map();
3012
- function buildSchedulesCacheKey(client, productId) {
3013
- return JSON.stringify({
3014
- key: client.getPublicKey(),
3015
- product_id: productId
3016
- });
3017
- }
3018
- function useProductSchedules(productId, options = {}) {
3019
- const context = useOptionalCimplifyClient();
3020
- const client = options.client ?? context?.client;
3021
- if (!client) {
3022
- throw new Error("useProductSchedules must be used within CimplifyProvider or passed { client }.");
3023
- }
3024
- const enabled = options.enabled ?? true;
3025
- const cacheKey = useMemo(() => buildSchedulesCacheKey(client, productId), [client, productId]);
3026
- const cached = schedulesCache.get(cacheKey);
3027
- const [schedules, setSchedules] = useState(cached ?? []);
3028
- const [isLoading, setIsLoading] = useState(enabled && !cached);
3029
- const [error, setError] = useState(null);
3030
- const load = useCallback(
3031
- async (force = false) => {
3032
- if (!enabled) {
3033
- setIsLoading(false);
3034
- return;
3035
- }
3036
- setError(null);
3037
- if (!force) {
3038
- const cachedSchedules = schedulesCache.get(cacheKey);
3039
- if (cachedSchedules) {
3040
- setSchedules(cachedSchedules);
3041
- setIsLoading(false);
3042
- return;
3043
- }
3044
- }
3045
- setIsLoading(true);
3046
- try {
3047
- const existing = schedulesInflight.get(cacheKey);
3048
- const promise = existing ?? (async () => {
3049
- const result = await client.catalogue.getProductSchedules(productId);
3050
- if (!result.ok) {
3051
- throw result.error;
3052
- }
3053
- return result.value;
3054
- })();
3055
- if (!existing) {
3056
- schedulesInflight.set(
3057
- cacheKey,
3058
- promise.finally(() => {
3059
- schedulesInflight.delete(cacheKey);
3060
- })
3061
- );
3062
- }
3063
- const value = await promise;
3064
- schedulesCache.set(cacheKey, value);
3065
- setSchedules(value);
3066
- } catch (loadError) {
3067
- setError(loadError);
3068
- } finally {
3069
- setIsLoading(false);
3070
- }
3071
- },
3072
- [cacheKey, client, enabled, productId]
3073
- );
3074
- useEffect(() => {
3075
- void load(false);
3076
- }, [load]);
3077
- const refetch = useCallback(async () => {
3078
- schedulesCache.delete(cacheKey);
3079
- await load(true);
3080
- }, [cacheKey, load]);
3081
- return { schedules, isLoading, error, refetch };
3082
- }
3083
- var availabilityCache = /* @__PURE__ */ new Map();
3084
- var availabilityInflight = /* @__PURE__ */ new Map();
3085
- function buildAvailabilityCacheKey(client, productId, locationId) {
3086
- return JSON.stringify({
3087
- key: client.getPublicKey(),
3088
- product_id: productId,
3089
- location_id: locationId
3090
- });
3091
- }
3092
- function useProductAvailability(productId, options = {}) {
3093
- const context = useOptionalCimplifyClient();
3094
- const client = options.client ?? context?.client;
3095
- if (!client) {
3096
- throw new Error("useProductAvailability must be used within CimplifyProvider or passed { client }.");
3097
- }
3098
- const enabled = options.enabled ?? true;
3099
- const locationId = options.locationId ?? client.getLocationId();
3100
- const previousLocationIdRef = useRef(locationId);
3101
- const cacheKey = useMemo(
3102
- () => locationId ? buildAvailabilityCacheKey(client, productId, locationId) : null,
3103
- [client, productId, locationId]
3104
- );
3105
- const cached = cacheKey ? availabilityCache.get(cacheKey) : void 0;
3106
- const [isAvailable, setIsAvailable] = useState(cached?.is_available ?? null);
3107
- const [schedulesToday, setSchedulesToday] = useState(
3108
- cached?.schedules_today ?? []
3109
- );
3110
- const [isLoading, setIsLoading] = useState(enabled && !cached && !!locationId);
3111
- const [error, setError] = useState(null);
3112
- useEffect(() => {
3113
- if (previousLocationIdRef.current !== locationId) {
3114
- availabilityCache.clear();
3115
- availabilityInflight.clear();
3116
- previousLocationIdRef.current = locationId;
3117
- }
3118
- }, [locationId]);
3119
- const load = useCallback(
3120
- async (force = false) => {
3121
- if (!enabled || !locationId || !cacheKey) {
3122
- setIsLoading(false);
3123
- return;
3124
- }
3125
- setError(null);
3126
- if (!force) {
3127
- const cachedAvailability = availabilityCache.get(cacheKey);
3128
- if (cachedAvailability) {
3129
- setIsAvailable(cachedAvailability.is_available);
3130
- setSchedulesToday(cachedAvailability.schedules_today);
3131
- setIsLoading(false);
3132
- return;
3133
- }
3134
- }
3135
- setIsLoading(true);
3136
- try {
3137
- const existing = availabilityInflight.get(cacheKey);
3138
- const promise = existing ?? (async () => {
3139
- const result = await client.catalogue.checkProductAvailableNow(productId, locationId);
3140
- if (!result.ok) {
3141
- throw result.error;
3142
- }
3143
- return result.value;
3144
- })();
3145
- if (!existing) {
3146
- availabilityInflight.set(
3147
- cacheKey,
3148
- promise.finally(() => {
3149
- availabilityInflight.delete(cacheKey);
3150
- })
3151
- );
3152
- }
3153
- const value = await promise;
3154
- availabilityCache.set(cacheKey, value);
3155
- setIsAvailable(value.is_available);
3156
- setSchedulesToday(value.schedules_today);
3157
- } catch (loadError) {
3158
- setError(loadError);
3159
- } finally {
3160
- setIsLoading(false);
3161
- }
3162
- },
3163
- [cacheKey, client, enabled, locationId, productId]
3164
- );
3165
- useEffect(() => {
3166
- void load(false);
3167
- }, [load]);
3168
- const refetch = useCallback(async () => {
3169
- if (cacheKey) {
3170
- availabilityCache.delete(cacheKey);
3171
- }
3172
- await load(true);
3173
- }, [cacheKey, load]);
3174
- return { isAvailable, schedulesToday, isLoading, error, refetch };
3175
- }
3176
- var dealsCache = /* @__PURE__ */ new Map();
3177
- var dealsInflight = /* @__PURE__ */ new Map();
3178
- function buildDealsCacheKey(client, locationId) {
3179
- return JSON.stringify({ key: client.getPublicKey(), location_id: locationId });
3180
- }
3181
- function useDeals(options = {}) {
3182
- const context = useOptionalCimplifyClient();
3183
- const client = options.client ?? context?.client;
3184
- if (!client) {
3185
- throw new Error("useDeals must be used within CimplifyProvider or passed { client }.");
3186
- }
3187
- const enabled = options.enabled ?? true;
3188
- const locationId = options.locationId ?? client.getLocationId() ?? void 0;
3189
- const previousLocationIdRef = useRef(locationId);
3190
- const cacheKey = useMemo(() => buildDealsCacheKey(client, locationId), [client, locationId]);
3191
- const cached = dealsCache.get(cacheKey);
3192
- const [deals, setDeals] = useState(cached ?? []);
3193
- const [isLoading, setIsLoading] = useState(enabled && !cached);
3194
- const [error, setError] = useState(null);
3195
- useEffect(() => {
3196
- if (previousLocationIdRef.current !== locationId) {
3197
- dealsCache.clear();
3198
- dealsInflight.clear();
3199
- previousLocationIdRef.current = locationId;
3200
- }
3201
- }, [locationId]);
3202
- const load = useCallback(
3203
- async (force = false) => {
3204
- if (!enabled) {
3205
- setIsLoading(false);
3206
- return;
3207
- }
3208
- setError(null);
3209
- if (!force) {
3210
- const cachedDeals = dealsCache.get(cacheKey);
3211
- if (cachedDeals) {
3212
- setDeals(cachedDeals);
3213
- setIsLoading(false);
3214
- return;
3215
- }
3216
- }
3217
- setIsLoading(true);
3218
- try {
3219
- const existing = dealsInflight.get(cacheKey);
3220
- const promise = existing ?? (async () => {
3221
- const result = await client.catalogue.getDeals(locationId);
3222
- if (!result.ok) {
3223
- throw result.error;
3224
- }
3225
- return result.value;
3226
- })();
3227
- if (!existing) {
3228
- dealsInflight.set(
3229
- cacheKey,
3230
- promise.finally(() => {
3231
- dealsInflight.delete(cacheKey);
3232
- })
3233
- );
3234
- }
3235
- const value = await promise;
3236
- dealsCache.set(cacheKey, value);
3237
- setDeals(value);
3238
- } catch (loadError) {
3239
- setError(loadError);
3240
- } finally {
3241
- setIsLoading(false);
3242
- }
3243
- },
3244
- [cacheKey, client, enabled, locationId]
3245
- );
3246
- useEffect(() => {
3247
- void load(false);
3248
- }, [load]);
3249
- const refetch = useCallback(async () => {
3250
- dealsCache.delete(cacheKey);
3251
- await load(true);
3252
- }, [cacheKey, load]);
3253
- return { deals, isLoading, error, refetch };
3254
- }
3255
- var onSaleCache = /* @__PURE__ */ new Map();
3256
- var onSaleInflight = /* @__PURE__ */ new Map();
3257
- function buildOnSaleCacheKey(client) {
3258
- return client.getPublicKey() || "__demo__";
3259
- }
3260
- function useProductsOnSale(options = {}) {
3261
- const context = useOptionalCimplifyClient();
3262
- const client = options.client ?? context?.client;
3263
- if (!client) {
3264
- throw new Error("useProductsOnSale must be used within CimplifyProvider or passed { client }.");
3265
- }
3266
- const enabled = options.enabled ?? true;
3267
- const cacheKey = useMemo(() => buildOnSaleCacheKey(client), [client]);
3268
- const cached = onSaleCache.get(cacheKey);
3269
- const [products, setProducts] = useState(cached ?? []);
3270
- const [isLoading, setIsLoading] = useState(enabled && !cached);
3271
- const [error, setError] = useState(null);
3272
- const load = useCallback(
3273
- async (force = false) => {
3274
- if (!enabled) {
3275
- setIsLoading(false);
3276
- return;
3277
- }
3278
- setError(null);
3279
- if (!force) {
3280
- const cachedProducts = onSaleCache.get(cacheKey);
3281
- if (cachedProducts) {
3282
- setProducts(cachedProducts);
3283
- setIsLoading(false);
3284
- return;
3285
- }
3286
- }
3287
- setIsLoading(true);
3288
- try {
3289
- const existing = onSaleInflight.get(cacheKey);
3290
- const promise = existing ?? (async () => {
3291
- const result = await client.catalogue.getProductsOnSale();
3292
- if (!result.ok) {
3293
- throw result.error;
3294
- }
3295
- return result.value;
3296
- })();
3297
- if (!existing) {
3298
- onSaleInflight.set(
3299
- cacheKey,
3300
- promise.finally(() => {
3301
- onSaleInflight.delete(cacheKey);
3302
- })
3303
- );
3304
- }
3305
- const value = await promise;
3306
- onSaleCache.set(cacheKey, value);
3307
- setProducts(value);
3308
- } catch (loadError) {
3309
- setError(loadError);
3310
- } finally {
3311
- setIsLoading(false);
3312
- }
3313
- },
3314
- [cacheKey, client, enabled]
3315
- );
3316
- useEffect(() => {
3317
- void load(false);
3318
- }, [load]);
3319
- const refetch = useCallback(async () => {
3320
- onSaleCache.delete(cacheKey);
3321
- await load(true);
3322
- }, [cacheKey, load]);
3323
- return { products, isLoading, error, refetch };
3324
- }
3325
- var productDealsCache = /* @__PURE__ */ new Map();
3326
- var productDealsInflight = /* @__PURE__ */ new Map();
3327
- function buildProductDealsCacheKey(client, productId) {
3328
- return JSON.stringify({ key: client.getPublicKey(), product_id: productId });
3329
- }
3330
- function useProductDeals(productId, options = {}) {
3331
- const context = useOptionalCimplifyClient();
3332
- const client = options.client ?? context?.client;
3333
- if (!client) {
3334
- throw new Error("useProductDeals must be used within CimplifyProvider or passed { client }.");
3335
- }
3336
- const enabled = options.enabled ?? true;
3337
- const cacheKey = useMemo(
3338
- () => buildProductDealsCacheKey(client, productId),
3339
- [client, productId]
3340
- );
3341
- const cached = productDealsCache.get(cacheKey);
3342
- const [deals, setDeals] = useState(cached ?? []);
3343
- const [isLoading, setIsLoading] = useState(enabled && !cached);
3344
- const [error, setError] = useState(null);
3345
- const load = useCallback(
3346
- async (force = false) => {
3347
- if (!enabled) {
3348
- setIsLoading(false);
3349
- return;
3350
- }
3351
- setError(null);
3352
- if (!force) {
3353
- const cachedDeals = productDealsCache.get(cacheKey);
3354
- if (cachedDeals) {
3355
- setDeals(cachedDeals);
3356
- setIsLoading(false);
3357
- return;
3358
- }
3359
- }
3360
- setIsLoading(true);
3361
- try {
3362
- const existing = productDealsInflight.get(cacheKey);
3363
- const promise = existing ?? (async () => {
3364
- const result = await client.catalogue.getProductDeals(productId);
3365
- if (!result.ok) {
3366
- throw result.error;
3367
- }
3368
- return result.value;
3369
- })();
3370
- if (!existing) {
3371
- productDealsInflight.set(
3372
- cacheKey,
3373
- promise.finally(() => {
3374
- productDealsInflight.delete(cacheKey);
3375
- })
3376
- );
3377
- }
3378
- const value = await promise;
3379
- productDealsCache.set(cacheKey, value);
3380
- setDeals(value);
3381
- } catch (loadError) {
3382
- setError(loadError);
3383
- } finally {
3384
- setIsLoading(false);
3385
- }
3386
- },
3387
- [cacheKey, client, enabled, productId]
3388
- );
3389
- useEffect(() => {
3390
- void load(false);
3391
- }, [load]);
3392
- const refetch = useCallback(async () => {
3393
- productDealsCache.delete(cacheKey);
3394
- await load(true);
3395
- }, [cacheKey, load]);
3396
- return { deals, isLoading, error, refetch };
3397
- }
3398
- function useValidateDiscount(options = {}) {
3399
- const context = useOptionalCimplifyClient();
3400
- const client = options.client ?? context?.client;
3401
- if (!client) {
3402
- throw new Error("useValidateDiscount must be used within CimplifyProvider or passed { client }.");
3403
- }
3404
- const [isValidating, setIsValidating] = useState(false);
3405
- const [error, setError] = useState(null);
3406
- const validate = useCallback(
3407
- async (code, orderSubtotal, locationId) => {
3408
- setError(null);
3409
- setIsValidating(true);
3410
- try {
3411
- const result = await client.catalogue.validateDiscountCode(code, orderSubtotal, locationId);
3412
- if (!result.ok) {
3413
- setError(result.error);
3414
- return null;
3415
- }
3416
- return result.value;
3417
- } catch (validateError) {
3418
- setError(validateError);
3419
- return null;
3420
- } finally {
3421
- setIsValidating(false);
3422
- }
3423
- },
3424
- [client]
3425
- );
3426
- return { validate, isValidating, error };
3427
- }
3428
- var bundlesCache = /* @__PURE__ */ new Map();
3429
- var bundlesInflight = /* @__PURE__ */ new Map();
3430
- function buildBundlesCacheKey(client, locationId) {
3431
- return JSON.stringify({
3432
- key: client.getPublicKey(),
3433
- location_id: locationId || "__none__"
3434
- });
3435
- }
3436
- function useBundles(options = {}) {
3437
- const context = useOptionalCimplifyClient();
3438
- const client = options.client ?? context?.client;
3439
- if (!client) {
3440
- throw new Error("useBundles must be used within CimplifyProvider or passed { client }.");
3441
- }
3442
- const enabled = options.enabled ?? true;
3443
- const locationId = client.getLocationId();
3444
- const previousLocationIdRef = useRef(locationId);
3445
- const requestIdRef = useRef(0);
3446
- const cacheKey = useMemo(
3447
- () => buildBundlesCacheKey(client, locationId),
3448
- [client, locationId]
3449
- );
3450
- const cached = bundlesCache.get(cacheKey);
3451
- const [bundles, setBundles] = useState(cached?.bundles ?? []);
3452
- const [isLoading, setIsLoading] = useState(enabled && !cached);
3453
- const [error, setError] = useState(null);
3454
- useEffect(() => {
3455
- if (previousLocationIdRef.current !== locationId) {
3456
- bundlesCache.clear();
3457
- bundlesInflight.clear();
3458
- previousLocationIdRef.current = locationId;
3459
- }
3460
- }, [locationId]);
3461
- const load = useCallback(
3462
- async (force = false) => {
3463
- if (!enabled) {
3464
- setIsLoading(false);
3465
- return;
3466
- }
3467
- const nextRequestId = ++requestIdRef.current;
3468
- setError(null);
3469
- if (!force) {
3470
- const cacheEntry = bundlesCache.get(cacheKey);
3471
- if (cacheEntry) {
3472
- setBundles(cacheEntry.bundles);
3473
- setIsLoading(false);
3474
- return;
3475
- }
3476
- }
3477
- setIsLoading(true);
3478
- try {
3479
- const existing = bundlesInflight.get(cacheKey);
3480
- const promise = existing ?? (async () => {
3481
- const result = await client.catalogue.getBundles();
3482
- if (!result.ok) {
3483
- throw result.error;
3484
- }
3485
- return result.value;
3486
- })();
3487
- if (!existing) {
3488
- bundlesInflight.set(cacheKey, promise);
3489
- promise.finally(() => {
3490
- bundlesInflight.delete(cacheKey);
3491
- }).catch(() => void 0);
3492
- }
3493
- const value = await promise;
3494
- bundlesCache.set(cacheKey, { bundles: value });
3495
- if (nextRequestId === requestIdRef.current) {
3496
- setBundles(value);
3497
- setError(null);
3498
- }
3499
- } catch (loadError) {
3500
- if (nextRequestId === requestIdRef.current) {
3501
- setError(loadError);
3502
- }
3503
- } finally {
3504
- if (nextRequestId === requestIdRef.current) {
3505
- setIsLoading(false);
3506
- }
3507
- }
3508
- },
3509
- [cacheKey, client, enabled]
3510
- );
3511
- useEffect(() => {
3512
- void load(false);
3513
- }, [load]);
3514
- const refetch = useCallback(async () => {
3515
- bundlesCache.delete(cacheKey);
3516
- await load(true);
3517
- }, [cacheKey, load]);
3518
- return { bundles, isLoading, error, refetch };
3519
- }
3520
- function useProductPrice(input) {
3521
- const {
3522
- product,
3523
- quantity = 1,
3524
- variant,
3525
- addOnOptions,
3526
- compositePrice,
3527
- bundleTotalPrice
3528
- } = input;
3529
- return useMemo(() => {
3530
- let unitPrice;
3531
- if (bundleTotalPrice != null) {
3532
- unitPrice = bundleTotalPrice;
3533
- } else if (compositePrice) {
3534
- unitPrice = parsePrice(compositePrice.final_price);
3535
- } else {
3536
- unitPrice = parsePrice(product.default_price);
3537
- if (variant?.price_adjustment) {
3538
- unitPrice += parsePrice(variant.price_adjustment);
3539
- }
3540
- if (addOnOptions) {
3541
- for (const option of addOnOptions) {
3542
- if (option.default_price) {
3543
- unitPrice += parsePrice(option.default_price);
3544
- }
3545
- }
3546
- }
3547
- }
3548
- unitPrice = Math.round(unitPrice * 100) / 100;
3549
- const totalPrice = Math.round(unitPrice * quantity * 100) / 100;
3550
- return {
3551
- unitPrice,
3552
- totalPrice,
3553
- displayTotalPrice: totalPrice
3554
- };
3555
- }, [product.default_price, quantity, variant?.price_adjustment, addOnOptions, compositePrice, bundleTotalPrice]);
3556
- }
3557
- var ordersCache = /* @__PURE__ */ new Map();
3558
- var ordersInflight = /* @__PURE__ */ new Map();
3559
- function buildOrdersCacheKey(client, status, limit) {
3560
- return JSON.stringify({ key: client.getPublicKey(), status, limit });
3561
- }
3562
- function useOrders(options = {}) {
3563
- const context = useOptionalCimplifyClient();
3564
- const client = options.client ?? context?.client;
3565
- if (!client) {
3566
- throw new Error("useOrders must be used within CimplifyProvider or passed { client }.");
3567
- }
3568
- const enabled = options.enabled ?? true;
3569
- const requestIdRef = useRef(0);
3570
- const cacheKey = useMemo(
3571
- () => buildOrdersCacheKey(client, options.status, options.limit),
3572
- [client, options.status, options.limit]
3573
- );
3574
- const cached = ordersCache.get(cacheKey);
3575
- const [orders, setOrders] = useState(cached ?? []);
3576
- const [isLoading, setIsLoading] = useState(enabled && !cached);
3577
- const [error, setError] = useState(null);
3578
- const load = useCallback(
3579
- async (force = false) => {
3580
- if (!enabled) {
3581
- setIsLoading(false);
3582
- return;
3583
- }
3584
- const nextRequestId = ++requestIdRef.current;
3585
- setError(null);
3586
- if (!force) {
3587
- const cachedOrders = ordersCache.get(cacheKey);
3588
- if (cachedOrders) {
3589
- setOrders(cachedOrders);
3590
- setIsLoading(false);
3591
- return;
3592
- }
3593
- }
3594
- setIsLoading(true);
3595
- try {
3596
- const existing = ordersInflight.get(cacheKey);
3597
- const promise = existing ?? (async () => {
3598
- const result = await client.orders.list({
3599
- status: options.status,
3600
- limit: options.limit
3601
- });
3602
- if (!result.ok) {
3603
- throw result.error;
3604
- }
3605
- return result.value;
3606
- })();
3607
- if (!existing) {
3608
- ordersInflight.set(
3609
- cacheKey,
3610
- promise.finally(() => {
3611
- ordersInflight.delete(cacheKey);
3612
- })
3613
- );
3614
- }
3615
- const value = await promise;
3616
- ordersCache.set(cacheKey, value);
3617
- if (nextRequestId === requestIdRef.current) {
3618
- setOrders(value);
3619
- setError(null);
3620
- }
3621
- } catch (loadError) {
3622
- if (nextRequestId === requestIdRef.current) {
3623
- setError(loadError);
3624
- }
3625
- } finally {
3626
- if (nextRequestId === requestIdRef.current) {
3627
- setIsLoading(false);
3628
- }
3629
- }
3630
- },
3631
- [cacheKey, client, enabled, options.status, options.limit]
3632
- );
3633
- useEffect(() => {
3634
- void load(false);
3635
- }, [load]);
3636
- const refetch = useCallback(async () => {
3637
- ordersCache.delete(cacheKey);
3638
- await load(true);
3639
- }, [cacheKey, load]);
3640
- return { orders, isLoading, error, refetch };
3641
- }
3642
- var servicesCache = /* @__PURE__ */ new Map();
3643
- var servicesInflight = /* @__PURE__ */ new Map();
3644
- function buildServicesCacheKey(client) {
3645
- return JSON.stringify({ key: client.getPublicKey() });
3646
- }
3647
- function useServices(options = {}) {
3648
- const context = useOptionalCimplifyClient();
3649
- const client = options.client ?? context?.client;
3650
- if (!client) {
3651
- throw new Error("useServices must be used within CimplifyProvider or passed { client }.");
3652
- }
3653
- const enabled = options.enabled ?? true;
3654
- const requestIdRef = useRef(0);
3655
- const cacheKey = useMemo(() => buildServicesCacheKey(client), [client]);
3656
- const cached = servicesCache.get(cacheKey);
3657
- const [services, setServices] = useState(cached ?? []);
3658
- const [isLoading, setIsLoading] = useState(enabled && !cached);
3659
- const [error, setError] = useState(null);
3660
- const load = useCallback(
3661
- async (force = false) => {
3662
- if (!enabled) {
3663
- setIsLoading(false);
3664
- return;
3665
- }
3666
- const nextRequestId = ++requestIdRef.current;
3667
- setError(null);
3668
- if (!force) {
3669
- const cachedServices = servicesCache.get(cacheKey);
3670
- if (cachedServices) {
3671
- setServices(cachedServices);
3672
- setIsLoading(false);
3673
- return;
3674
- }
3675
- }
3676
- setIsLoading(true);
3677
- try {
3678
- const existing = servicesInflight.get(cacheKey);
3679
- const promise = existing ?? (async () => {
3680
- const result = await client.scheduling.getServices();
3681
- if (!result.ok) {
3682
- throw result.error;
3683
- }
3684
- return result.value;
3685
- })();
3686
- if (!existing) {
3687
- servicesInflight.set(
3688
- cacheKey,
3689
- promise.finally(() => {
3690
- servicesInflight.delete(cacheKey);
3691
- })
3692
- );
3693
- }
3694
- const value = await promise;
3695
- servicesCache.set(cacheKey, value);
3696
- if (nextRequestId === requestIdRef.current) {
3697
- setServices(value);
3698
- setError(null);
3699
- }
3700
- } catch (loadError) {
3701
- if (nextRequestId === requestIdRef.current) {
3702
- setError(loadError);
3703
- }
3704
- } finally {
3705
- if (nextRequestId === requestIdRef.current) {
3706
- setIsLoading(false);
3707
- }
3708
- }
3709
- },
3710
- [cacheKey, client, enabled]
3711
- );
3712
- useEffect(() => {
3713
- void load(false);
3714
- }, [load]);
3715
- const refetch = useCallback(async () => {
3716
- servicesCache.delete(cacheKey);
3717
- await load(true);
3718
- }, [cacheKey, load]);
3719
- return { services, isLoading, error, refetch };
3720
- }
3721
- var slotsCache = /* @__PURE__ */ new Map();
3722
- var slotsInflight = /* @__PURE__ */ new Map();
3723
- function buildSlotsCacheKey(client, serviceId, date, participantCount) {
3724
- return JSON.stringify({
3725
- key: client.getPublicKey(),
3726
- serviceId,
3727
- date,
3728
- participantCount
3729
- });
3730
- }
3731
- function useAvailableSlots(serviceId, date, options = {}) {
3732
- const context = useOptionalCimplifyClient();
3733
- const client = options.client ?? context?.client;
3734
- if (!client) {
3735
- throw new Error("useAvailableSlots must be used within CimplifyProvider or passed { client }.");
3736
- }
3737
- const enabled = (options.enabled ?? true) && !!serviceId && !!date;
3738
- const requestIdRef = useRef(0);
3739
- const cacheKey = useMemo(
3740
- () => serviceId && date ? buildSlotsCacheKey(client, serviceId, date, options.participantCount) : null,
3741
- [client, serviceId, date, options.participantCount]
3742
- );
3743
- const cached = cacheKey ? slotsCache.get(cacheKey) : void 0;
3744
- const [slots, setSlots] = useState(cached ?? []);
3745
- const [isLoading, setIsLoading] = useState(enabled && !cached);
3746
- const [error, setError] = useState(null);
3747
- const load = useCallback(
3748
- async (force = false) => {
3749
- if (!enabled || !cacheKey || !serviceId || !date) {
3750
- setIsLoading(false);
3751
- return;
3752
- }
3753
- const nextRequestId = ++requestIdRef.current;
3754
- setError(null);
3755
- if (!force) {
3756
- const cachedSlots = slotsCache.get(cacheKey);
3757
- if (cachedSlots) {
3758
- setSlots(cachedSlots);
3759
- setIsLoading(false);
3760
- return;
3761
- }
3762
- }
3763
- setIsLoading(true);
3764
- try {
3765
- const existing = slotsInflight.get(cacheKey);
3766
- const promise = existing ?? (async () => {
3767
- const result = await client.scheduling.getAvailableSlots({
3768
- service_id: serviceId,
3769
- date,
3770
- participant_count: options.participantCount
3771
- });
3772
- if (!result.ok) {
3773
- throw result.error;
3774
- }
3775
- return result.value;
3776
- })();
3777
- if (!existing) {
3778
- slotsInflight.set(
3779
- cacheKey,
3780
- promise.finally(() => {
3781
- slotsInflight.delete(cacheKey);
3782
- })
3783
- );
3784
- }
3785
- const value = await promise;
3786
- slotsCache.set(cacheKey, value);
3787
- if (nextRequestId === requestIdRef.current) {
3788
- setSlots(value);
3789
- setError(null);
3790
- }
3791
- } catch (loadError) {
3792
- if (nextRequestId === requestIdRef.current) {
3793
- setError(loadError);
3794
- }
3795
- } finally {
3796
- if (nextRequestId === requestIdRef.current) {
3797
- setIsLoading(false);
3798
- }
3799
- }
3800
- },
3801
- [cacheKey, client, enabled, serviceId, date, options.participantCount]
3802
- );
3803
- useEffect(() => {
3804
- void load(false);
3805
- }, [load]);
3806
- const refetch = useCallback(async () => {
3807
- if (cacheKey) {
3808
- slotsCache.delete(cacheKey);
3809
- }
3810
- await load(true);
3811
- }, [cacheKey, load]);
3812
- return { slots, isLoading, error, refetch };
3813
- }
3814
- var availabilityCache2 = /* @__PURE__ */ new Map();
3815
- var availabilityInflight2 = /* @__PURE__ */ new Map();
3816
- function buildAvailabilityCacheKey2(client, serviceId, startDate, endDate, participantCount) {
3817
- return JSON.stringify({
3818
- key: client.getPublicKey(),
3819
- serviceId,
3820
- startDate,
3821
- endDate,
3822
- participantCount
3823
- });
3824
- }
3825
- function useServiceAvailability(serviceId, startDate, endDate, options = {}) {
3826
- const context = useOptionalCimplifyClient();
3827
- const client = options.client ?? context?.client;
3828
- if (!client) {
3829
- throw new Error(
3830
- "useServiceAvailability must be used within CimplifyProvider or passed { client }."
3831
- );
3832
- }
3833
- const enabled = (options.enabled ?? true) && !!serviceId && !!startDate && !!endDate;
3834
- const requestIdRef = useRef(0);
3835
- const cacheKey = useMemo(
3836
- () => serviceId && startDate && endDate ? buildAvailabilityCacheKey2(
3837
- client,
3838
- serviceId,
3839
- startDate,
3840
- endDate,
3841
- options.participantCount
3842
- ) : null,
3843
- [client, serviceId, startDate, endDate, options.participantCount]
3844
- );
3845
- const cached = cacheKey ? availabilityCache2.get(cacheKey) : void 0;
3846
- const [days, setDays] = useState(cached ?? []);
3847
- const [isLoading, setIsLoading] = useState(enabled && !cached);
3848
- const [error, setError] = useState(null);
3849
- const load = useCallback(
3850
- async (force = false) => {
3851
- if (!enabled || !cacheKey || !serviceId || !startDate || !endDate) {
3852
- setIsLoading(false);
3853
- return;
3854
- }
3855
- const nextRequestId = ++requestIdRef.current;
3856
- setError(null);
3857
- if (!force) {
3858
- const cachedDays = availabilityCache2.get(cacheKey);
3859
- if (cachedDays) {
3860
- setDays(cachedDays);
3861
- setIsLoading(false);
3862
- return;
3863
- }
2667
+ });
2668
+ function useBundles(options = {}) {
2669
+ const { data, isLoading, error, refetch } = bundlesQuery(options);
2670
+ return { bundles: data ?? [], isLoading, error, refetch };
2671
+ }
2672
+ function useProductPrice(input) {
2673
+ const {
2674
+ product,
2675
+ quantity = 1,
2676
+ variant,
2677
+ addOnOptions,
2678
+ compositePrice,
2679
+ bundleTotalPrice
2680
+ } = input;
2681
+ return useMemo(() => {
2682
+ let unitPrice;
2683
+ if (bundleTotalPrice != null) {
2684
+ unitPrice = bundleTotalPrice;
2685
+ } else if (compositePrice) {
2686
+ unitPrice = parsePrice(compositePrice.final_price);
2687
+ } else {
2688
+ unitPrice = parsePrice(product.default_price);
2689
+ if (variant?.price_adjustment) {
2690
+ unitPrice += parsePrice(variant.price_adjustment);
3864
2691
  }
3865
- setIsLoading(true);
3866
- try {
3867
- const existing = availabilityInflight2.get(cacheKey);
3868
- const promise = existing ?? (async () => {
3869
- const result = await client.scheduling.getServiceAvailability({
3870
- service_id: serviceId,
3871
- start_date: startDate,
3872
- end_date: endDate,
3873
- location_id: options.locationId,
3874
- participant_count: options.participantCount
3875
- });
3876
- if (!result.ok) {
3877
- throw result.error;
2692
+ if (addOnOptions) {
2693
+ for (const option of addOnOptions) {
2694
+ if (option.default_price) {
2695
+ unitPrice += parsePrice(option.default_price);
3878
2696
  }
3879
- return result.value.availability;
3880
- })();
3881
- if (!existing) {
3882
- availabilityInflight2.set(
3883
- cacheKey,
3884
- promise.finally(() => {
3885
- availabilityInflight2.delete(cacheKey);
3886
- })
3887
- );
3888
- }
3889
- const value = await promise;
3890
- availabilityCache2.set(cacheKey, value);
3891
- if (nextRequestId === requestIdRef.current) {
3892
- setDays(value);
3893
- setError(null);
3894
- }
3895
- } catch (loadError) {
3896
- if (nextRequestId === requestIdRef.current) {
3897
- setError(loadError);
3898
- }
3899
- } finally {
3900
- if (nextRequestId === requestIdRef.current) {
3901
- setIsLoading(false);
3902
2697
  }
3903
2698
  }
3904
- },
3905
- [cacheKey, client, enabled, serviceId, startDate, endDate, options.locationId, options.participantCount]
3906
- );
3907
- useEffect(() => {
3908
- void load(false);
3909
- }, [load]);
3910
- const refetch = useCallback(async () => {
3911
- if (cacheKey) {
3912
- availabilityCache2.delete(cacheKey);
3913
2699
  }
3914
- await load(true);
3915
- }, [cacheKey, load]);
3916
- return { days, isLoading, error, refetch };
2700
+ unitPrice = Math.round(unitPrice * 100) / 100;
2701
+ const totalPrice = Math.round(unitPrice * quantity * 100) / 100;
2702
+ return {
2703
+ unitPrice,
2704
+ totalPrice,
2705
+ displayTotalPrice: totalPrice
2706
+ };
2707
+ }, [product.default_price, quantity, variant?.price_adjustment, addOnOptions, compositePrice, bundleTotalPrice]);
2708
+ }
2709
+
2710
+ // src/react/hooks/use-orders.ts
2711
+ var ordersQuery = createCachedQuery({
2712
+ name: "useOrders",
2713
+ key: (client, options) => cacheKey(client.getPublicKey(), options.status, options.limit),
2714
+ fetch: async (client, options) => {
2715
+ const result = await client.orders.list({
2716
+ status: options.status,
2717
+ limit: options.limit
2718
+ });
2719
+ if (!result.ok) throw result.error;
2720
+ return result.value;
2721
+ }
2722
+ });
2723
+ function useOrders(options = {}) {
2724
+ const { data, isLoading, error, refetch } = ordersQuery(options);
2725
+ return { orders: data ?? [], isLoading, error, refetch };
2726
+ }
2727
+
2728
+ // src/react/hooks/use-services.ts
2729
+ var servicesQuery = createCachedQuery({
2730
+ name: "useServices",
2731
+ key: (client) => cacheKey(client.getPublicKey()),
2732
+ fetch: async (client) => {
2733
+ const result = await client.scheduling.getServices();
2734
+ if (!result.ok) throw result.error;
2735
+ return result.value;
2736
+ }
2737
+ });
2738
+ function useServices(options = {}) {
2739
+ const { data, isLoading, error, refetch } = servicesQuery(options);
2740
+ return { services: data ?? [], isLoading, error, refetch };
3917
2741
  }
3918
- var bookingsCache = /* @__PURE__ */ new Map();
3919
- var bookingsInflight = /* @__PURE__ */ new Map();
3920
- function buildBookingsCacheKey(client, filter) {
3921
- return JSON.stringify({ key: client.getPublicKey(), filter });
2742
+
2743
+ // src/react/hooks/use-available-slots.ts
2744
+ var slotsQuery = createCachedQuery({
2745
+ name: "useAvailableSlots",
2746
+ key: (client, options) => cacheKey(client.getPublicKey(), options.serviceId, options.date, options.participantCount),
2747
+ fetch: async (client, options) => {
2748
+ const result = await client.scheduling.getAvailableSlots({
2749
+ service_id: options.serviceId,
2750
+ date: options.date,
2751
+ participant_count: options.participantCount
2752
+ });
2753
+ if (!result.ok) throw result.error;
2754
+ return result.value;
2755
+ }
2756
+ });
2757
+ function useAvailableSlots(serviceId, date, options = {}) {
2758
+ const { data, isLoading, error, refetch } = slotsQuery({
2759
+ ...options,
2760
+ serviceId: serviceId || "",
2761
+ date: date || "",
2762
+ enabled: (options.enabled ?? true) && !!serviceId && !!date
2763
+ });
2764
+ return { slots: data ?? [], isLoading, error, refetch };
3922
2765
  }
2766
+
2767
+ // src/react/hooks/use-service-availability.ts
2768
+ var serviceAvailabilityQuery = createCachedQuery({
2769
+ name: "useServiceAvailability",
2770
+ key: (client, options) => cacheKey(
2771
+ client.getPublicKey(),
2772
+ options.serviceId,
2773
+ options.startDate,
2774
+ options.endDate,
2775
+ options.participantCount
2776
+ ),
2777
+ fetch: async (client, options) => {
2778
+ const result = await client.scheduling.getServiceAvailability({
2779
+ service_id: options.serviceId,
2780
+ start_date: options.startDate,
2781
+ end_date: options.endDate,
2782
+ location_id: options.locationId,
2783
+ participant_count: options.participantCount
2784
+ });
2785
+ if (!result.ok) throw result.error;
2786
+ return result.value.availability;
2787
+ }
2788
+ });
2789
+ function useServiceAvailability(serviceId, startDate, endDate, options = {}) {
2790
+ const { data, isLoading, error, refetch } = serviceAvailabilityQuery({
2791
+ ...options,
2792
+ serviceId: serviceId || "",
2793
+ startDate: startDate || "",
2794
+ endDate: endDate || "",
2795
+ enabled: (options.enabled ?? true) && !!serviceId && !!startDate && !!endDate
2796
+ });
2797
+ return { days: data ?? [], isLoading, error, refetch };
2798
+ }
2799
+ var bookingsQuery = createCachedQuery({
2800
+ name: "useBookings",
2801
+ key: (client, options) => cacheKey(client.getPublicKey(), options.filter ?? "all"),
2802
+ fetch: async (client, options) => {
2803
+ const filter = options.filter ?? "all";
2804
+ let result;
2805
+ switch (filter) {
2806
+ case "upcoming":
2807
+ result = await client.scheduling.getUpcomingBookings();
2808
+ break;
2809
+ case "past":
2810
+ result = await client.scheduling.getPastBookings();
2811
+ break;
2812
+ default:
2813
+ result = await client.scheduling.getCustomerBookings();
2814
+ break;
2815
+ }
2816
+ if (!result.ok) throw result.error;
2817
+ return result.value;
2818
+ }
2819
+ });
3923
2820
  function useBookings(options = {}) {
3924
2821
  const context = useOptionalCimplifyClient();
3925
2822
  const client = options.client ?? context?.client;
3926
- if (!client) {
3927
- throw new Error("useBookings must be used within CimplifyProvider or passed { client }.");
3928
- }
3929
- const filter = options.filter ?? "all";
3930
- const enabled = options.enabled ?? true;
3931
- const requestIdRef = useRef(0);
3932
- const cacheKey = useMemo(
3933
- () => buildBookingsCacheKey(client, filter),
3934
- [client, filter]
3935
- );
3936
- const cached = bookingsCache.get(cacheKey);
3937
- const [bookings, setBookings] = useState(cached ?? []);
3938
- const [isLoading, setIsLoading] = useState(enabled && !cached);
3939
- const [error, setError] = useState(null);
3940
- const load = useCallback(
3941
- async (force = false) => {
3942
- if (!enabled) {
3943
- setIsLoading(false);
3944
- return;
3945
- }
3946
- const nextRequestId = ++requestIdRef.current;
3947
- setError(null);
3948
- if (!force) {
3949
- const cachedBookings = bookingsCache.get(cacheKey);
3950
- if (cachedBookings) {
3951
- setBookings(cachedBookings);
3952
- setIsLoading(false);
3953
- return;
3954
- }
3955
- }
3956
- setIsLoading(true);
3957
- try {
3958
- const existing = bookingsInflight.get(cacheKey);
3959
- const promise = existing ?? (async () => {
3960
- let result;
3961
- switch (filter) {
3962
- case "upcoming":
3963
- result = await client.scheduling.getUpcomingBookings();
3964
- break;
3965
- case "past":
3966
- result = await client.scheduling.getPastBookings();
3967
- break;
3968
- default:
3969
- result = await client.scheduling.getCustomerBookings();
3970
- break;
3971
- }
3972
- if (!result.ok) {
3973
- throw result.error;
3974
- }
3975
- return result.value;
3976
- })();
3977
- if (!existing) {
3978
- bookingsInflight.set(
3979
- cacheKey,
3980
- promise.finally(() => {
3981
- bookingsInflight.delete(cacheKey);
3982
- })
3983
- );
3984
- }
3985
- const value = await promise;
3986
- bookingsCache.set(cacheKey, value);
3987
- if (nextRequestId === requestIdRef.current) {
3988
- setBookings(value);
3989
- setError(null);
3990
- }
3991
- } catch (loadError) {
3992
- if (nextRequestId === requestIdRef.current) {
3993
- setError(loadError);
3994
- }
3995
- } finally {
3996
- if (nextRequestId === requestIdRef.current) {
3997
- setIsLoading(false);
3998
- }
3999
- }
4000
- },
4001
- [cacheKey, client, enabled, filter]
4002
- );
4003
- useEffect(() => {
4004
- void load(false);
4005
- }, [load]);
4006
- const refetch = useCallback(async () => {
4007
- bookingsCache.delete(cacheKey);
4008
- await load(true);
4009
- }, [cacheKey, load]);
2823
+ const { data, isLoading, error, refetch } = bookingsQuery(options);
4010
2824
  const cancelBooking = useCallback(
4011
2825
  async (bookingId, reason) => {
2826
+ if (!client) throw new Error("useBookings must be used within CimplifyProvider or passed { client }.");
4012
2827
  const result = await client.scheduling.cancelBooking({
4013
2828
  booking_id: bookingId,
4014
2829
  reason
4015
2830
  });
4016
- if (!result.ok) {
4017
- throw result.error;
4018
- }
4019
- for (const key of bookingsCache.keys()) {
4020
- bookingsCache.delete(key);
4021
- }
4022
- await load(true);
2831
+ if (!result.ok) throw result.error;
2832
+ bookingsQuery.clear();
2833
+ await refetch();
4023
2834
  return result.value;
4024
2835
  },
4025
- [client, load]
2836
+ [client, refetch]
4026
2837
  );
4027
- return { bookings, isLoading, error, refetch, cancelBooking };
2838
+ return { bookings: data ?? [], isLoading, error, refetch, cancelBooking };
4028
2839
  }
4029
- var definitionsCache = /* @__PURE__ */ new Map();
4030
- var definitionsInflight = /* @__PURE__ */ new Map();
4031
- function buildCacheKey(client, namespace) {
4032
- return `attr_defs_${client.getPublicKey() || "__demo__"}${namespace ? `_${namespace}` : ""}`;
4033
- }
4034
- function useAttributeDefinitions(options = {}) {
4035
- const context = useOptionalCimplifyClient();
4036
- const client = options.client ?? context?.client;
4037
- if (!client) {
4038
- throw new Error(
4039
- "useAttributeDefinitions must be used within CimplifyProvider or passed { client }."
4040
- );
2840
+
2841
+ // src/react/hooks/use-attribute-definitions.ts
2842
+ var attributeDefinitionsQuery = createCachedQuery({
2843
+ name: "useAttributeDefinitions",
2844
+ key: (client, options) => cacheKey(client.getPublicKey() || "__demo__", options.namespace),
2845
+ fetch: async (client, options) => {
2846
+ const result = await client.catalogue.getAttributeDefinitions(options.namespace);
2847
+ if (!result.ok) throw result.error;
2848
+ return result.value;
4041
2849
  }
4042
- const enabled = options.enabled ?? true;
4043
- const namespace = options.namespace;
4044
- const cacheKey = useMemo(() => buildCacheKey(client, namespace), [client, namespace]);
4045
- const cached = definitionsCache.get(cacheKey);
4046
- const [definitions, setDefinitions] = useState(cached ?? []);
4047
- const [isLoading, setIsLoading] = useState(enabled && !cached);
4048
- const [error, setError] = useState(null);
4049
- const load = useCallback(
4050
- async (force = false) => {
4051
- if (!enabled) {
4052
- setIsLoading(false);
4053
- return;
4054
- }
4055
- setError(null);
4056
- if (!force) {
4057
- const cachedDefs = definitionsCache.get(cacheKey);
4058
- if (cachedDefs) {
4059
- setDefinitions(cachedDefs);
4060
- setIsLoading(false);
4061
- return;
4062
- }
4063
- }
4064
- setIsLoading(true);
4065
- try {
4066
- const existing = definitionsInflight.get(cacheKey);
4067
- const promise = existing ?? (async () => {
4068
- const result = await client.catalogue.getAttributeDefinitions(namespace);
4069
- if (!result.ok) {
4070
- throw result.error;
4071
- }
4072
- return result.value;
4073
- })();
4074
- if (!existing) {
4075
- definitionsInflight.set(
4076
- cacheKey,
4077
- promise.finally(() => {
4078
- definitionsInflight.delete(cacheKey);
4079
- })
4080
- );
4081
- }
4082
- const value = await promise;
4083
- definitionsCache.set(cacheKey, value);
4084
- setDefinitions(value);
4085
- } catch (loadError) {
4086
- setError(loadError);
4087
- } finally {
4088
- setIsLoading(false);
4089
- }
4090
- },
4091
- [cacheKey, client, enabled]
4092
- );
4093
- useEffect(() => {
4094
- void load(false);
4095
- }, [load]);
4096
- const refetch = useCallback(async () => {
4097
- definitionsCache.delete(cacheKey);
4098
- await load(true);
4099
- }, [cacheKey, load]);
4100
- return { definitions, isLoading, error, refetch };
2850
+ });
2851
+ function useAttributeDefinitions(options = {}) {
2852
+ const { data, isLoading, error, refetch } = attributeDefinitionsQuery(options);
2853
+ return { definitions: data ?? [], isLoading, error, refetch };
4101
2854
  }
4102
- var facetsCache = /* @__PURE__ */ new Map();
4103
- var facetsInflight = /* @__PURE__ */ new Map();
4104
- function usePropertyFacets(options = {}) {
4105
- const context = useOptionalCimplifyClient();
4106
- const client = options.client ?? context?.client;
4107
- if (!client) {
4108
- throw new Error(
4109
- "usePropertyFacets must be used within CimplifyProvider or passed { client }."
4110
- );
2855
+
2856
+ // src/react/hooks/use-property-facets.ts
2857
+ var propertyFacetsQuery = createCachedQuery({
2858
+ name: "usePropertyFacets",
2859
+ key: (client, options) => cacheKey(client.getPublicKey() || "__demo__", options.category_id, options.product_type),
2860
+ fetch: async (client, options) => {
2861
+ const result = await client.catalogue.getPropertyFacets({
2862
+ category_id: options.category_id,
2863
+ product_type: options.product_type
2864
+ });
2865
+ if (!result.ok) throw result.error;
2866
+ return result.value;
4111
2867
  }
4112
- const enabled = options.enabled ?? true;
4113
- const cacheKey = useMemo(
4114
- () => `facets_${client.getPublicKey() || "__demo__"}_${options.category_id ?? ""}_${options.product_type ?? ""}`,
4115
- [client, options.category_id, options.product_type]
4116
- );
4117
- const cached = facetsCache.get(cacheKey);
4118
- const [facets, setFacets] = useState(cached ?? []);
4119
- const [isLoading, setIsLoading] = useState(enabled && !cached);
4120
- const [error, setError] = useState(null);
4121
- const load = useCallback(
4122
- async (force = false) => {
4123
- if (!enabled) {
4124
- setIsLoading(false);
4125
- return;
4126
- }
4127
- setError(null);
4128
- if (!force) {
4129
- const cachedFacets = facetsCache.get(cacheKey);
4130
- if (cachedFacets) {
4131
- setFacets(cachedFacets);
4132
- setIsLoading(false);
4133
- return;
4134
- }
4135
- }
4136
- setIsLoading(true);
4137
- try {
4138
- const existing = facetsInflight.get(cacheKey);
4139
- const promise = existing ?? (async () => {
4140
- const result = await client.catalogue.getPropertyFacets({
4141
- category_id: options.category_id,
4142
- product_type: options.product_type
4143
- });
4144
- if (!result.ok) {
4145
- throw result.error;
4146
- }
4147
- return result.value;
4148
- })();
4149
- if (!existing) {
4150
- facetsInflight.set(
4151
- cacheKey,
4152
- promise.finally(() => {
4153
- facetsInflight.delete(cacheKey);
4154
- })
4155
- );
4156
- }
4157
- const value = await promise;
4158
- facetsCache.set(cacheKey, value);
4159
- setFacets(value);
4160
- } catch (loadError) {
4161
- setError(loadError);
4162
- } finally {
4163
- setIsLoading(false);
4164
- }
4165
- },
4166
- [cacheKey, client, enabled, options.category_id, options.product_type]
4167
- );
4168
- useEffect(() => {
4169
- void load(false);
4170
- }, [load]);
4171
- const refetch = useCallback(async () => {
4172
- facetsCache.delete(cacheKey);
4173
- await load(true);
4174
- }, [cacheKey, load]);
4175
- return { facets, isLoading, error, refetch };
2868
+ });
2869
+ function usePropertyFacets(options = {}) {
2870
+ const { data, isLoading, error, refetch } = propertyFacetsQuery(options);
2871
+ return { facets: data ?? [], isLoading, error, refetch };
4176
2872
  }
4177
2873
  function useBillingPlans(productId, options = {}) {
4178
2874
  const context = useOptionalCimplifyClient();
@@ -4304,417 +3000,112 @@ function useVariantSelector(options) {
4304
3000
  reset
4305
3001
  };
4306
3002
  }
4307
- var activityStateCache = /* @__PURE__ */ new Map();
4308
- var activityStateInflight = /* @__PURE__ */ new Map();
4309
- function buildActivityStateCacheKey(client) {
4310
- return JSON.stringify({ key: client.getPublicKey(), type: "activity_state" });
4311
- }
3003
+ var activityStateQuery = createCachedQuery({
3004
+ name: "useActivityState",
3005
+ key: (client) => cacheKey(client.getPublicKey()),
3006
+ fetch: async (client) => {
3007
+ const result = await client.activity.getState();
3008
+ if (!result.ok) throw result.error;
3009
+ return result.value;
3010
+ }
3011
+ });
4312
3012
  function useActivityState(options = {}) {
4313
3013
  const context = useOptionalCimplifyClient();
4314
3014
  const client = options.client ?? context?.client;
4315
- if (!client) {
4316
- throw new Error("useActivityState must be used within CimplifyProvider or passed { client }.");
4317
- }
4318
- const enabled = options.enabled ?? true;
4319
- const cacheKey = useMemo(() => buildActivityStateCacheKey(client), [client]);
4320
- const cached = activityStateCache.get(cacheKey);
4321
- const [state, setState] = useState(cached ?? null);
4322
- const [isLoading, setIsLoading] = useState(enabled && !cached);
4323
- const [error, setError] = useState(null);
4324
- const load = useCallback(
4325
- async (force = false) => {
4326
- if (!enabled) {
4327
- setIsLoading(false);
4328
- return;
4329
- }
4330
- setError(null);
4331
- if (!force) {
4332
- const cachedState = activityStateCache.get(cacheKey);
4333
- if (cachedState) {
4334
- setState(cachedState);
4335
- setIsLoading(false);
4336
- return;
4337
- }
4338
- }
4339
- setIsLoading(true);
4340
- try {
4341
- const existing = activityStateInflight.get(cacheKey);
4342
- const promise = existing ?? (async () => {
4343
- const result = await client.activity.getState();
4344
- if (!result.ok) {
4345
- throw result.error;
4346
- }
4347
- return result.value;
4348
- })();
4349
- if (!existing) {
4350
- activityStateInflight.set(
4351
- cacheKey,
4352
- promise.finally(() => {
4353
- activityStateInflight.delete(cacheKey);
4354
- })
4355
- );
4356
- }
4357
- const value = await promise;
4358
- activityStateCache.set(cacheKey, value);
4359
- setState(value);
4360
- } catch (loadError) {
4361
- setError(loadError);
4362
- } finally {
4363
- setIsLoading(false);
4364
- }
4365
- },
4366
- [cacheKey, client, enabled]
4367
- );
4368
- useEffect(() => {
4369
- void load(false);
4370
- }, [load]);
4371
- const refetch = useCallback(async () => {
4372
- activityStateCache.delete(cacheKey);
4373
- await load(true);
4374
- }, [cacheKey, load]);
3015
+ const { data, isLoading, error, refetch } = activityStateQuery(options);
4375
3016
  const dismissMessage = useCallback(
4376
3017
  async (code) => {
3018
+ if (!client) return;
4377
3019
  const result = await client.activity.dismissMessage(code);
4378
- if (!result.ok) {
4379
- setError(result.error);
4380
- return;
4381
- }
4382
- setState((prev) => {
4383
- if (!prev) return prev;
4384
- return { ...prev, messages: result.value.messages };
4385
- });
4386
- activityStateCache.delete(cacheKey);
4387
- await load(true);
3020
+ if (!result.ok) return;
3021
+ activityStateQuery.clear();
3022
+ await refetch();
4388
3023
  },
4389
- [cacheKey, client, load]
3024
+ [client, refetch]
4390
3025
  );
4391
- const messages = state?.messages ?? [];
4392
- const intent = state?.intent ?? "";
4393
- return { state, messages, intent, isLoading, error, refetch, dismissMessage };
4394
- }
4395
- var recommendationsCache = /* @__PURE__ */ new Map();
4396
- var recommendationsInflight = /* @__PURE__ */ new Map();
4397
- function buildRecommendationsCacheKey(client, locationId, limit) {
4398
- return JSON.stringify({
4399
- key: client.getPublicKey(),
4400
- type: "recommendations",
4401
- location_id: locationId,
4402
- limit
4403
- });
3026
+ return {
3027
+ state: data,
3028
+ messages: data?.messages ?? [],
3029
+ intent: data?.intent ?? "",
3030
+ isLoading,
3031
+ error,
3032
+ refetch,
3033
+ dismissMessage
3034
+ };
4404
3035
  }
4405
- function useRecommendations(options = {}) {
4406
- const context = useOptionalCimplifyClient();
4407
- const client = options.client ?? context?.client;
4408
- if (!client) {
4409
- throw new Error(
4410
- "useRecommendations must be used within CimplifyProvider or passed { client }."
4411
- );
3036
+
3037
+ // src/react/hooks/use-recommendations.ts
3038
+ var recommendationsQuery = createCachedQuery({
3039
+ name: "useRecommendations",
3040
+ locationSensitive: true,
3041
+ key: (client, options) => {
3042
+ const locationId = options.locationId ?? client.getLocationId();
3043
+ return cacheKey(client.getPublicKey(), locationId, options.limit);
3044
+ },
3045
+ fetch: async (client, options) => {
3046
+ const locationId = options.locationId ?? client.getLocationId() ?? void 0;
3047
+ const result = await client.activity.getRecommendations({
3048
+ location_id: locationId,
3049
+ limit: options.limit
3050
+ });
3051
+ if (!result.ok) throw result.error;
3052
+ return result.value;
4412
3053
  }
4413
- const enabled = options.enabled ?? true;
4414
- const locationId = options.locationId ?? client.getLocationId() ?? void 0;
4415
- const limit = options.limit;
4416
- const previousLocationIdRef = useRef(locationId);
4417
- const cacheKey = useMemo(
4418
- () => buildRecommendationsCacheKey(client, locationId, limit),
4419
- [client, locationId, limit]
4420
- );
4421
- const cached = recommendationsCache.get(cacheKey);
4422
- const [response, setResponse] = useState(cached ?? null);
4423
- const [isLoading, setIsLoading] = useState(enabled && !cached);
4424
- const [error, setError] = useState(null);
4425
- useEffect(() => {
4426
- if (previousLocationIdRef.current !== locationId) {
4427
- recommendationsCache.clear();
4428
- recommendationsInflight.clear();
4429
- previousLocationIdRef.current = locationId;
4430
- }
4431
- }, [locationId]);
4432
- const load = useCallback(
4433
- async (force = false) => {
4434
- if (!enabled) {
4435
- setIsLoading(false);
4436
- return;
4437
- }
4438
- setError(null);
4439
- if (!force) {
4440
- const cachedResponse = recommendationsCache.get(cacheKey);
4441
- if (cachedResponse) {
4442
- setResponse(cachedResponse);
4443
- setIsLoading(false);
4444
- return;
4445
- }
4446
- }
4447
- setIsLoading(true);
4448
- try {
4449
- const existing = recommendationsInflight.get(cacheKey);
4450
- const promise = existing ?? (async () => {
4451
- const result = await client.activity.getRecommendations({
4452
- location_id: locationId,
4453
- limit
4454
- });
4455
- if (!result.ok) {
4456
- throw result.error;
4457
- }
4458
- return result.value;
4459
- })();
4460
- if (!existing) {
4461
- recommendationsInflight.set(
4462
- cacheKey,
4463
- promise.finally(() => {
4464
- recommendationsInflight.delete(cacheKey);
4465
- })
4466
- );
4467
- }
4468
- const value = await promise;
4469
- recommendationsCache.set(cacheKey, value);
4470
- setResponse(value);
4471
- } catch (loadError) {
4472
- setError(loadError);
4473
- } finally {
4474
- setIsLoading(false);
4475
- }
4476
- },
4477
- [cacheKey, client, enabled, locationId, limit]
4478
- );
4479
- useEffect(() => {
4480
- void load(false);
4481
- }, [load]);
4482
- const refetch = useCallback(async () => {
4483
- recommendationsCache.delete(cacheKey);
4484
- await load(true);
4485
- }, [cacheKey, load]);
4486
- const recommendations = response?.recommendations ?? [];
4487
- const intent = response?.intent ?? "";
4488
- return { recommendations, intent, isLoading, error, refetch };
4489
- }
4490
- var deliveryFeeCache = /* @__PURE__ */ new Map();
4491
- var deliveryFeeInflight = /* @__PURE__ */ new Map();
4492
- function buildDeliveryFeeCacheKey(client, latitude, longitude, country) {
4493
- return JSON.stringify({
4494
- key: client.getPublicKey(),
4495
- lat: latitude,
4496
- lng: longitude,
4497
- country
4498
- });
3054
+ });
3055
+ function useRecommendations(options = {}) {
3056
+ const { data, isLoading, error, refetch } = recommendationsQuery(options);
3057
+ return {
3058
+ recommendations: data?.recommendations ?? [],
3059
+ intent: data?.intent ?? "",
3060
+ isLoading,
3061
+ error,
3062
+ refetch
3063
+ };
4499
3064
  }
4500
- function useDeliveryFee(options) {
4501
- const context = useOptionalCimplifyClient();
4502
- const client = options.client ?? context?.client;
4503
- if (!client) {
4504
- throw new Error("useDeliveryFee must be used within CimplifyProvider or passed { client }.");
3065
+
3066
+ // src/react/hooks/use-delivery-fee.ts
3067
+ var deliveryFeeQuery = createCachedQuery({
3068
+ name: "useDeliveryFee",
3069
+ key: (client, options) => cacheKey(client.getPublicKey(), options.latitude, options.longitude, options.country),
3070
+ fetch: async (client, options) => {
3071
+ const result = await client.delivery.getFee(options.latitude, options.longitude, options.country);
3072
+ if (!result.ok) throw result.error;
3073
+ return result.value;
4505
3074
  }
4506
- const enabled = options.enabled ?? true;
4507
- const { latitude, longitude, country } = options;
4508
- const cacheKey = useMemo(
4509
- () => buildDeliveryFeeCacheKey(client, latitude, longitude, country),
4510
- [client, latitude, longitude, country]
4511
- );
4512
- const cached = deliveryFeeCache.get(cacheKey);
4513
- const [fee, setFee] = useState(cached ?? null);
4514
- const [isLoading, setIsLoading] = useState(enabled && !cached);
4515
- const [error, setError] = useState(null);
4516
- const requestIdRef = useRef(0);
4517
- const load = useCallback(
4518
- async (force = false) => {
4519
- if (!enabled) {
4520
- setIsLoading(false);
4521
- return;
4522
- }
4523
- setError(null);
4524
- if (!force) {
4525
- const cachedFee = deliveryFeeCache.get(cacheKey);
4526
- if (cachedFee) {
4527
- setFee(cachedFee);
4528
- setIsLoading(false);
4529
- return;
4530
- }
4531
- }
4532
- setIsLoading(true);
4533
- const currentRequestId = ++requestIdRef.current;
4534
- try {
4535
- const existing = deliveryFeeInflight.get(cacheKey);
4536
- const promise = existing ?? (async () => {
4537
- const result = await client.delivery.getFee(latitude, longitude, country);
4538
- if (!result.ok) {
4539
- throw result.error;
4540
- }
4541
- return result.value;
4542
- })();
4543
- if (!existing) {
4544
- deliveryFeeInflight.set(
4545
- cacheKey,
4546
- promise.finally(() => {
4547
- deliveryFeeInflight.delete(cacheKey);
4548
- })
4549
- );
4550
- }
4551
- const value = await promise;
4552
- if (currentRequestId !== requestIdRef.current) return;
4553
- deliveryFeeCache.set(cacheKey, value);
4554
- setFee(value);
4555
- } catch (loadError) {
4556
- if (currentRequestId !== requestIdRef.current) return;
4557
- setError(loadError);
4558
- } finally {
4559
- if (currentRequestId === requestIdRef.current) {
4560
- setIsLoading(false);
4561
- }
4562
- }
4563
- },
4564
- [cacheKey, client, country, enabled, latitude, longitude]
4565
- );
4566
- useEffect(() => {
4567
- void load(false);
4568
- }, [load]);
4569
- const refetch = useCallback(async () => {
4570
- deliveryFeeCache.delete(cacheKey);
4571
- await load(true);
4572
- }, [cacheKey, load]);
4573
- return { fee, isLoading, error, refetch };
4574
- }
4575
- var fxRateCache = /* @__PURE__ */ new Map();
4576
- var fxRateInflight = /* @__PURE__ */ new Map();
4577
- function buildFxRateCacheKey(client, from, to) {
4578
- return JSON.stringify({ key: client.getPublicKey(), from, to });
3075
+ });
3076
+ function useDeliveryFee(options) {
3077
+ const { data, isLoading, error, refetch } = deliveryFeeQuery(options);
3078
+ return { fee: data, isLoading, error, refetch };
4579
3079
  }
4580
- function useFxRate(options) {
4581
- const context = useOptionalCimplifyClient();
4582
- const client = options.client ?? context?.client;
4583
- if (!client) {
4584
- throw new Error("useFxRate must be used within CimplifyProvider or passed { client }.");
3080
+
3081
+ // src/react/hooks/use-fx-rate.ts
3082
+ var fxRateQuery = createCachedQuery({
3083
+ name: "useFxRate",
3084
+ key: (client, options) => cacheKey(client.getPublicKey(), options.from, options.to),
3085
+ fetch: async (client, options) => {
3086
+ const result = await client.fx.getRate(options.from, options.to);
3087
+ if (!result.ok) throw result.error;
3088
+ return result.value;
4585
3089
  }
4586
- const enabled = options.enabled ?? true;
4587
- const { from, to } = options;
4588
- const cacheKey = useMemo(
4589
- () => buildFxRateCacheKey(client, from, to),
4590
- [client, from, to]
4591
- );
4592
- const cached = fxRateCache.get(cacheKey);
4593
- const [rate, setRate] = useState(cached ?? null);
4594
- const [isLoading, setIsLoading] = useState(enabled && !cached);
4595
- const [error, setError] = useState(null);
4596
- const load = useCallback(
4597
- async (force = false) => {
4598
- if (!enabled) {
4599
- setIsLoading(false);
4600
- return;
4601
- }
4602
- setError(null);
4603
- if (!force) {
4604
- const cachedRate = fxRateCache.get(cacheKey);
4605
- if (cachedRate) {
4606
- setRate(cachedRate);
4607
- setIsLoading(false);
4608
- return;
4609
- }
4610
- }
4611
- setIsLoading(true);
4612
- try {
4613
- const existing = fxRateInflight.get(cacheKey);
4614
- const promise = existing ?? (async () => {
4615
- const result = await client.fx.getRate(from, to);
4616
- if (!result.ok) {
4617
- throw result.error;
4618
- }
4619
- return result.value;
4620
- })();
4621
- if (!existing) {
4622
- fxRateInflight.set(
4623
- cacheKey,
4624
- promise.finally(() => {
4625
- fxRateInflight.delete(cacheKey);
4626
- })
4627
- );
4628
- }
4629
- const value = await promise;
4630
- fxRateCache.set(cacheKey, value);
4631
- setRate(value);
4632
- } catch (loadError) {
4633
- setError(loadError);
4634
- } finally {
4635
- setIsLoading(false);
4636
- }
4637
- },
4638
- [cacheKey, client, enabled, from, to]
4639
- );
4640
- useEffect(() => {
4641
- void load(false);
4642
- }, [load]);
4643
- const refetch = useCallback(async () => {
4644
- fxRateCache.delete(cacheKey);
4645
- await load(true);
4646
- }, [cacheKey, load]);
4647
- return { rate, isLoading, error, refetch };
4648
- }
4649
- var bootstrapCache = /* @__PURE__ */ new Map();
4650
- var bootstrapInflight = /* @__PURE__ */ new Map();
4651
- function buildBootstrapCacheKey(client) {
4652
- return JSON.stringify({ key: client.getPublicKey(), type: "bootstrap" });
3090
+ });
3091
+ function useFxRate(options) {
3092
+ const { data, isLoading, error, refetch } = fxRateQuery(options);
3093
+ return { rate: data, isLoading, error, refetch };
4653
3094
  }
4654
- function useBootstrap(options = {}) {
4655
- const context = useOptionalCimplifyClient();
4656
- const client = options.client ?? context?.client;
4657
- if (!client) {
4658
- throw new Error("useBootstrap must be used within CimplifyProvider or passed { client }.");
3095
+
3096
+ // src/react/hooks/use-bootstrap.ts
3097
+ var bootstrapQuery = createCachedQuery({
3098
+ name: "useBootstrap",
3099
+ key: (client) => cacheKey(client.getPublicKey()),
3100
+ fetch: async (client) => {
3101
+ const result = await client.business.getBootstrap();
3102
+ if (!result.ok) throw result.error;
3103
+ return result.value;
4659
3104
  }
4660
- const enabled = options.enabled ?? true;
4661
- const cacheKey = useMemo(() => buildBootstrapCacheKey(client), [client]);
4662
- const cached = bootstrapCache.get(cacheKey);
4663
- const [bootstrap, setBootstrap] = useState(cached ?? null);
4664
- const [isLoading, setIsLoading] = useState(enabled && !cached);
4665
- const [error, setError] = useState(null);
4666
- const load = useCallback(
4667
- async (force = false) => {
4668
- if (!enabled) {
4669
- setIsLoading(false);
4670
- return;
4671
- }
4672
- setError(null);
4673
- if (!force) {
4674
- const cachedBootstrap = bootstrapCache.get(cacheKey);
4675
- if (cachedBootstrap) {
4676
- setBootstrap(cachedBootstrap);
4677
- setIsLoading(false);
4678
- return;
4679
- }
4680
- }
4681
- setIsLoading(true);
4682
- try {
4683
- const existing = bootstrapInflight.get(cacheKey);
4684
- const promise = existing ?? (async () => {
4685
- const result = await client.business.getBootstrap();
4686
- if (!result.ok) {
4687
- throw result.error;
4688
- }
4689
- return result.value;
4690
- })();
4691
- if (!existing) {
4692
- bootstrapInflight.set(
4693
- cacheKey,
4694
- promise.finally(() => {
4695
- bootstrapInflight.delete(cacheKey);
4696
- })
4697
- );
4698
- }
4699
- const value = await promise;
4700
- bootstrapCache.set(cacheKey, value);
4701
- setBootstrap(value);
4702
- } catch (loadError) {
4703
- setError(loadError);
4704
- } finally {
4705
- setIsLoading(false);
4706
- }
4707
- },
4708
- [cacheKey, client, enabled]
4709
- );
4710
- useEffect(() => {
4711
- void load(false);
4712
- }, [load]);
4713
- const refetch = useCallback(async () => {
4714
- bootstrapCache.delete(cacheKey);
4715
- await load(true);
4716
- }, [cacheKey, load]);
4717
- return { bootstrap, isLoading, error, refetch };
3105
+ });
3106
+ function useBootstrap(options = {}) {
3107
+ const { data, isLoading, error, refetch } = bootstrapQuery(options);
3108
+ return { bootstrap: data, isLoading, error, refetch };
4718
3109
  }
4719
3110
  var ElementsContext = createContext({
4720
3111
  elements: null,