@upstash/react-redis-browser 0.1.2-canary-5 → 0.1.2-canary-7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.css CHANGED
@@ -971,6 +971,10 @@
971
971
  .ups-db .p-6 {
972
972
  padding: 1.5rem;
973
973
  }
974
+ .ups-db .px-0 {
975
+ padding-left: 0px;
976
+ padding-right: 0px;
977
+ }
974
978
  .ups-db .px-2 {
975
979
  padding-left: 0.5rem;
976
980
  padding-right: 0.5rem;
package/dist/index.js CHANGED
@@ -2891,6 +2891,12 @@ function Toaster() {
2891
2891
 
2892
2892
 
2893
2893
 
2894
+
2895
+
2896
+
2897
+
2898
+
2899
+
2894
2900
  // src/components/databrowser/hooks/use-fetch-keys.ts
2895
2901
 
2896
2902
 
@@ -2908,35 +2914,28 @@ var DATA_TYPE_NAMES = {
2908
2914
 
2909
2915
  // src/components/databrowser/hooks/use-fetch-keys.ts
2910
2916
  var PAGE_SIZE = 30;
2911
- var INITIAL_FETCH_COUNT = 100;
2912
- var MAX_FETCH_COUNT = 1e3;
2917
+ var FETCH_COUNTS = [100, 200, 400, 800];
2913
2918
  var useFetchKeys = (search) => {
2914
2919
  const { redis } = useDatabrowser();
2915
2920
  const cache = _react.useRef.call(void 0, );
2916
2921
  const lastKey = _react.useRef.call(void 0, );
2917
- const getPage = _react.useCallback.call(void 0,
2918
- (page) => {
2919
- const newKey = JSON.stringify(search);
2920
- if (!cache.current || lastKey.current !== newKey) {
2921
- cache.current = new PaginationCache(redis, search.key, search.type);
2922
- lastKey.current = newKey;
2923
- }
2924
- return cache.current.getPage(page);
2925
- },
2926
- [search]
2927
- );
2922
+ const fetchKeys = _react.useCallback.call(void 0, () => {
2923
+ const newKey = JSON.stringify(search);
2924
+ if (!cache.current || lastKey.current !== newKey) {
2925
+ cache.current = new PaginationCache(redis, search.key, search.type);
2926
+ lastKey.current = newKey;
2927
+ }
2928
+ return cache.current.fetchNewKeys();
2929
+ }, [search]);
2928
2930
  const resetCache = _react.useCallback.call(void 0, () => {
2929
2931
  cache.current = void 0;
2930
2932
  lastKey.current = void 0;
2931
2933
  }, []);
2932
2934
  return {
2933
- getPage,
2935
+ fetchKeys,
2934
2936
  resetCache
2935
2937
  };
2936
2938
  };
2937
- function slicePage(keys, page) {
2938
- return keys.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE);
2939
- }
2940
2939
  var PaginationCache = (_class = class {
2941
2940
  constructor(redis, searchTerm, typeFilter) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);
2942
2941
  this.redis = redis;
@@ -2952,8 +2951,9 @@ var PaginationCache = (_class = class {
2952
2951
  )}
2953
2952
  __init2() {this.targetCount = 0}
2954
2953
  __init3() {this.isFetching = false}
2955
- async getPage(page) {
2956
- this.targetCount = (page + 1) * PAGE_SIZE + 1;
2954
+ async fetchNewKeys() {
2955
+ const initialKeys = new Set(this.getKeys().map(([key]) => key));
2956
+ this.targetCount = this.getKeys().length + PAGE_SIZE;
2957
2957
  void this.startFetch();
2958
2958
  await new Promise((resolve) => {
2959
2959
  const interval = setInterval(() => {
@@ -2963,10 +2963,9 @@ var PaginationCache = (_class = class {
2963
2963
  }
2964
2964
  }, 100);
2965
2965
  });
2966
- const hasEnoughForNextPage = this.getLength() > (page + 1) * PAGE_SIZE;
2967
- const hasNextPage = !this.isAllEnded() || hasEnoughForNextPage;
2966
+ const hasNextPage = !this.isAllEnded();
2968
2967
  return {
2969
- keys: slicePage(this.getKeys(), page),
2968
+ keys: this.getKeys().filter(([key]) => !initialKeys.has(key)),
2970
2969
  hasNextPage
2971
2970
  };
2972
2971
  }
@@ -2992,33 +2991,29 @@ var PaginationCache = (_class = class {
2992
2991
  }
2993
2992
  }
2994
2993
  __init4() {this.fetchForType = async (type) => {
2995
- let fetchCount = INITIAL_FETCH_COUNT;
2994
+ let i = 0;
2996
2995
  while (true) {
2997
2996
  const cursor = this.cache[type].cursor;
2998
2997
  if (cursor === "-1" || this.getLength() >= this.targetCount) {
2999
2998
  break;
3000
2999
  }
3000
+ const fetchCount = FETCH_COUNTS[Math.min(i, FETCH_COUNTS.length - 1)];
3001
3001
  const [nextCursor, newKeys] = await this.redis.scan(cursor, {
3002
3002
  count: fetchCount,
3003
3003
  match: this.searchTerm,
3004
3004
  type
3005
3005
  });
3006
- fetchCount = Math.min(fetchCount * 2, MAX_FETCH_COUNT);
3007
- const dedupedSet = /* @__PURE__ */ new Set([...this.cache[type].keys, ...newKeys]);
3008
- this.cache[type].keys = [...dedupedSet];
3006
+ this.cache[type].keys = [...this.cache[type].keys, ...newKeys];
3009
3007
  this.cache[type].cursor = nextCursor === "0" ? "-1" : nextCursor;
3008
+ i++;
3010
3009
  }
3011
3010
  }}
3012
3011
  async fetch() {
3013
3012
  const types = this.typeFilter ? [this.typeFilter] : DATA_TYPES;
3014
3013
  await Promise.all(types.map(this.fetchForType));
3015
3014
  }
3016
- // TODO: Yusuf, implement this function
3017
3015
  isAllEnded() {
3018
3016
  const types = this.typeFilter ? [this.typeFilter] : DATA_TYPES;
3019
- if (!Array.isArray(types)) {
3020
- throw new TypeError("types is not an array");
3021
- }
3022
3017
  return types.every((type) => this.cache[type] && this.cache[type].cursor === "-1");
3023
3018
  }
3024
3019
  }, _class);
@@ -3036,17 +3031,21 @@ var KeysProvider = ({ children }) => {
3036
3031
  }),
3037
3032
  [searchState]
3038
3033
  );
3039
- const { getPage, resetCache } = useFetchKeys(search);
3034
+ const { fetchKeys, resetCache } = useFetchKeys(search);
3035
+ const pageRef = _react.useRef.call(void 0, 0);
3040
3036
  const query = _reactquery.useInfiniteQuery.call(void 0, {
3041
3037
  queryKey: [FETCH_KEYS_QUERY_KEY, search],
3042
3038
  initialPageParam: 0,
3043
- queryFn: async ({ pageParam: pageIndex }) => {
3044
- return getPage(pageIndex);
3039
+ queryFn: async ({ pageParam: page }) => {
3040
+ if (pageRef.current >= page) resetCache();
3041
+ pageRef.current = page;
3042
+ return await fetchKeys();
3045
3043
  },
3046
3044
  select: (data) => data,
3047
3045
  getNextPageParam: (lastPage, __, lastPageIndex) => {
3048
3046
  return lastPage.hasNextPage ? lastPageIndex + 1 : void 0;
3049
- }
3047
+ },
3048
+ refetchOnMount: false
3050
3049
  });
3051
3050
  const refetch = _react.useCallback.call(void 0, () => {
3052
3051
  resetCache();
@@ -3054,8 +3053,14 @@ var KeysProvider = ({ children }) => {
3054
3053
  }, [query, resetCache]);
3055
3054
  const keys = _react.useMemo.call(void 0, () => {
3056
3055
  const keys2 = _nullishCoalesce(_optionalChain([query, 'access', _10 => _10.data, 'optionalAccess', _11 => _11.pages, 'access', _12 => _12.flatMap, 'call', _13 => _13((page) => page.keys)]), () => ( []));
3057
- const keysSet = new Set(keys2.map(([key, _]) => key));
3058
- return keys2.filter(([key, _]) => keysSet.has(key));
3056
+ const keysSet = /* @__PURE__ */ new Set();
3057
+ const dedupedKeys = [];
3058
+ for (const key of keys2) {
3059
+ if (keysSet.has(key[0])) continue;
3060
+ keysSet.add(key[0]);
3061
+ dedupedKeys.push(key);
3062
+ }
3063
+ return dedupedKeys;
3059
3064
  }, [query.data]);
3060
3065
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3061
3066
  KeysContext.Provider,
@@ -3171,39 +3176,39 @@ var useAddKey = () => {
3171
3176
  mutationFn: async ({ key, type }) => {
3172
3177
  switch (type) {
3173
3178
  case "set": {
3174
- redis.sadd(key, "value");
3179
+ await redis.sadd(key, "value");
3175
3180
  break;
3176
3181
  }
3177
3182
  case "zset": {
3178
- redis.zadd(key, {
3183
+ await redis.zadd(key, {
3179
3184
  member: "value",
3180
3185
  score: 0
3181
3186
  });
3182
3187
  break;
3183
3188
  }
3184
3189
  case "hash": {
3185
- redis.hset(key, {
3190
+ await redis.hset(key, {
3186
3191
  field: "field",
3187
3192
  value: "value"
3188
3193
  });
3189
3194
  break;
3190
3195
  }
3191
3196
  case "list": {
3192
- redis.lpush(key, "value");
3197
+ await redis.lpush(key, "value");
3193
3198
  break;
3194
3199
  }
3195
3200
  case "stream": {
3196
- redis.xadd(key, "*", {
3201
+ await redis.xadd(key, "*", {
3197
3202
  foo: "bar"
3198
3203
  });
3199
3204
  break;
3200
3205
  }
3201
3206
  case "string": {
3202
- redis.set(key, "value");
3207
+ await redis.set(key, "value");
3203
3208
  break;
3204
3209
  }
3205
3210
  case "json": {
3206
- redis.json.set(key, "$", {
3211
+ await redis.json.set(key, "$", {
3207
3212
  foo: "bar"
3208
3213
  });
3209
3214
  break;
@@ -3802,7 +3807,9 @@ function DeleteAlertDialog({
3802
3807
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, AlertDialogDescription, { className: "mt-5", children: [
3803
3808
  "Are you sure you want to delete this ",
3804
3809
  deletionType,
3805
- "? This action cannot be undone."
3810
+ "?",
3811
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "br", {}),
3812
+ "This action cannot be undone."
3806
3813
  ] })
3807
3814
  ] }),
3808
3815
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, AlertDialogFooter, { children: [
@@ -3825,12 +3832,11 @@ function DeleteAlertDialog({
3825
3832
  var ItemContextMenu = ({
3826
3833
  children,
3827
3834
  dataKey,
3828
- itemKey,
3829
- itemValue,
3830
3835
  type
3831
3836
  }) => {
3832
3837
  const { mutate: editItem } = useEditListItem();
3833
3838
  const [isAlertOpen, setAlertOpen] = _react.useState.call(void 0, false);
3839
+ const [data, setData] = _react.useState.call(void 0, );
3834
3840
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
3835
3841
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3836
3842
  DeleteAlertDialog,
@@ -3840,25 +3846,46 @@ var ItemContextMenu = ({
3840
3846
  onOpenChange: setAlertOpen,
3841
3847
  onDeleteConfirm: (e) => {
3842
3848
  e.stopPropagation();
3843
- editItem({
3844
- type,
3845
- dataKey,
3846
- itemKey,
3847
- // For deletion
3848
- newKey: void 0
3849
- });
3849
+ if (data) {
3850
+ editItem({
3851
+ type,
3852
+ dataKey,
3853
+ itemKey: _optionalChain([data, 'optionalAccess', _20 => _20.key]),
3854
+ // For deletion
3855
+ newKey: void 0
3856
+ });
3857
+ }
3850
3858
  setAlertOpen(false);
3851
3859
  }
3852
3860
  }
3853
3861
  ),
3854
3862
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ContextMenu, { children: [
3855
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ContextMenuTrigger, { asChild: true, children }),
3863
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3864
+ ContextMenuTrigger,
3865
+ {
3866
+ asChild: true,
3867
+ onContextMenu: (e) => {
3868
+ const el = e.target;
3869
+ const item = el.closest("[data-item-key]");
3870
+ if (item && item instanceof HTMLElement && item.dataset.itemKey !== void 0) {
3871
+ setData({
3872
+ key: item.dataset.itemKey,
3873
+ value: item.dataset.itemValue
3874
+ });
3875
+ } else {
3876
+ throw new Error("Key not found");
3877
+ }
3878
+ },
3879
+ children
3880
+ }
3881
+ ),
3856
3882
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ContextMenuContent, { children: [
3857
3883
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3858
3884
  ContextMenuItem,
3859
3885
  {
3860
3886
  onClick: () => {
3861
- navigator.clipboard.writeText(itemKey);
3887
+ if (!data) return;
3888
+ navigator.clipboard.writeText(_optionalChain([data, 'optionalAccess', _21 => _21.key]));
3862
3889
  toast({
3863
3890
  description: "Key copied to clipboard"
3864
3891
  });
@@ -3866,11 +3893,11 @@ var ItemContextMenu = ({
3866
3893
  children: "Copy key"
3867
3894
  }
3868
3895
  ),
3869
- itemValue !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3896
+ _optionalChain([data, 'optionalAccess', _22 => _22.value]) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3870
3897
  ContextMenuItem,
3871
3898
  {
3872
3899
  onClick: () => {
3873
- navigator.clipboard.writeText(itemValue);
3900
+ navigator.clipboard.writeText(_nullishCoalesce(_optionalChain([data, 'optionalAccess', _23 => _23.value]), () => ( "")));
3874
3901
  toast({
3875
3902
  description: "Value copied to clipboard"
3876
3903
  });
@@ -4243,7 +4270,7 @@ var Spinner = ({
4243
4270
  strokeWidth: "2",
4244
4271
  strokeLinecap: "round",
4245
4272
  strokeLinejoin: "round",
4246
- className: "ml-2 h-4 w-4 animate-spin",
4273
+ className: cn("h-4 w-4 animate-spin", isLoadingText ? "ml-2" : ""),
4247
4274
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
4248
4275
  }
4249
4276
  )
@@ -4362,7 +4389,7 @@ var LengthBadge = ({
4362
4389
  content
4363
4390
  }) => {
4364
4391
  const { data, isLoading } = useFetchKeyLength({ dataKey, type });
4365
- const length = _nullishCoalesce(_optionalChain([content, 'optionalAccess', _20 => _20.length]), () => ( data));
4392
+ const length = _nullishCoalesce(_optionalChain([content, 'optionalAccess', _24 => _24.length]), () => ( data));
4366
4393
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Badge, { label: "Length:", children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Skeleton, { className: "ml-1 h-3 w-10 rounded-md opacity-50" }) : length });
4367
4394
  };
4368
4395
  var SizeBadge = ({ dataKey }) => {
@@ -4540,7 +4567,14 @@ function KeyActions({ dataKey, content }) {
4540
4567
  children: "Copy content"
4541
4568
  }
4542
4569
  ),
4543
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DeleteAlertDialog, { deletionType: "key", onDeleteConfirm: async () => await deleteKey(dataKey), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DropdownMenuItem, { onSelect: (e) => e.preventDefault(), children: "Delete key" }) })
4570
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4571
+ DeleteAlertDialog,
4572
+ {
4573
+ deletionType: "key",
4574
+ onDeleteConfirm: async () => await deleteKey(dataKey),
4575
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DropdownMenuItem, { onSelect: (e) => e.preventDefault(), children: "Delete key" })
4576
+ }
4577
+ )
4544
4578
  ] })
4545
4579
  ] });
4546
4580
  }
@@ -4588,7 +4622,7 @@ var TooltipContent = React11.forwardRef(({ className, sideOffset = 4, ...props }
4588
4622
  ref,
4589
4623
  sideOffset,
4590
4624
  className: cn(
4591
- "animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 overflow-hidden rounded-md bg-zinc-900 px-3 py-1.5 text-xs text-zinc-50 dark:bg-zinc-50 dark:text-zinc-900",
4625
+ "z-50 overflow-hidden rounded-md bg-zinc-900 px-3 py-1.5 text-xs text-zinc-50 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:bg-zinc-50 dark:text-zinc-900",
4592
4626
  className
4593
4627
  ),
4594
4628
  ...props
@@ -4682,7 +4716,7 @@ var CustomEditor = ({
4682
4716
  if (!monaco || !editorRef.current) {
4683
4717
  return;
4684
4718
  }
4685
- _optionalChain([monaco, 'optionalAccess', _21 => _21.editor, 'access', _22 => _22.setModelLanguage, 'call', _23 => _23(editorRef.current.getModel(), language)]);
4719
+ _optionalChain([monaco, 'optionalAccess', _25 => _25.editor, 'access', _26 => _26.setModelLanguage, 'call', _27 => _27(editorRef.current.getModel(), language)]);
4686
4720
  }, [monaco, language]);
4687
4721
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4688
4722
  "div",
@@ -4928,7 +4962,7 @@ var ListDisplay = ({ dataKey, type }) => {
4928
4962
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full flex-col gap-2", children: [
4929
4963
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DisplayHeader, { dataKey, type }),
4930
4964
  selectedListItem && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListEditDisplay, { dataKey, type, item: selectedListItem }),
4931
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: cn("min-h-0 grow", selectedListItem && "hidden"), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfiniteScroll, { query, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pr-3", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "table", { className: "w-full", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tbody", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListItems, { dataKey, type, query }) }) }) }) }) })
4965
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: cn("min-h-0 grow", selectedListItem && "hidden"), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfiniteScroll, { query, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pr-3", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "table", { className: "w-full", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ItemContextMenu, { dataKey, type, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tbody", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListItems, { dataKey, type, query }) }) }) }) }) }) })
4932
4966
  ] });
4933
4967
  };
4934
4968
  var ListItems = ({
@@ -4937,70 +4971,63 @@ var ListItems = ({
4937
4971
  dataKey
4938
4972
  }) => {
4939
4973
  const { setSelectedListItem } = useDatabrowserStore();
4940
- const keys = _react.useMemo.call(void 0, () => _nullishCoalesce(_optionalChain([query, 'access', _24 => _24.data, 'optionalAccess', _25 => _25.pages, 'access', _26 => _26.flatMap, 'call', _27 => _27((page) => page.keys)]), () => ( [])), [query.data]);
4974
+ const keys = _react.useMemo.call(void 0, () => _nullishCoalesce(_optionalChain([query, 'access', _28 => _28.data, 'optionalAccess', _29 => _29.pages, 'access', _30 => _30.flatMap, 'call', _31 => _31((page) => page.keys)]), () => ( [])), [query.data]);
4941
4975
  const { mutate: editItem } = useEditListItem();
4942
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: keys.map(({ key, value }, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4943
- ItemContextMenu,
4976
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: keys.map(({ key, value }, i) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4977
+ "tr",
4944
4978
  {
4945
- dataKey,
4946
- type,
4947
- itemKey: key,
4948
- itemValue: value,
4949
- children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4950
- "tr",
4951
- {
4952
- onClick: () => {
4953
- setSelectedListItem({ key, value });
4954
- },
4955
- className: "h-10 border-b border-b-zinc-100 hover:bg-zinc-50",
4956
- children: [
4957
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4958
- "td",
4959
- {
4960
- className: cn(
4961
- "cursor-pointer truncate px-3",
4962
- type === "list" || type === "stream" ? "w-32 min-w-24" : "max-w-0"
4963
- ),
4964
- children: key
4965
- }
4966
- ),
4967
- value !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4968
- "td",
4969
- {
4970
- className: cn("cursor-pointer truncate px-3", type === "zset" ? "w-24" : "max-w-0"),
4971
- children: value
4972
- }
4979
+ "data-item-key": key,
4980
+ "data-item-value": value,
4981
+ onClick: () => {
4982
+ setSelectedListItem({ key, value });
4983
+ },
4984
+ className: "h-10 border-b border-b-zinc-100 hover:bg-zinc-50",
4985
+ children: [
4986
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4987
+ "td",
4988
+ {
4989
+ className: cn(
4990
+ "cursor-pointer truncate px-3",
4991
+ type === "list" || type === "stream" ? "w-32 min-w-24" : "max-w-0"
4973
4992
  ),
4974
- type !== "stream" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4975
- "td",
4993
+ children: key
4994
+ }
4995
+ ),
4996
+ value !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4997
+ "td",
4998
+ {
4999
+ className: cn("cursor-pointer truncate px-3", type === "zset" ? "w-24" : "max-w-0"),
5000
+ children: value
5001
+ }
5002
+ ),
5003
+ type !== "stream" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5004
+ "td",
5005
+ {
5006
+ width: 20,
5007
+ className: "px-3",
5008
+ onClick: (e) => {
5009
+ e.stopPropagation();
5010
+ },
5011
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5012
+ DeleteAlertDialog,
4976
5013
  {
4977
- width: 20,
4978
- className: "px-3",
4979
- onClick: (e) => {
5014
+ deletionType: "item",
5015
+ onDeleteConfirm: (e) => {
4980
5016
  e.stopPropagation();
5017
+ editItem({
5018
+ type,
5019
+ dataKey,
5020
+ itemKey: key,
5021
+ // For deletion
5022
+ newKey: void 0
5023
+ });
4981
5024
  },
4982
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4983
- DeleteAlertDialog,
4984
- {
4985
- deletionType: "item",
4986
- onDeleteConfirm: (e) => {
4987
- e.stopPropagation();
4988
- editItem({
4989
- type,
4990
- dataKey,
4991
- itemKey: key,
4992
- // For deletion
4993
- newKey: void 0
4994
- });
4995
- },
4996
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { size: "icon-sm", variant: "secondary", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconTrash, { className: "size-4 text-zinc-500" }) })
4997
- }
4998
- )
5025
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { size: "icon-sm", variant: "secondary", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconTrash, { className: "size-4 text-zinc-500" }) })
4999
5026
  }
5000
5027
  )
5001
- ]
5002
- }
5003
- )
5028
+ }
5029
+ )
5030
+ ]
5004
5031
  },
5005
5032
  `${dataKey}-${key}-${i}`
5006
5033
  )) });
@@ -5070,10 +5097,14 @@ var EditorDisplayForm = ({
5070
5097
 
5071
5098
  var DataDisplay = () => {
5072
5099
  const { selectedKey } = useDatabrowserStore();
5100
+ const { query } = useKeys();
5073
5101
  const type = useKeyType(selectedKey);
5074
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full rounded-xl border p-1 bg-white", children: !selectedKey ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", {}) : !type ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-gray-500", children: "Loading..." }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: type === "string" || type === "json" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EditorDisplay, { dataKey: selectedKey, type }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListDisplay, { dataKey: selectedKey, type }) }) });
5102
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full rounded-xl border bg-white p-1", children: !selectedKey ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", {}) : !type ? query.isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-gray-500", children: "Loading..." }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: type === "string" || type === "json" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EditorDisplay, { dataKey: selectedKey, type }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListDisplay, { dataKey: selectedKey, type }) }) });
5075
5103
  };
5076
5104
 
5105
+ // src/components/databrowser/components/sidebar/index.tsx
5106
+
5107
+
5077
5108
  // src/components/databrowser/components/add-key-modal.tsx
5078
5109
 
5079
5110
  var _reactdialog = require('@radix-ui/react-dialog'); var DialogPrimitive = _interopRequireWildcard(_reactdialog);
@@ -5199,7 +5230,7 @@ function AddKeyModal() {
5199
5230
  setSelectedKey(key);
5200
5231
  setOpen(false);
5201
5232
  setTimeout(() => {
5202
- _optionalChain([window, 'access', _28 => _28.document, 'access', _29 => _29.querySelector, 'call', _30 => _30(`[data-key="${key}"]`), 'optionalAccess', _31 => _31.scrollIntoView, 'call', _32 => _32({
5233
+ _optionalChain([window, 'access', _32 => _32.document, 'access', _33 => _33.querySelector, 'call', _34 => _34(`[data-key="${key}"]`), 'optionalAccess', _35 => _35.scrollIntoView, 'call', _36 => _36({
5203
5234
  behavior: "smooth",
5204
5235
  block: "start",
5205
5236
  inline: "nearest"
@@ -5250,7 +5281,7 @@ function AddKeyModal() {
5250
5281
  }
5251
5282
  )
5252
5283
  ] }),
5253
- formState.errors.key && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "mb-3 mt-2 text-xs text-red-500", children: _optionalChain([formState, 'access', _33 => _33.errors, 'access', _34 => _34.key, 'optionalAccess', _35 => _35.message]) }),
5284
+ formState.errors.key && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "mb-3 mt-2 text-xs text-red-500", children: _optionalChain([formState, 'access', _37 => _37.errors, 'access', _38 => _38.key, 'optionalAccess', _39 => _39.message]) }),
5254
5285
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "mt-2 text-xs text-zinc-500", children: "After creating the key, you can edit the value" }),
5255
5286
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mt-6 flex justify-end gap-2", children: [
5256
5287
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -5286,12 +5317,10 @@ var Empty = () => {
5286
5317
 
5287
5318
 
5288
5319
 
5289
- var SidebarContextMenu = ({
5290
- children,
5291
- dataKey
5292
- }) => {
5320
+ var SidebarContextMenu = ({ children }) => {
5293
5321
  const { mutate: deleteKey } = useDeleteKey();
5294
5322
  const [isAlertOpen, setAlertOpen] = _react.useState.call(void 0, false);
5323
+ const [dataKey, setDataKey] = _react.useState.call(void 0, "");
5295
5324
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
5296
5325
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5297
5326
  DeleteAlertDialog,
@@ -5307,7 +5336,21 @@ var SidebarContextMenu = ({
5307
5336
  }
5308
5337
  ),
5309
5338
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ContextMenu, { children: [
5310
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ContextMenuTrigger, { asChild: true, children }),
5339
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5340
+ ContextMenuTrigger,
5341
+ {
5342
+ onContextMenu: (e) => {
5343
+ const el = e.target;
5344
+ const key = el.closest("[data-key]");
5345
+ if (key && key instanceof HTMLElement && key.dataset.key !== void 0) {
5346
+ setDataKey(key.dataset.key);
5347
+ } else {
5348
+ throw new Error("Key not found");
5349
+ }
5350
+ },
5351
+ children
5352
+ }
5353
+ ),
5311
5354
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, ContextMenuContent, { children: [
5312
5355
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5313
5356
  ContextMenuItem,
@@ -5332,7 +5375,7 @@ var SidebarContextMenu = ({
5332
5375
 
5333
5376
  var KeysList = () => {
5334
5377
  const { keys } = useKeys();
5335
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pr-3", children: keys.map((data, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KeyItem, { nextKey: _nullishCoalesce(_optionalChain([keys, 'access', _36 => _36.at, 'call', _37 => _37(i + 1), 'optionalAccess', _38 => _38[0]]), () => ( "")), data }, data[0])) });
5378
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "pr-3", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SidebarContextMenu, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: keys.map((data, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KeyItem, { nextKey: _nullishCoalesce(_optionalChain([keys, 'access', _40 => _40.at, 'call', _41 => _41(i + 1), 'optionalAccess', _42 => _42[0]]), () => ( "")), data }, data[0])) }) }) });
5336
5379
  };
5337
5380
  var keyStyles = {
5338
5381
  string: "border-sky-400 !bg-sky-50 text-sky-900",
@@ -5348,7 +5391,7 @@ var KeyItem = ({ data, nextKey }) => {
5348
5391
  const [dataKey, dataType] = data;
5349
5392
  const isKeySelected = selectedKey === dataKey;
5350
5393
  const isNextKeySelected = selectedKey === nextKey;
5351
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SidebarContextMenu, { dataKey, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
5394
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
5352
5395
  Button,
5353
5396
  {
5354
5397
  "data-key": dataKey,
@@ -5366,7 +5409,7 @@ var KeyItem = ({ data, nextKey }) => {
5366
5409
  !isKeySelected && !isNextKeySelected && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "absolute -bottom-px left-3 right-3 h-px bg-zinc-100" })
5367
5410
  ]
5368
5411
  }
5369
- ) }, dataKey);
5412
+ );
5370
5413
  };
5371
5414
 
5372
5415
  // src/components/databrowser/components/sidebar/search-input.tsx
@@ -5440,12 +5483,15 @@ function DataTypeSelector() {
5440
5483
  // src/components/databrowser/components/sidebar/index.tsx
5441
5484
 
5442
5485
  function Sidebar() {
5443
- const { keys, query } = useKeys();
5444
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full flex-col gap-2 rounded-xl border p-1 bg-white", children: [
5486
+ const { keys, query, refetch } = useKeys();
5487
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full flex-col gap-2 rounded-xl border bg-white p-1", children: [
5445
5488
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "rounded-lg bg-zinc-100 px-3 py-2", children: [
5446
5489
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-10 items-center justify-between pl-1", children: [
5447
5490
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DisplayDbSize, {}),
5448
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex gap-1", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AddKeyModal, {}) })
5491
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex gap-1", children: [
5492
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { className: "h-7 w-7 px-0", onClick: refetch, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Spinner, { isLoading: query.isFetching, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _iconsreact.IconRefresh, { size: 16 }) }) }),
5493
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AddKeyModal, {})
5494
+ ] })
5449
5495
  ] }),
5450
5496
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-10 items-center", children: [
5451
5497
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DataTypeSelector, {}),
package/dist/index.mjs CHANGED
@@ -2888,7 +2888,13 @@ function Toaster() {
2888
2888
  }
2889
2889
 
2890
2890
  // src/components/databrowser/hooks/use-keys.tsx
2891
- import { createContext as createContext2, useCallback as useCallback2, useContext as useContext2, useMemo as useMemo2 } from "react";
2891
+ import {
2892
+ createContext as createContext2,
2893
+ useCallback as useCallback2,
2894
+ useContext as useContext2,
2895
+ useMemo as useMemo2,
2896
+ useRef as useRef2
2897
+ } from "react";
2892
2898
  import { useInfiniteQuery } from "@tanstack/react-query";
2893
2899
 
2894
2900
  // src/components/databrowser/hooks/use-fetch-keys.ts
@@ -2908,35 +2914,28 @@ var DATA_TYPE_NAMES = {
2908
2914
 
2909
2915
  // src/components/databrowser/hooks/use-fetch-keys.ts
2910
2916
  var PAGE_SIZE = 30;
2911
- var INITIAL_FETCH_COUNT = 100;
2912
- var MAX_FETCH_COUNT = 1e3;
2917
+ var FETCH_COUNTS = [100, 200, 400, 800];
2913
2918
  var useFetchKeys = (search) => {
2914
2919
  const { redis } = useDatabrowser();
2915
2920
  const cache = useRef();
2916
2921
  const lastKey = useRef();
2917
- const getPage = useCallback(
2918
- (page) => {
2919
- const newKey = JSON.stringify(search);
2920
- if (!cache.current || lastKey.current !== newKey) {
2921
- cache.current = new PaginationCache(redis, search.key, search.type);
2922
- lastKey.current = newKey;
2923
- }
2924
- return cache.current.getPage(page);
2925
- },
2926
- [search]
2927
- );
2922
+ const fetchKeys = useCallback(() => {
2923
+ const newKey = JSON.stringify(search);
2924
+ if (!cache.current || lastKey.current !== newKey) {
2925
+ cache.current = new PaginationCache(redis, search.key, search.type);
2926
+ lastKey.current = newKey;
2927
+ }
2928
+ return cache.current.fetchNewKeys();
2929
+ }, [search]);
2928
2930
  const resetCache = useCallback(() => {
2929
2931
  cache.current = void 0;
2930
2932
  lastKey.current = void 0;
2931
2933
  }, []);
2932
2934
  return {
2933
- getPage,
2935
+ fetchKeys,
2934
2936
  resetCache
2935
2937
  };
2936
2938
  };
2937
- function slicePage(keys, page) {
2938
- return keys.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE);
2939
- }
2940
2939
  var PaginationCache = class {
2941
2940
  constructor(redis, searchTerm, typeFilter) {
2942
2941
  this.redis = redis;
@@ -2952,8 +2951,9 @@ var PaginationCache = class {
2952
2951
  );
2953
2952
  targetCount = 0;
2954
2953
  isFetching = false;
2955
- async getPage(page) {
2956
- this.targetCount = (page + 1) * PAGE_SIZE + 1;
2954
+ async fetchNewKeys() {
2955
+ const initialKeys = new Set(this.getKeys().map(([key]) => key));
2956
+ this.targetCount = this.getKeys().length + PAGE_SIZE;
2957
2957
  void this.startFetch();
2958
2958
  await new Promise((resolve) => {
2959
2959
  const interval = setInterval(() => {
@@ -2963,10 +2963,9 @@ var PaginationCache = class {
2963
2963
  }
2964
2964
  }, 100);
2965
2965
  });
2966
- const hasEnoughForNextPage = this.getLength() > (page + 1) * PAGE_SIZE;
2967
- const hasNextPage = !this.isAllEnded() || hasEnoughForNextPage;
2966
+ const hasNextPage = !this.isAllEnded();
2968
2967
  return {
2969
- keys: slicePage(this.getKeys(), page),
2968
+ keys: this.getKeys().filter(([key]) => !initialKeys.has(key)),
2970
2969
  hasNextPage
2971
2970
  };
2972
2971
  }
@@ -2992,33 +2991,29 @@ var PaginationCache = class {
2992
2991
  }
2993
2992
  }
2994
2993
  fetchForType = async (type) => {
2995
- let fetchCount = INITIAL_FETCH_COUNT;
2994
+ let i = 0;
2996
2995
  while (true) {
2997
2996
  const cursor = this.cache[type].cursor;
2998
2997
  if (cursor === "-1" || this.getLength() >= this.targetCount) {
2999
2998
  break;
3000
2999
  }
3000
+ const fetchCount = FETCH_COUNTS[Math.min(i, FETCH_COUNTS.length - 1)];
3001
3001
  const [nextCursor, newKeys] = await this.redis.scan(cursor, {
3002
3002
  count: fetchCount,
3003
3003
  match: this.searchTerm,
3004
3004
  type
3005
3005
  });
3006
- fetchCount = Math.min(fetchCount * 2, MAX_FETCH_COUNT);
3007
- const dedupedSet = /* @__PURE__ */ new Set([...this.cache[type].keys, ...newKeys]);
3008
- this.cache[type].keys = [...dedupedSet];
3006
+ this.cache[type].keys = [...this.cache[type].keys, ...newKeys];
3009
3007
  this.cache[type].cursor = nextCursor === "0" ? "-1" : nextCursor;
3008
+ i++;
3010
3009
  }
3011
3010
  };
3012
3011
  async fetch() {
3013
3012
  const types = this.typeFilter ? [this.typeFilter] : DATA_TYPES;
3014
3013
  await Promise.all(types.map(this.fetchForType));
3015
3014
  }
3016
- // TODO: Yusuf, implement this function
3017
3015
  isAllEnded() {
3018
3016
  const types = this.typeFilter ? [this.typeFilter] : DATA_TYPES;
3019
- if (!Array.isArray(types)) {
3020
- throw new TypeError("types is not an array");
3021
- }
3022
3017
  return types.every((type) => this.cache[type] && this.cache[type].cursor === "-1");
3023
3018
  }
3024
3019
  };
@@ -3036,17 +3031,21 @@ var KeysProvider = ({ children }) => {
3036
3031
  }),
3037
3032
  [searchState]
3038
3033
  );
3039
- const { getPage, resetCache } = useFetchKeys(search);
3034
+ const { fetchKeys, resetCache } = useFetchKeys(search);
3035
+ const pageRef = useRef2(0);
3040
3036
  const query = useInfiniteQuery({
3041
3037
  queryKey: [FETCH_KEYS_QUERY_KEY, search],
3042
3038
  initialPageParam: 0,
3043
- queryFn: async ({ pageParam: pageIndex }) => {
3044
- return getPage(pageIndex);
3039
+ queryFn: async ({ pageParam: page }) => {
3040
+ if (pageRef.current >= page) resetCache();
3041
+ pageRef.current = page;
3042
+ return await fetchKeys();
3045
3043
  },
3046
3044
  select: (data) => data,
3047
3045
  getNextPageParam: (lastPage, __, lastPageIndex) => {
3048
3046
  return lastPage.hasNextPage ? lastPageIndex + 1 : void 0;
3049
- }
3047
+ },
3048
+ refetchOnMount: false
3050
3049
  });
3051
3050
  const refetch = useCallback2(() => {
3052
3051
  resetCache();
@@ -3054,8 +3053,14 @@ var KeysProvider = ({ children }) => {
3054
3053
  }, [query, resetCache]);
3055
3054
  const keys = useMemo2(() => {
3056
3055
  const keys2 = query.data?.pages.flatMap((page) => page.keys) ?? [];
3057
- const keysSet = new Set(keys2.map(([key, _]) => key));
3058
- return keys2.filter(([key, _]) => keysSet.has(key));
3056
+ const keysSet = /* @__PURE__ */ new Set();
3057
+ const dedupedKeys = [];
3058
+ for (const key of keys2) {
3059
+ if (keysSet.has(key[0])) continue;
3060
+ keysSet.add(key[0]);
3061
+ dedupedKeys.push(key);
3062
+ }
3063
+ return dedupedKeys;
3059
3064
  }, [query.data]);
3060
3065
  return /* @__PURE__ */ jsx4(
3061
3066
  KeysContext.Provider,
@@ -3171,39 +3176,39 @@ var useAddKey = () => {
3171
3176
  mutationFn: async ({ key, type }) => {
3172
3177
  switch (type) {
3173
3178
  case "set": {
3174
- redis.sadd(key, "value");
3179
+ await redis.sadd(key, "value");
3175
3180
  break;
3176
3181
  }
3177
3182
  case "zset": {
3178
- redis.zadd(key, {
3183
+ await redis.zadd(key, {
3179
3184
  member: "value",
3180
3185
  score: 0
3181
3186
  });
3182
3187
  break;
3183
3188
  }
3184
3189
  case "hash": {
3185
- redis.hset(key, {
3190
+ await redis.hset(key, {
3186
3191
  field: "field",
3187
3192
  value: "value"
3188
3193
  });
3189
3194
  break;
3190
3195
  }
3191
3196
  case "list": {
3192
- redis.lpush(key, "value");
3197
+ await redis.lpush(key, "value");
3193
3198
  break;
3194
3199
  }
3195
3200
  case "stream": {
3196
- redis.xadd(key, "*", {
3201
+ await redis.xadd(key, "*", {
3197
3202
  foo: "bar"
3198
3203
  });
3199
3204
  break;
3200
3205
  }
3201
3206
  case "string": {
3202
- redis.set(key, "value");
3207
+ await redis.set(key, "value");
3203
3208
  break;
3204
3209
  }
3205
3210
  case "json": {
3206
- redis.json.set(key, "$", {
3211
+ await redis.json.set(key, "$", {
3207
3212
  foo: "bar"
3208
3213
  });
3209
3214
  break;
@@ -3802,7 +3807,9 @@ function DeleteAlertDialog({
3802
3807
  /* @__PURE__ */ jsxs5(AlertDialogDescription, { className: "mt-5", children: [
3803
3808
  "Are you sure you want to delete this ",
3804
3809
  deletionType,
3805
- "? This action cannot be undone."
3810
+ "?",
3811
+ /* @__PURE__ */ jsx10("br", {}),
3812
+ "This action cannot be undone."
3806
3813
  ] })
3807
3814
  ] }),
3808
3815
  /* @__PURE__ */ jsxs5(AlertDialogFooter, { children: [
@@ -3825,12 +3832,11 @@ import { Fragment, jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
3825
3832
  var ItemContextMenu = ({
3826
3833
  children,
3827
3834
  dataKey,
3828
- itemKey,
3829
- itemValue,
3830
3835
  type
3831
3836
  }) => {
3832
3837
  const { mutate: editItem } = useEditListItem();
3833
3838
  const [isAlertOpen, setAlertOpen] = useState4(false);
3839
+ const [data, setData] = useState4();
3834
3840
  return /* @__PURE__ */ jsxs6(Fragment, { children: [
3835
3841
  /* @__PURE__ */ jsx11(
3836
3842
  DeleteAlertDialog,
@@ -3840,25 +3846,46 @@ var ItemContextMenu = ({
3840
3846
  onOpenChange: setAlertOpen,
3841
3847
  onDeleteConfirm: (e) => {
3842
3848
  e.stopPropagation();
3843
- editItem({
3844
- type,
3845
- dataKey,
3846
- itemKey,
3847
- // For deletion
3848
- newKey: void 0
3849
- });
3849
+ if (data) {
3850
+ editItem({
3851
+ type,
3852
+ dataKey,
3853
+ itemKey: data?.key,
3854
+ // For deletion
3855
+ newKey: void 0
3856
+ });
3857
+ }
3850
3858
  setAlertOpen(false);
3851
3859
  }
3852
3860
  }
3853
3861
  ),
3854
3862
  /* @__PURE__ */ jsxs6(ContextMenu, { children: [
3855
- /* @__PURE__ */ jsx11(ContextMenuTrigger, { asChild: true, children }),
3863
+ /* @__PURE__ */ jsx11(
3864
+ ContextMenuTrigger,
3865
+ {
3866
+ asChild: true,
3867
+ onContextMenu: (e) => {
3868
+ const el = e.target;
3869
+ const item = el.closest("[data-item-key]");
3870
+ if (item && item instanceof HTMLElement && item.dataset.itemKey !== void 0) {
3871
+ setData({
3872
+ key: item.dataset.itemKey,
3873
+ value: item.dataset.itemValue
3874
+ });
3875
+ } else {
3876
+ throw new Error("Key not found");
3877
+ }
3878
+ },
3879
+ children
3880
+ }
3881
+ ),
3856
3882
  /* @__PURE__ */ jsxs6(ContextMenuContent, { children: [
3857
3883
  /* @__PURE__ */ jsx11(
3858
3884
  ContextMenuItem,
3859
3885
  {
3860
3886
  onClick: () => {
3861
- navigator.clipboard.writeText(itemKey);
3887
+ if (!data) return;
3888
+ navigator.clipboard.writeText(data?.key);
3862
3889
  toast({
3863
3890
  description: "Key copied to clipboard"
3864
3891
  });
@@ -3866,11 +3893,11 @@ var ItemContextMenu = ({
3866
3893
  children: "Copy key"
3867
3894
  }
3868
3895
  ),
3869
- itemValue !== void 0 && /* @__PURE__ */ jsx11(
3896
+ data?.value && /* @__PURE__ */ jsx11(
3870
3897
  ContextMenuItem,
3871
3898
  {
3872
3899
  onClick: () => {
3873
- navigator.clipboard.writeText(itemValue);
3900
+ navigator.clipboard.writeText(data?.value ?? "");
3874
3901
  toast({
3875
3902
  description: "Value copied to clipboard"
3876
3903
  });
@@ -4243,7 +4270,7 @@ var Spinner = ({
4243
4270
  strokeWidth: "2",
4244
4271
  strokeLinecap: "round",
4245
4272
  strokeLinejoin: "round",
4246
- className: "ml-2 h-4 w-4 animate-spin",
4273
+ className: cn("h-4 w-4 animate-spin", isLoadingText ? "ml-2" : ""),
4247
4274
  children: /* @__PURE__ */ jsx18("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
4248
4275
  }
4249
4276
  )
@@ -4540,7 +4567,14 @@ function KeyActions({ dataKey, content }) {
4540
4567
  children: "Copy content"
4541
4568
  }
4542
4569
  ),
4543
- /* @__PURE__ */ jsx22(DeleteAlertDialog, { deletionType: "key", onDeleteConfirm: async () => await deleteKey(dataKey), children: /* @__PURE__ */ jsx22(DropdownMenuItem, { onSelect: (e) => e.preventDefault(), children: "Delete key" }) })
4570
+ /* @__PURE__ */ jsx22(
4571
+ DeleteAlertDialog,
4572
+ {
4573
+ deletionType: "key",
4574
+ onDeleteConfirm: async () => await deleteKey(dataKey),
4575
+ children: /* @__PURE__ */ jsx22(DropdownMenuItem, { onSelect: (e) => e.preventDefault(), children: "Delete key" })
4576
+ }
4577
+ )
4544
4578
  ] })
4545
4579
  ] });
4546
4580
  }
@@ -4588,7 +4622,7 @@ var TooltipContent = React11.forwardRef(({ className, sideOffset = 4, ...props }
4588
4622
  ref,
4589
4623
  sideOffset,
4590
4624
  className: cn(
4591
- "animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 overflow-hidden rounded-md bg-zinc-900 px-3 py-1.5 text-xs text-zinc-50 dark:bg-zinc-50 dark:text-zinc-900",
4625
+ "z-50 overflow-hidden rounded-md bg-zinc-900 px-3 py-1.5 text-xs text-zinc-50 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:bg-zinc-50 dark:text-zinc-900",
4592
4626
  className
4593
4627
  ),
4594
4628
  ...props
@@ -4629,7 +4663,7 @@ var ContentTypeSelect = ({
4629
4663
  };
4630
4664
 
4631
4665
  // src/components/databrowser/components/display/input/custom-editor.tsx
4632
- import { useEffect as useEffect6, useRef as useRef2 } from "react";
4666
+ import { useEffect as useEffect6, useRef as useRef3 } from "react";
4633
4667
  import { Editor, useMonaco } from "@monaco-editor/react";
4634
4668
 
4635
4669
  // src/components/databrowser/copy-button.tsx
@@ -4677,7 +4711,7 @@ var CustomEditor = ({
4677
4711
  showCopyButton
4678
4712
  }) => {
4679
4713
  const monaco = useMonaco();
4680
- const editorRef = useRef2();
4714
+ const editorRef = useRef3();
4681
4715
  useEffect6(() => {
4682
4716
  if (!monaco || !editorRef.current) {
4683
4717
  return;
@@ -4928,7 +4962,7 @@ var ListDisplay = ({ dataKey, type }) => {
4928
4962
  return /* @__PURE__ */ jsxs20("div", { className: "flex h-full flex-col gap-2", children: [
4929
4963
  /* @__PURE__ */ jsx30(DisplayHeader, { dataKey, type }),
4930
4964
  selectedListItem && /* @__PURE__ */ jsx30(ListEditDisplay, { dataKey, type, item: selectedListItem }),
4931
- /* @__PURE__ */ jsx30("div", { className: cn("min-h-0 grow", selectedListItem && "hidden"), children: /* @__PURE__ */ jsx30(InfiniteScroll, { query, children: /* @__PURE__ */ jsx30("div", { className: "pr-3", children: /* @__PURE__ */ jsx30("table", { className: "w-full", children: /* @__PURE__ */ jsx30("tbody", { children: /* @__PURE__ */ jsx30(ListItems, { dataKey, type, query }) }) }) }) }) })
4965
+ /* @__PURE__ */ jsx30("div", { className: cn("min-h-0 grow", selectedListItem && "hidden"), children: /* @__PURE__ */ jsx30(InfiniteScroll, { query, children: /* @__PURE__ */ jsx30("div", { className: "pr-3", children: /* @__PURE__ */ jsx30("table", { className: "w-full", children: /* @__PURE__ */ jsx30(ItemContextMenu, { dataKey, type, children: /* @__PURE__ */ jsx30("tbody", { children: /* @__PURE__ */ jsx30(ListItems, { dataKey, type, query }) }) }) }) }) }) })
4932
4966
  ] });
4933
4967
  };
4934
4968
  var ListItems = ({
@@ -4939,68 +4973,61 @@ var ListItems = ({
4939
4973
  const { setSelectedListItem } = useDatabrowserStore();
4940
4974
  const keys = useMemo5(() => query.data?.pages.flatMap((page) => page.keys) ?? [], [query.data]);
4941
4975
  const { mutate: editItem } = useEditListItem();
4942
- return /* @__PURE__ */ jsx30(Fragment5, { children: keys.map(({ key, value }, i) => /* @__PURE__ */ jsx30(
4943
- ItemContextMenu,
4976
+ return /* @__PURE__ */ jsx30(Fragment5, { children: keys.map(({ key, value }, i) => /* @__PURE__ */ jsxs20(
4977
+ "tr",
4944
4978
  {
4945
- dataKey,
4946
- type,
4947
- itemKey: key,
4948
- itemValue: value,
4949
- children: /* @__PURE__ */ jsxs20(
4950
- "tr",
4951
- {
4952
- onClick: () => {
4953
- setSelectedListItem({ key, value });
4954
- },
4955
- className: "h-10 border-b border-b-zinc-100 hover:bg-zinc-50",
4956
- children: [
4957
- /* @__PURE__ */ jsx30(
4958
- "td",
4959
- {
4960
- className: cn(
4961
- "cursor-pointer truncate px-3",
4962
- type === "list" || type === "stream" ? "w-32 min-w-24" : "max-w-0"
4963
- ),
4964
- children: key
4965
- }
4966
- ),
4967
- value !== void 0 && /* @__PURE__ */ jsx30(
4968
- "td",
4969
- {
4970
- className: cn("cursor-pointer truncate px-3", type === "zset" ? "w-24" : "max-w-0"),
4971
- children: value
4972
- }
4979
+ "data-item-key": key,
4980
+ "data-item-value": value,
4981
+ onClick: () => {
4982
+ setSelectedListItem({ key, value });
4983
+ },
4984
+ className: "h-10 border-b border-b-zinc-100 hover:bg-zinc-50",
4985
+ children: [
4986
+ /* @__PURE__ */ jsx30(
4987
+ "td",
4988
+ {
4989
+ className: cn(
4990
+ "cursor-pointer truncate px-3",
4991
+ type === "list" || type === "stream" ? "w-32 min-w-24" : "max-w-0"
4973
4992
  ),
4974
- type !== "stream" && /* @__PURE__ */ jsx30(
4975
- "td",
4993
+ children: key
4994
+ }
4995
+ ),
4996
+ value !== void 0 && /* @__PURE__ */ jsx30(
4997
+ "td",
4998
+ {
4999
+ className: cn("cursor-pointer truncate px-3", type === "zset" ? "w-24" : "max-w-0"),
5000
+ children: value
5001
+ }
5002
+ ),
5003
+ type !== "stream" && /* @__PURE__ */ jsx30(
5004
+ "td",
5005
+ {
5006
+ width: 20,
5007
+ className: "px-3",
5008
+ onClick: (e) => {
5009
+ e.stopPropagation();
5010
+ },
5011
+ children: /* @__PURE__ */ jsx30(
5012
+ DeleteAlertDialog,
4976
5013
  {
4977
- width: 20,
4978
- className: "px-3",
4979
- onClick: (e) => {
5014
+ deletionType: "item",
5015
+ onDeleteConfirm: (e) => {
4980
5016
  e.stopPropagation();
5017
+ editItem({
5018
+ type,
5019
+ dataKey,
5020
+ itemKey: key,
5021
+ // For deletion
5022
+ newKey: void 0
5023
+ });
4981
5024
  },
4982
- children: /* @__PURE__ */ jsx30(
4983
- DeleteAlertDialog,
4984
- {
4985
- deletionType: "item",
4986
- onDeleteConfirm: (e) => {
4987
- e.stopPropagation();
4988
- editItem({
4989
- type,
4990
- dataKey,
4991
- itemKey: key,
4992
- // For deletion
4993
- newKey: void 0
4994
- });
4995
- },
4996
- children: /* @__PURE__ */ jsx30(Button, { size: "icon-sm", variant: "secondary", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx30(IconTrash, { className: "size-4 text-zinc-500" }) })
4997
- }
4998
- )
5025
+ children: /* @__PURE__ */ jsx30(Button, { size: "icon-sm", variant: "secondary", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx30(IconTrash, { className: "size-4 text-zinc-500" }) })
4999
5026
  }
5000
5027
  )
5001
- ]
5002
- }
5003
- )
5028
+ }
5029
+ )
5030
+ ]
5004
5031
  },
5005
5032
  `${dataKey}-${key}-${i}`
5006
5033
  )) });
@@ -5070,10 +5097,14 @@ var EditorDisplayForm = ({
5070
5097
  import { Fragment as Fragment7, jsx as jsx32 } from "react/jsx-runtime";
5071
5098
  var DataDisplay = () => {
5072
5099
  const { selectedKey } = useDatabrowserStore();
5100
+ const { query } = useKeys();
5073
5101
  const type = useKeyType(selectedKey);
5074
- return /* @__PURE__ */ jsx32("div", { className: "h-full rounded-xl border p-1 bg-white", children: !selectedKey ? /* @__PURE__ */ jsx32("div", {}) : !type ? /* @__PURE__ */ jsx32("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx32("span", { className: "text-gray-500", children: "Loading..." }) }) : /* @__PURE__ */ jsx32(Fragment7, { children: type === "string" || type === "json" ? /* @__PURE__ */ jsx32(EditorDisplay, { dataKey: selectedKey, type }) : /* @__PURE__ */ jsx32(ListDisplay, { dataKey: selectedKey, type }) }) });
5102
+ return /* @__PURE__ */ jsx32("div", { className: "h-full rounded-xl border bg-white p-1", children: !selectedKey ? /* @__PURE__ */ jsx32("div", {}) : !type ? query.isLoading ? /* @__PURE__ */ jsx32("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx32("span", { className: "text-gray-500", children: "Loading..." }) }) : /* @__PURE__ */ jsx32("div", {}) : /* @__PURE__ */ jsx32(Fragment7, { children: type === "string" || type === "json" ? /* @__PURE__ */ jsx32(EditorDisplay, { dataKey: selectedKey, type }) : /* @__PURE__ */ jsx32(ListDisplay, { dataKey: selectedKey, type }) }) });
5075
5103
  };
5076
5104
 
5105
+ // src/components/databrowser/components/sidebar/index.tsx
5106
+ import { IconRefresh } from "@tabler/icons-react";
5107
+
5077
5108
  // src/components/databrowser/components/add-key-modal.tsx
5078
5109
  import { useState as useState8 } from "react";
5079
5110
  import { DialogDescription as DialogDescription2 } from "@radix-ui/react-dialog";
@@ -5286,12 +5317,10 @@ var Empty = () => {
5286
5317
  import { useState as useState9 } from "react";
5287
5318
  import { ContextMenuSeparator as ContextMenuSeparator3 } from "@radix-ui/react-context-menu";
5288
5319
  import { Fragment as Fragment8, jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
5289
- var SidebarContextMenu = ({
5290
- children,
5291
- dataKey
5292
- }) => {
5320
+ var SidebarContextMenu = ({ children }) => {
5293
5321
  const { mutate: deleteKey } = useDeleteKey();
5294
5322
  const [isAlertOpen, setAlertOpen] = useState9(false);
5323
+ const [dataKey, setDataKey] = useState9("");
5295
5324
  return /* @__PURE__ */ jsxs25(Fragment8, { children: [
5296
5325
  /* @__PURE__ */ jsx36(
5297
5326
  DeleteAlertDialog,
@@ -5307,7 +5336,21 @@ var SidebarContextMenu = ({
5307
5336
  }
5308
5337
  ),
5309
5338
  /* @__PURE__ */ jsxs25(ContextMenu, { children: [
5310
- /* @__PURE__ */ jsx36(ContextMenuTrigger, { asChild: true, children }),
5339
+ /* @__PURE__ */ jsx36(
5340
+ ContextMenuTrigger,
5341
+ {
5342
+ onContextMenu: (e) => {
5343
+ const el = e.target;
5344
+ const key = el.closest("[data-key]");
5345
+ if (key && key instanceof HTMLElement && key.dataset.key !== void 0) {
5346
+ setDataKey(key.dataset.key);
5347
+ } else {
5348
+ throw new Error("Key not found");
5349
+ }
5350
+ },
5351
+ children
5352
+ }
5353
+ ),
5311
5354
  /* @__PURE__ */ jsxs25(ContextMenuContent, { children: [
5312
5355
  /* @__PURE__ */ jsx36(
5313
5356
  ContextMenuItem,
@@ -5329,10 +5372,10 @@ var SidebarContextMenu = ({
5329
5372
  };
5330
5373
 
5331
5374
  // src/components/databrowser/components/sidebar/keys-list.tsx
5332
- import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
5375
+ import { Fragment as Fragment9, jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
5333
5376
  var KeysList = () => {
5334
5377
  const { keys } = useKeys();
5335
- return /* @__PURE__ */ jsx37("div", { className: "pr-3", children: keys.map((data, i) => /* @__PURE__ */ jsx37(KeyItem, { nextKey: keys.at(i + 1)?.[0] ?? "", data }, data[0])) });
5378
+ return /* @__PURE__ */ jsx37("div", { className: "pr-3", children: /* @__PURE__ */ jsx37(SidebarContextMenu, { children: /* @__PURE__ */ jsx37(Fragment9, { children: keys.map((data, i) => /* @__PURE__ */ jsx37(KeyItem, { nextKey: keys.at(i + 1)?.[0] ?? "", data }, data[0])) }) }) });
5336
5379
  };
5337
5380
  var keyStyles = {
5338
5381
  string: "border-sky-400 !bg-sky-50 text-sky-900",
@@ -5348,7 +5391,7 @@ var KeyItem = ({ data, nextKey }) => {
5348
5391
  const [dataKey, dataType] = data;
5349
5392
  const isKeySelected = selectedKey === dataKey;
5350
5393
  const isNextKeySelected = selectedKey === nextKey;
5351
- return /* @__PURE__ */ jsx37(SidebarContextMenu, { dataKey, children: /* @__PURE__ */ jsxs26(
5394
+ return /* @__PURE__ */ jsxs26(
5352
5395
  Button,
5353
5396
  {
5354
5397
  "data-key": dataKey,
@@ -5366,7 +5409,7 @@ var KeyItem = ({ data, nextKey }) => {
5366
5409
  !isKeySelected && !isNextKeySelected && /* @__PURE__ */ jsx37("span", { className: "absolute -bottom-px left-3 right-3 h-px bg-zinc-100" })
5367
5410
  ]
5368
5411
  }
5369
- ) }, dataKey);
5412
+ );
5370
5413
  };
5371
5414
 
5372
5415
  // src/components/databrowser/components/sidebar/search-input.tsx
@@ -5440,12 +5483,15 @@ function DataTypeSelector() {
5440
5483
  // src/components/databrowser/components/sidebar/index.tsx
5441
5484
  import { jsx as jsx41, jsxs as jsxs30 } from "react/jsx-runtime";
5442
5485
  function Sidebar() {
5443
- const { keys, query } = useKeys();
5444
- return /* @__PURE__ */ jsxs30("div", { className: "flex h-full flex-col gap-2 rounded-xl border p-1 bg-white", children: [
5486
+ const { keys, query, refetch } = useKeys();
5487
+ return /* @__PURE__ */ jsxs30("div", { className: "flex h-full flex-col gap-2 rounded-xl border bg-white p-1", children: [
5445
5488
  /* @__PURE__ */ jsxs30("div", { className: "rounded-lg bg-zinc-100 px-3 py-2", children: [
5446
5489
  /* @__PURE__ */ jsxs30("div", { className: "flex h-10 items-center justify-between pl-1", children: [
5447
5490
  /* @__PURE__ */ jsx41(DisplayDbSize, {}),
5448
- /* @__PURE__ */ jsx41("div", { className: "flex gap-1", children: /* @__PURE__ */ jsx41(AddKeyModal, {}) })
5491
+ /* @__PURE__ */ jsxs30("div", { className: "flex gap-1", children: [
5492
+ /* @__PURE__ */ jsx41(Button, { className: "h-7 w-7 px-0", onClick: refetch, children: /* @__PURE__ */ jsx41(Spinner, { isLoading: query.isFetching, children: /* @__PURE__ */ jsx41(IconRefresh, { size: 16 }) }) }),
5493
+ /* @__PURE__ */ jsx41(AddKeyModal, {})
5494
+ ] })
5449
5495
  ] }),
5450
5496
  /* @__PURE__ */ jsxs30("div", { className: "flex h-10 items-center", children: [
5451
5497
  /* @__PURE__ */ jsx41(DataTypeSelector, {}),
package/package.json CHANGED
@@ -1 +1 @@
1
- { "name": "@upstash/react-redis-browser", "version": "v0.1.2-canary-5", "main": "./dist/index.js", "types": "./dist/index.d.ts", "license": "MIT", "private": false, "publishConfig": { "access": "public" }, "bugs": { "url": "https://github.com/upstash/react-redis-browser/issues" }, "homepage": "https://github.com/upstash/react-redis-browser", "files": [ "./dist/**" ], "scripts": { "build": "tsup", "dev": "vite", "lint": "tsc && eslint", "fmt": "prettier --write ." }, "lint-staged": { "**/*.{js,ts,tsx}": [ "prettier --write", "eslint --fix" ] }, "dependencies": { "@ianvs/prettier-plugin-sort-imports": "^4.4.0", "@monaco-editor/react": "^4.6.0", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-context-menu": "^2.2.2", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-icons": "1.3.0", "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-scroll-area": "^1.0.3", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-toast": "^1.1.5", "@radix-ui/react-tooltip": "^1.0.7", "@tabler/icons-react": "^3.19.0", "@tanstack/react-query": "^5.32.0", "@types/bytes": "^3.1.4", "@upstash/redis": "^1.31.6", "bytes": "^3.1.2", "react-hook-form": "^7.53.0", "react-resizable-panels": "^2.1.4", "zustand": "5.0.0" }, "devDependencies": { "postcss-prefix-selector": "^2.1.0", "@types/node": "^22.8.4", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@typescript-eslint/eslint-plugin": "8.4.0", "@typescript-eslint/parser": "8.4.0", "@vitejs/plugin-react": "^4.1.0", "autoprefixer": "^10.4.14", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", "eslint": "9.10.0", "eslint-plugin-unicorn": "55.0.0", "postcss": "^8.4.31", "prettier": "^3.0.3", "prettier-plugin-tailwindcss": "^0.5.5", "react": "^18.3.1", "react-dom": "^18.3.1", "tailwind-merge": "^2.5.4", "tailwindcss": "^3.4.14", "tailwindcss-animate": "^1.0.7", "tsup": "^8.3.5", "typescript": "^5.0.4", "vite": "^5.4.10", "vite-tsconfig-paths": "^5.0.1" }, "peerDependencies": { "react": "^18.2.0 || ^19", "react-dom": "^18.2.0 || ^19" } }
1
+ { "name": "@upstash/react-redis-browser", "version": "v0.1.2-canary-7", "main": "./dist/index.js", "types": "./dist/index.d.ts", "license": "MIT", "private": false, "publishConfig": { "access": "public" }, "bugs": { "url": "https://github.com/upstash/react-redis-browser/issues" }, "homepage": "https://github.com/upstash/react-redis-browser", "files": [ "./dist/**" ], "scripts": { "build": "tsup", "dev": "vite", "lint": "tsc && eslint", "fmt": "prettier --write ./src" }, "lint-staged": { "**/*.{js,ts,tsx}": [ "prettier --write", "eslint --fix" ] }, "dependencies": { "@ianvs/prettier-plugin-sort-imports": "^4.4.0", "@monaco-editor/react": "^4.6.0", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-context-menu": "^2.2.2", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-icons": "1.3.0", "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-scroll-area": "^1.0.3", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-toast": "^1.1.5", "@radix-ui/react-tooltip": "^1.0.7", "@tabler/icons-react": "^3.19.0", "@tanstack/react-query": "^5.32.0", "@types/bytes": "^3.1.4", "@upstash/redis": "^1.34.3", "bytes": "^3.1.2", "react-hook-form": "^7.53.0", "react-resizable-panels": "^2.1.4", "zustand": "5.0.0" }, "devDependencies": { "postcss-prefix-selector": "^2.1.0", "@types/node": "^22.8.4", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@typescript-eslint/eslint-plugin": "8.4.0", "@typescript-eslint/parser": "8.4.0", "@vitejs/plugin-react": "^4.1.0", "autoprefixer": "^10.4.14", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", "eslint": "9.10.0", "eslint-plugin-unicorn": "55.0.0", "postcss": "^8.4.31", "prettier": "^3.0.3", "prettier-plugin-tailwindcss": "^0.5.5", "react": "^18.3.1", "react-dom": "^18.3.1", "tailwind-merge": "^2.5.4", "tailwindcss": "^3.4.14", "tailwindcss-animate": "^1.0.7", "tsup": "^8.3.5", "typescript": "^5.0.4", "vite": "^5.4.10", "vite-tsconfig-paths": "^5.0.1" }, "peerDependencies": { "react": "^18.2.0 || ^19", "react-dom": "^18.2.0 || ^19" } }