@braine/quantum-query 1.2.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -132,6 +132,32 @@ const user = await api.get<User>('/me');
132
132
 
133
133
  ---
134
134
 
135
+ ## 🔐 Authentication (Built-in)
136
+
137
+ No more interceptors. We handle token injection and **automatic refresh on 401** errors out of the box.
138
+
139
+ ```typescript
140
+ const client = createClient({
141
+ baseURL: 'https://api.myapp.com',
142
+ auth: {
143
+ // 1. Inject Token
144
+ getToken: () => localStorage.getItem('token'),
145
+
146
+ // 2. Refresh & Retry (Auto-called on 401)
147
+ onTokenExpired: async (client) => {
148
+ const newToken = await refreshToken();
149
+ localStorage.setItem('token', newToken);
150
+ return newToken; // Original request is automatically retried
151
+ },
152
+
153
+ // 3. Redirect on Fail
154
+ onAuthFailed: () => window.location.href = '/login'
155
+ }
156
+ });
157
+ ```
158
+
159
+ ---
160
+
135
161
  ## 🛡️ Data Integrity (Runtime Safety)
136
162
 
137
163
  Don't trust the backend. Validate it. We support **Zod**, **Valibot**, or **Yup** schemas directly in the hook.
package/dist/index.cjs CHANGED
@@ -793,6 +793,21 @@ var QueryCache = class {
793
793
  this.deduplicationCache.set(key, promise);
794
794
  return promise;
795
795
  };
796
+ /**
797
+ * Invalidate all queries
798
+ */
799
+ invalidateAll = () => {
800
+ for (const key of this.signals.keys()) {
801
+ this.signals.get(key)?.set(void 0);
802
+ }
803
+ };
804
+ /**
805
+ * Remove a specific query from cache
806
+ */
807
+ remove = (queryKey) => {
808
+ const key = this.generateKey(queryKey);
809
+ this.signals.delete(key);
810
+ };
796
811
  /**
797
812
  * Invalidate queries matching the key prefix
798
813
  * Marks them as undefined to trigger refetches without breaking subscriptions
@@ -1448,7 +1463,7 @@ function useQueryCache() {
1448
1463
  const [cache, setCache] = (0, import_react7.useState)(client.getAll());
1449
1464
  (0, import_react7.useEffect)(() => {
1450
1465
  const interval = setInterval(() => {
1451
- setCache({ ...client.getAll() });
1466
+ setCache(new Map(client.getAll()));
1452
1467
  }, 500);
1453
1468
  return () => clearInterval(interval);
1454
1469
  }, [client]);
@@ -1459,8 +1474,17 @@ function useQueryCache() {
1459
1474
  var import_jsx_runtime2 = require("react/jsx-runtime");
1460
1475
  function QuantumDevTools() {
1461
1476
  const [isOpen, setIsOpen] = (0, import_react8.useState)(false);
1477
+ const [filter, setFilter] = (0, import_react8.useState)("");
1462
1478
  const cache = useQueryCache();
1463
1479
  const client = useQueryClient();
1480
+ const entries = (0, import_react8.useMemo)(() => Array.from(cache.entries()), [cache]);
1481
+ const filteredEntries = (0, import_react8.useMemo)(() => {
1482
+ if (!filter) return entries;
1483
+ const search = filter.toLowerCase();
1484
+ return entries.filter(
1485
+ ([_, entry]) => entry.key.some((k) => String(k).toLowerCase().includes(search))
1486
+ );
1487
+ }, [entries, filter]);
1464
1488
  if (!isOpen) {
1465
1489
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1466
1490
  "button",
@@ -1468,22 +1492,28 @@ function QuantumDevTools() {
1468
1492
  onClick: () => setIsOpen(true),
1469
1493
  style: {
1470
1494
  position: "fixed",
1471
- bottom: "10px",
1472
- right: "10px",
1473
- background: "#000",
1474
- color: "#fff",
1475
- border: "none",
1495
+ bottom: "20px",
1496
+ right: "20px",
1497
+ background: "#111",
1498
+ color: "#b0fb5d",
1499
+ // Quantum Green
1500
+ border: "1px solid #333",
1476
1501
  borderRadius: "50%",
1477
- width: "40px",
1478
- height: "40px",
1502
+ width: "48px",
1503
+ height: "48px",
1479
1504
  cursor: "pointer",
1480
1505
  zIndex: 9999,
1481
- boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
1506
+ boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
1482
1507
  fontSize: "20px",
1483
1508
  display: "flex",
1484
1509
  alignItems: "center",
1485
- justifyContent: "center"
1510
+ justifyContent: "center",
1511
+ transition: "transform 0.2s",
1512
+ fontFamily: "monospace"
1486
1513
  },
1514
+ onMouseEnter: (e) => e.currentTarget.style.transform = "scale(1.1)",
1515
+ onMouseLeave: (e) => e.currentTarget.style.transform = "scale(1)",
1516
+ title: "Open Quantum DevTools",
1487
1517
  children: "\u26A1\uFE0F"
1488
1518
  }
1489
1519
  );
@@ -1493,27 +1523,39 @@ function QuantumDevTools() {
1493
1523
  bottom: 0,
1494
1524
  right: 0,
1495
1525
  width: "100%",
1496
- maxWidth: "600px",
1497
- height: "400px",
1498
- background: "#1a1a1a",
1499
- color: "#fff",
1500
- borderTopLeftRadius: "10px",
1501
- boxShadow: "0 -4px 20px rgba(0,0,0,0.3)",
1526
+ maxWidth: "650px",
1527
+ height: "450px",
1528
+ background: "#0a0a0a",
1529
+ color: "#e0e0e0",
1530
+ borderTopLeftRadius: "12px",
1531
+ boxShadow: "0 -10px 40px rgba(0,0,0,0.5)",
1502
1532
  zIndex: 9999,
1503
1533
  display: "flex",
1504
1534
  flexDirection: "column",
1505
- fontFamily: "monospace"
1535
+ fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
1536
+ fontSize: "13px",
1537
+ border: "1px solid #333"
1506
1538
  }, children: [
1507
1539
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: {
1508
- padding: "10px",
1509
- borderBottom: "1px solid #333",
1540
+ padding: "12px 16px",
1541
+ borderBottom: "1px solid #222",
1510
1542
  display: "flex",
1511
1543
  justifyContent: "space-between",
1512
1544
  alignItems: "center",
1513
- background: "#222",
1514
- borderTopLeftRadius: "10px"
1545
+ background: "#111",
1546
+ borderTopLeftRadius: "12px"
1515
1547
  }, children: [
1516
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontWeight: "bold" }, children: "\u26A1\uFE0F Quantum DevTools" }),
1548
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
1549
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#b0fb5d", fontSize: "16px" }, children: "\u26A1\uFE0F" }),
1550
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontWeight: 600, letterSpacing: "-0.5px" }, children: "Quantum DevTools" }),
1551
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: {
1552
+ background: "#222",
1553
+ padding: "2px 6px",
1554
+ borderRadius: "4px",
1555
+ fontSize: "10px",
1556
+ color: "#666"
1557
+ }, children: "v1.2.2" })
1558
+ ] }),
1517
1559
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1518
1560
  "button",
1519
1561
  {
@@ -1521,58 +1563,166 @@ function QuantumDevTools() {
1521
1563
  style: {
1522
1564
  background: "transparent",
1523
1565
  border: "none",
1524
- color: "#999",
1566
+ color: "#666",
1567
+ cursor: "pointer",
1568
+ fontSize: "20px",
1569
+ padding: "4px",
1570
+ lineHeight: 1
1571
+ },
1572
+ children: "\xD7"
1573
+ }
1574
+ )
1575
+ ] }),
1576
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: {
1577
+ padding: "8px 16px",
1578
+ borderBottom: "1px solid #222",
1579
+ background: "#0f0f0f",
1580
+ display: "flex",
1581
+ gap: "12px"
1582
+ }, children: [
1583
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1584
+ "input",
1585
+ {
1586
+ type: "text",
1587
+ placeholder: "Filter queries...",
1588
+ value: filter,
1589
+ onChange: (e) => setFilter(e.target.value),
1590
+ style: {
1591
+ background: "#1a1a1a",
1592
+ border: "1px solid #333",
1593
+ color: "#fff",
1594
+ padding: "6px 10px",
1595
+ borderRadius: "4px",
1596
+ flex: 1,
1597
+ fontSize: "12px",
1598
+ outline: "none"
1599
+ }
1600
+ }
1601
+ ),
1602
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1603
+ "button",
1604
+ {
1605
+ onClick: () => client.invalidateAll(),
1606
+ title: "Invalidate All Queries",
1607
+ style: {
1608
+ background: "#222",
1609
+ border: "1px solid #333",
1610
+ color: "#d69e2e",
1611
+ borderRadius: "4px",
1612
+ padding: "0 12px",
1525
1613
  cursor: "pointer",
1526
- fontSize: "16px"
1614
+ fontSize: "12px",
1615
+ fontWeight: 500
1527
1616
  },
1528
- children: "\u2715"
1617
+ children: "\u21BB Invalidate All"
1529
1618
  }
1530
1619
  )
1531
1620
  ] }),
1532
1621
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: {
1533
1622
  flex: 1,
1534
1623
  overflowY: "auto",
1535
- padding: "10px",
1624
+ padding: "8px",
1536
1625
  display: "flex",
1537
1626
  flexDirection: "column",
1538
- gap: "8px"
1539
- }, children: Array.from(cache.entries()).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: "20px", textAlign: "center", color: "#666" }, children: "No active queries" }) : Array.from(cache.entries()).map(([keyHash, entry]) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: {
1540
- background: "#2a2a2a",
1541
- borderRadius: "4px",
1542
- padding: "8px",
1543
- border: "1px solid #333"
1627
+ gap: "8px",
1628
+ background: "#050505"
1629
+ }, children: entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: {
1630
+ padding: "40px",
1631
+ textAlign: "center",
1632
+ color: "#444",
1633
+ fontStyle: "italic"
1634
+ }, children: "No active queries in cache." }) : filteredEntries.map(([keyHash, entry]) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1635
+ QueryItem,
1636
+ {
1637
+ entry,
1638
+ client,
1639
+ isStale: client.isStale(entry.key)
1640
+ },
1641
+ keyHash
1642
+ )) })
1643
+ ] });
1644
+ }
1645
+ function QueryItem({ entry, client, isStale }) {
1646
+ const [expanded, setExpanded] = (0, import_react8.useState)(false);
1647
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: {
1648
+ background: "#111",
1649
+ borderRadius: "6px",
1650
+ border: "1px solid #222",
1651
+ overflow: "hidden"
1652
+ }, children: [
1653
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1654
+ "div",
1655
+ {
1656
+ onClick: () => setExpanded(!expanded),
1657
+ style: {
1658
+ padding: "8px 12px",
1659
+ display: "flex",
1660
+ alignItems: "center",
1661
+ justifyContent: "space-between",
1662
+ cursor: "pointer",
1663
+ background: expanded ? "#161616" : "transparent"
1664
+ },
1665
+ children: [
1666
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "10px", alignItems: "center", overflow: "hidden" }, children: [
1667
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: {
1668
+ color: isStale ? "#d69e2e" : "#b0fb5d",
1669
+ fontSize: "14px",
1670
+ fontWeight: "bold",
1671
+ minWidth: "10px"
1672
+ }, children: isStale ? "\u2022" : "\u2022" }),
1673
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: {
1674
+ color: "#e0e0e0",
1675
+ fontWeight: 500,
1676
+ whiteSpace: "nowrap",
1677
+ overflow: "hidden",
1678
+ textOverflow: "ellipsis"
1679
+ }, children: [
1680
+ "['",
1681
+ entry.key.join("', '"),
1682
+ "']"
1683
+ ] })
1684
+ ] }),
1685
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
1686
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: {
1687
+ fontSize: "10px",
1688
+ padding: "2px 6px",
1689
+ borderRadius: "3px",
1690
+ background: isStale ? "rgba(214, 158, 46, 0.15)" : "rgba(176, 251, 93, 0.15)",
1691
+ color: isStale ? "#d69e2e" : "#b0fb5d",
1692
+ border: `1px solid ${isStale ? "rgba(214, 158, 46, 0.3)" : "rgba(176, 251, 93, 0.3)"}`
1693
+ }, children: isStale ? "STALE" : "FRESH" }),
1694
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#666", fontSize: "10px" }, children: expanded ? "\u25BC" : "\u25B6" })
1695
+ ] })
1696
+ ]
1697
+ }
1698
+ ),
1699
+ expanded && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: {
1700
+ padding: "10px",
1701
+ borderTop: "1px solid #222",
1702
+ background: "#0a0a0a"
1544
1703
  }, children: [
1545
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "8px" }, children: [
1546
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#aaa", fontSize: "12px" }, children: entry.key.map((k) => String(k)).join(" / ") }),
1547
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", gap: "5px" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: {
1548
- fontSize: "10px",
1549
- padding: "2px 4px",
1550
- borderRadius: "2px",
1551
- background: client.isStale(entry.key) ? "#dda0dd" : "#90ee90",
1552
- color: "#000"
1553
- }, children: client.isStale(entry.key) ? "STALE" : "FRESH" }) })
1554
- ] }),
1555
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: {
1556
- fontSize: "11px",
1557
- color: "#ddd",
1558
- whiteSpace: "pre-wrap",
1559
- maxHeight: "100px",
1560
- overflow: "hidden",
1561
- opacity: 0.8
1562
- }, children: JSON.stringify(entry.data, null, 2) }),
1563
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginTop: "8px", display: "flex", gap: "8px" }, children: [
1704
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: {
1705
+ display: "flex",
1706
+ gap: "8px",
1707
+ marginBottom: "10px",
1708
+ borderBottom: "1px solid #222",
1709
+ paddingBottom: "8px"
1710
+ }, children: [
1564
1711
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1565
1712
  "button",
1566
1713
  {
1567
- onClick: () => client.invalidate(entry.key),
1714
+ onClick: (e) => {
1715
+ e.stopPropagation();
1716
+ client.invalidate(entry.key);
1717
+ },
1568
1718
  style: {
1569
- background: "#444",
1570
- border: "none",
1571
- color: "#fff",
1572
- padding: "4px 8px",
1573
- borderRadius: "3px",
1719
+ background: "#222",
1720
+ border: "1px solid #333",
1721
+ color: "#d69e2e",
1722
+ padding: "4px 10px",
1723
+ borderRadius: "4px",
1574
1724
  cursor: "pointer",
1575
- fontSize: "10px"
1725
+ fontSize: "11px"
1576
1726
  },
1577
1727
  children: "Invalidate"
1578
1728
  }
@@ -1580,23 +1730,40 @@ function QuantumDevTools() {
1580
1730
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1581
1731
  "button",
1582
1732
  {
1583
- onClick: () => {
1584
- client.invalidate(entry.key);
1733
+ onClick: (e) => {
1734
+ e.stopPropagation();
1735
+ client.remove(entry.key);
1585
1736
  },
1586
1737
  style: {
1587
- background: "#444",
1588
- border: "none",
1589
- color: "#fff",
1590
- padding: "4px 8px",
1591
- borderRadius: "3px",
1738
+ background: "#222",
1739
+ border: "1px solid #333",
1740
+ color: "#ff4d4f",
1741
+ padding: "4px 10px",
1742
+ borderRadius: "4px",
1592
1743
  cursor: "pointer",
1593
- fontSize: "10px"
1744
+ fontSize: "11px"
1594
1745
  },
1595
- children: "Refetch"
1746
+ children: "Remove"
1596
1747
  }
1597
1748
  )
1749
+ ] }),
1750
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { position: "relative" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("pre", { style: {
1751
+ margin: 0,
1752
+ fontSize: "11px",
1753
+ color: "#a0a0a0",
1754
+ overflowX: "auto",
1755
+ fontFamily: "monospace"
1756
+ }, children: JSON.stringify(entry.data, null, 2) }) }),
1757
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: {
1758
+ marginTop: "8px",
1759
+ fontSize: "10px",
1760
+ color: "#444",
1761
+ textAlign: "right"
1762
+ }, children: [
1763
+ "Updated: ",
1764
+ new Date(entry.updatedAt).toLocaleTimeString()
1598
1765
  ] })
1599
- ] }, keyHash)) })
1766
+ ] })
1600
1767
  ] });
1601
1768
  }
1602
1769
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.d.cts CHANGED
@@ -183,6 +183,14 @@ declare class QueryCache {
183
183
  * If a request for the same key is already in flight, returns the existing promise.
184
184
  */
185
185
  fetch: <T>(queryKey: QueryKeyInput, fn: () => Promise<T>) => Promise<T>;
186
+ /**
187
+ * Invalidate all queries
188
+ */
189
+ invalidateAll: () => void;
190
+ /**
191
+ * Remove a specific query from cache
192
+ */
193
+ remove: (queryKey: QueryKeyInput) => void;
186
194
  /**
187
195
  * Invalidate queries matching the key prefix
188
196
  * Marks them as undefined to trigger refetches without breaking subscriptions
package/dist/index.d.ts CHANGED
@@ -183,6 +183,14 @@ declare class QueryCache {
183
183
  * If a request for the same key is already in flight, returns the existing promise.
184
184
  */
185
185
  fetch: <T>(queryKey: QueryKeyInput, fn: () => Promise<T>) => Promise<T>;
186
+ /**
187
+ * Invalidate all queries
188
+ */
189
+ invalidateAll: () => void;
190
+ /**
191
+ * Remove a specific query from cache
192
+ */
193
+ remove: (queryKey: QueryKeyInput) => void;
186
194
  /**
187
195
  * Invalidate queries matching the key prefix
188
196
  * Marks them as undefined to trigger refetches without breaking subscriptions
package/dist/index.js CHANGED
@@ -745,6 +745,21 @@ var QueryCache = class {
745
745
  this.deduplicationCache.set(key, promise);
746
746
  return promise;
747
747
  };
748
+ /**
749
+ * Invalidate all queries
750
+ */
751
+ invalidateAll = () => {
752
+ for (const key of this.signals.keys()) {
753
+ this.signals.get(key)?.set(void 0);
754
+ }
755
+ };
756
+ /**
757
+ * Remove a specific query from cache
758
+ */
759
+ remove = (queryKey) => {
760
+ const key = this.generateKey(queryKey);
761
+ this.signals.delete(key);
762
+ };
748
763
  /**
749
764
  * Invalidate queries matching the key prefix
750
765
  * Marks them as undefined to trigger refetches without breaking subscriptions
@@ -1391,7 +1406,7 @@ function useInfiniteQuery({
1391
1406
  }
1392
1407
 
1393
1408
  // src/addon/query/devtools.tsx
1394
- import { useState as useState5 } from "react";
1409
+ import { useState as useState5, useMemo } from "react";
1395
1410
 
1396
1411
  // src/addon/query/useQueryCache.ts
1397
1412
  import { useState as useState4, useEffect as useEffect5 } from "react";
@@ -1400,7 +1415,7 @@ function useQueryCache() {
1400
1415
  const [cache, setCache] = useState4(client.getAll());
1401
1416
  useEffect5(() => {
1402
1417
  const interval = setInterval(() => {
1403
- setCache({ ...client.getAll() });
1418
+ setCache(new Map(client.getAll()));
1404
1419
  }, 500);
1405
1420
  return () => clearInterval(interval);
1406
1421
  }, [client]);
@@ -1411,8 +1426,17 @@ function useQueryCache() {
1411
1426
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
1412
1427
  function QuantumDevTools() {
1413
1428
  const [isOpen, setIsOpen] = useState5(false);
1429
+ const [filter, setFilter] = useState5("");
1414
1430
  const cache = useQueryCache();
1415
1431
  const client = useQueryClient();
1432
+ const entries = useMemo(() => Array.from(cache.entries()), [cache]);
1433
+ const filteredEntries = useMemo(() => {
1434
+ if (!filter) return entries;
1435
+ const search = filter.toLowerCase();
1436
+ return entries.filter(
1437
+ ([_, entry]) => entry.key.some((k) => String(k).toLowerCase().includes(search))
1438
+ );
1439
+ }, [entries, filter]);
1416
1440
  if (!isOpen) {
1417
1441
  return /* @__PURE__ */ jsx2(
1418
1442
  "button",
@@ -1420,22 +1444,28 @@ function QuantumDevTools() {
1420
1444
  onClick: () => setIsOpen(true),
1421
1445
  style: {
1422
1446
  position: "fixed",
1423
- bottom: "10px",
1424
- right: "10px",
1425
- background: "#000",
1426
- color: "#fff",
1427
- border: "none",
1447
+ bottom: "20px",
1448
+ right: "20px",
1449
+ background: "#111",
1450
+ color: "#b0fb5d",
1451
+ // Quantum Green
1452
+ border: "1px solid #333",
1428
1453
  borderRadius: "50%",
1429
- width: "40px",
1430
- height: "40px",
1454
+ width: "48px",
1455
+ height: "48px",
1431
1456
  cursor: "pointer",
1432
1457
  zIndex: 9999,
1433
- boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
1458
+ boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
1434
1459
  fontSize: "20px",
1435
1460
  display: "flex",
1436
1461
  alignItems: "center",
1437
- justifyContent: "center"
1462
+ justifyContent: "center",
1463
+ transition: "transform 0.2s",
1464
+ fontFamily: "monospace"
1438
1465
  },
1466
+ onMouseEnter: (e) => e.currentTarget.style.transform = "scale(1.1)",
1467
+ onMouseLeave: (e) => e.currentTarget.style.transform = "scale(1)",
1468
+ title: "Open Quantum DevTools",
1439
1469
  children: "\u26A1\uFE0F"
1440
1470
  }
1441
1471
  );
@@ -1445,27 +1475,39 @@ function QuantumDevTools() {
1445
1475
  bottom: 0,
1446
1476
  right: 0,
1447
1477
  width: "100%",
1448
- maxWidth: "600px",
1449
- height: "400px",
1450
- background: "#1a1a1a",
1451
- color: "#fff",
1452
- borderTopLeftRadius: "10px",
1453
- boxShadow: "0 -4px 20px rgba(0,0,0,0.3)",
1478
+ maxWidth: "650px",
1479
+ height: "450px",
1480
+ background: "#0a0a0a",
1481
+ color: "#e0e0e0",
1482
+ borderTopLeftRadius: "12px",
1483
+ boxShadow: "0 -10px 40px rgba(0,0,0,0.5)",
1454
1484
  zIndex: 9999,
1455
1485
  display: "flex",
1456
1486
  flexDirection: "column",
1457
- fontFamily: "monospace"
1487
+ fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
1488
+ fontSize: "13px",
1489
+ border: "1px solid #333"
1458
1490
  }, children: [
1459
1491
  /* @__PURE__ */ jsxs("div", { style: {
1460
- padding: "10px",
1461
- borderBottom: "1px solid #333",
1492
+ padding: "12px 16px",
1493
+ borderBottom: "1px solid #222",
1462
1494
  display: "flex",
1463
1495
  justifyContent: "space-between",
1464
1496
  alignItems: "center",
1465
- background: "#222",
1466
- borderTopLeftRadius: "10px"
1497
+ background: "#111",
1498
+ borderTopLeftRadius: "12px"
1467
1499
  }, children: [
1468
- /* @__PURE__ */ jsx2("span", { style: { fontWeight: "bold" }, children: "\u26A1\uFE0F Quantum DevTools" }),
1500
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
1501
+ /* @__PURE__ */ jsx2("span", { style: { color: "#b0fb5d", fontSize: "16px" }, children: "\u26A1\uFE0F" }),
1502
+ /* @__PURE__ */ jsx2("span", { style: { fontWeight: 600, letterSpacing: "-0.5px" }, children: "Quantum DevTools" }),
1503
+ /* @__PURE__ */ jsx2("span", { style: {
1504
+ background: "#222",
1505
+ padding: "2px 6px",
1506
+ borderRadius: "4px",
1507
+ fontSize: "10px",
1508
+ color: "#666"
1509
+ }, children: "v1.2.2" })
1510
+ ] }),
1469
1511
  /* @__PURE__ */ jsx2(
1470
1512
  "button",
1471
1513
  {
@@ -1473,58 +1515,166 @@ function QuantumDevTools() {
1473
1515
  style: {
1474
1516
  background: "transparent",
1475
1517
  border: "none",
1476
- color: "#999",
1518
+ color: "#666",
1519
+ cursor: "pointer",
1520
+ fontSize: "20px",
1521
+ padding: "4px",
1522
+ lineHeight: 1
1523
+ },
1524
+ children: "\xD7"
1525
+ }
1526
+ )
1527
+ ] }),
1528
+ /* @__PURE__ */ jsxs("div", { style: {
1529
+ padding: "8px 16px",
1530
+ borderBottom: "1px solid #222",
1531
+ background: "#0f0f0f",
1532
+ display: "flex",
1533
+ gap: "12px"
1534
+ }, children: [
1535
+ /* @__PURE__ */ jsx2(
1536
+ "input",
1537
+ {
1538
+ type: "text",
1539
+ placeholder: "Filter queries...",
1540
+ value: filter,
1541
+ onChange: (e) => setFilter(e.target.value),
1542
+ style: {
1543
+ background: "#1a1a1a",
1544
+ border: "1px solid #333",
1545
+ color: "#fff",
1546
+ padding: "6px 10px",
1547
+ borderRadius: "4px",
1548
+ flex: 1,
1549
+ fontSize: "12px",
1550
+ outline: "none"
1551
+ }
1552
+ }
1553
+ ),
1554
+ /* @__PURE__ */ jsx2(
1555
+ "button",
1556
+ {
1557
+ onClick: () => client.invalidateAll(),
1558
+ title: "Invalidate All Queries",
1559
+ style: {
1560
+ background: "#222",
1561
+ border: "1px solid #333",
1562
+ color: "#d69e2e",
1563
+ borderRadius: "4px",
1564
+ padding: "0 12px",
1477
1565
  cursor: "pointer",
1478
- fontSize: "16px"
1566
+ fontSize: "12px",
1567
+ fontWeight: 500
1479
1568
  },
1480
- children: "\u2715"
1569
+ children: "\u21BB Invalidate All"
1481
1570
  }
1482
1571
  )
1483
1572
  ] }),
1484
1573
  /* @__PURE__ */ jsx2("div", { style: {
1485
1574
  flex: 1,
1486
1575
  overflowY: "auto",
1487
- padding: "10px",
1576
+ padding: "8px",
1488
1577
  display: "flex",
1489
1578
  flexDirection: "column",
1490
- gap: "8px"
1491
- }, children: Array.from(cache.entries()).length === 0 ? /* @__PURE__ */ jsx2("div", { style: { padding: "20px", textAlign: "center", color: "#666" }, children: "No active queries" }) : Array.from(cache.entries()).map(([keyHash, entry]) => /* @__PURE__ */ jsxs("div", { style: {
1492
- background: "#2a2a2a",
1493
- borderRadius: "4px",
1494
- padding: "8px",
1495
- border: "1px solid #333"
1579
+ gap: "8px",
1580
+ background: "#050505"
1581
+ }, children: entries.length === 0 ? /* @__PURE__ */ jsx2("div", { style: {
1582
+ padding: "40px",
1583
+ textAlign: "center",
1584
+ color: "#444",
1585
+ fontStyle: "italic"
1586
+ }, children: "No active queries in cache." }) : filteredEntries.map(([keyHash, entry]) => /* @__PURE__ */ jsx2(
1587
+ QueryItem,
1588
+ {
1589
+ entry,
1590
+ client,
1591
+ isStale: client.isStale(entry.key)
1592
+ },
1593
+ keyHash
1594
+ )) })
1595
+ ] });
1596
+ }
1597
+ function QueryItem({ entry, client, isStale }) {
1598
+ const [expanded, setExpanded] = useState5(false);
1599
+ return /* @__PURE__ */ jsxs("div", { style: {
1600
+ background: "#111",
1601
+ borderRadius: "6px",
1602
+ border: "1px solid #222",
1603
+ overflow: "hidden"
1604
+ }, children: [
1605
+ /* @__PURE__ */ jsxs(
1606
+ "div",
1607
+ {
1608
+ onClick: () => setExpanded(!expanded),
1609
+ style: {
1610
+ padding: "8px 12px",
1611
+ display: "flex",
1612
+ alignItems: "center",
1613
+ justifyContent: "space-between",
1614
+ cursor: "pointer",
1615
+ background: expanded ? "#161616" : "transparent"
1616
+ },
1617
+ children: [
1618
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "10px", alignItems: "center", overflow: "hidden" }, children: [
1619
+ /* @__PURE__ */ jsx2("span", { style: {
1620
+ color: isStale ? "#d69e2e" : "#b0fb5d",
1621
+ fontSize: "14px",
1622
+ fontWeight: "bold",
1623
+ minWidth: "10px"
1624
+ }, children: isStale ? "\u2022" : "\u2022" }),
1625
+ /* @__PURE__ */ jsxs("span", { style: {
1626
+ color: "#e0e0e0",
1627
+ fontWeight: 500,
1628
+ whiteSpace: "nowrap",
1629
+ overflow: "hidden",
1630
+ textOverflow: "ellipsis"
1631
+ }, children: [
1632
+ "['",
1633
+ entry.key.join("', '"),
1634
+ "']"
1635
+ ] })
1636
+ ] }),
1637
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
1638
+ /* @__PURE__ */ jsx2("span", { style: {
1639
+ fontSize: "10px",
1640
+ padding: "2px 6px",
1641
+ borderRadius: "3px",
1642
+ background: isStale ? "rgba(214, 158, 46, 0.15)" : "rgba(176, 251, 93, 0.15)",
1643
+ color: isStale ? "#d69e2e" : "#b0fb5d",
1644
+ border: `1px solid ${isStale ? "rgba(214, 158, 46, 0.3)" : "rgba(176, 251, 93, 0.3)"}`
1645
+ }, children: isStale ? "STALE" : "FRESH" }),
1646
+ /* @__PURE__ */ jsx2("span", { style: { color: "#666", fontSize: "10px" }, children: expanded ? "\u25BC" : "\u25B6" })
1647
+ ] })
1648
+ ]
1649
+ }
1650
+ ),
1651
+ expanded && /* @__PURE__ */ jsxs("div", { style: {
1652
+ padding: "10px",
1653
+ borderTop: "1px solid #222",
1654
+ background: "#0a0a0a"
1496
1655
  }, children: [
1497
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "8px" }, children: [
1498
- /* @__PURE__ */ jsx2("span", { style: { color: "#aaa", fontSize: "12px" }, children: entry.key.map((k) => String(k)).join(" / ") }),
1499
- /* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: "5px" }, children: /* @__PURE__ */ jsx2("span", { style: {
1500
- fontSize: "10px",
1501
- padding: "2px 4px",
1502
- borderRadius: "2px",
1503
- background: client.isStale(entry.key) ? "#dda0dd" : "#90ee90",
1504
- color: "#000"
1505
- }, children: client.isStale(entry.key) ? "STALE" : "FRESH" }) })
1506
- ] }),
1507
- /* @__PURE__ */ jsx2("div", { style: {
1508
- fontSize: "11px",
1509
- color: "#ddd",
1510
- whiteSpace: "pre-wrap",
1511
- maxHeight: "100px",
1512
- overflow: "hidden",
1513
- opacity: 0.8
1514
- }, children: JSON.stringify(entry.data, null, 2) }),
1515
- /* @__PURE__ */ jsxs("div", { style: { marginTop: "8px", display: "flex", gap: "8px" }, children: [
1656
+ /* @__PURE__ */ jsxs("div", { style: {
1657
+ display: "flex",
1658
+ gap: "8px",
1659
+ marginBottom: "10px",
1660
+ borderBottom: "1px solid #222",
1661
+ paddingBottom: "8px"
1662
+ }, children: [
1516
1663
  /* @__PURE__ */ jsx2(
1517
1664
  "button",
1518
1665
  {
1519
- onClick: () => client.invalidate(entry.key),
1666
+ onClick: (e) => {
1667
+ e.stopPropagation();
1668
+ client.invalidate(entry.key);
1669
+ },
1520
1670
  style: {
1521
- background: "#444",
1522
- border: "none",
1523
- color: "#fff",
1524
- padding: "4px 8px",
1525
- borderRadius: "3px",
1671
+ background: "#222",
1672
+ border: "1px solid #333",
1673
+ color: "#d69e2e",
1674
+ padding: "4px 10px",
1675
+ borderRadius: "4px",
1526
1676
  cursor: "pointer",
1527
- fontSize: "10px"
1677
+ fontSize: "11px"
1528
1678
  },
1529
1679
  children: "Invalidate"
1530
1680
  }
@@ -1532,23 +1682,40 @@ function QuantumDevTools() {
1532
1682
  /* @__PURE__ */ jsx2(
1533
1683
  "button",
1534
1684
  {
1535
- onClick: () => {
1536
- client.invalidate(entry.key);
1685
+ onClick: (e) => {
1686
+ e.stopPropagation();
1687
+ client.remove(entry.key);
1537
1688
  },
1538
1689
  style: {
1539
- background: "#444",
1540
- border: "none",
1541
- color: "#fff",
1542
- padding: "4px 8px",
1543
- borderRadius: "3px",
1690
+ background: "#222",
1691
+ border: "1px solid #333",
1692
+ color: "#ff4d4f",
1693
+ padding: "4px 10px",
1694
+ borderRadius: "4px",
1544
1695
  cursor: "pointer",
1545
- fontSize: "10px"
1696
+ fontSize: "11px"
1546
1697
  },
1547
- children: "Refetch"
1698
+ children: "Remove"
1548
1699
  }
1549
1700
  )
1701
+ ] }),
1702
+ /* @__PURE__ */ jsx2("div", { style: { position: "relative" }, children: /* @__PURE__ */ jsx2("pre", { style: {
1703
+ margin: 0,
1704
+ fontSize: "11px",
1705
+ color: "#a0a0a0",
1706
+ overflowX: "auto",
1707
+ fontFamily: "monospace"
1708
+ }, children: JSON.stringify(entry.data, null, 2) }) }),
1709
+ /* @__PURE__ */ jsxs("div", { style: {
1710
+ marginTop: "8px",
1711
+ fontSize: "10px",
1712
+ color: "#444",
1713
+ textAlign: "right"
1714
+ }, children: [
1715
+ "Updated: ",
1716
+ new Date(entry.updatedAt).toLocaleTimeString()
1550
1717
  ] })
1551
- ] }, keyHash)) })
1718
+ ] })
1552
1719
  ] });
1553
1720
  }
1554
1721
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@braine/quantum-query",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "scripts": {