@cstar.help/react 0.10.4 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.cjs +170 -167
  2. package/dist/index.js +117 -114
  3. package/package.json +3 -3
package/dist/index.cjs CHANGED
@@ -465,105 +465,117 @@ function useCategories() {
465
465
  }
466
466
 
467
467
  // src/library/useArticles.ts
468
+ var import_react11 = require("react");
469
+
470
+ // src/useLatestCall.ts
468
471
  var import_react10 = require("react");
472
+ function useLatestCall() {
473
+ const latest = (0, import_react10.useRef)(0);
474
+ (0, import_react10.useEffect)(
475
+ () => () => {
476
+ latest.current += 1;
477
+ },
478
+ []
479
+ );
480
+ return (0, import_react10.useCallback)(() => {
481
+ const call = latest.current += 1;
482
+ return () => call === latest.current;
483
+ }, []);
484
+ }
485
+
486
+ // src/library/useArticles.ts
469
487
  function useArticles(params) {
470
488
  const client = useLibraryClient();
471
- const [articles, setArticles] = (0, import_react10.useState)([]);
472
- const [isLoading, setIsLoading] = (0, import_react10.useState)(true);
473
- const [error, setError] = (0, import_react10.useState)(null);
474
- const mountedRef = (0, import_react10.useRef)(true);
489
+ const [articles, setArticles] = (0, import_react11.useState)([]);
490
+ const [isLoading, setIsLoading] = (0, import_react11.useState)(true);
491
+ const [error, setError] = (0, import_react11.useState)(null);
492
+ const startCall = useLatestCall();
475
493
  const categorySlug = params?.categorySlug;
476
494
  const limit = params?.limit;
477
495
  const offset = params?.offset;
478
- const refresh = (0, import_react10.useCallback)(async () => {
496
+ const refresh = (0, import_react11.useCallback)(async () => {
497
+ const isLatest = startCall();
479
498
  setIsLoading(true);
480
499
  setError(null);
481
500
  try {
482
501
  const data = await client.articles({ categorySlug, limit, offset });
483
- if (mountedRef.current) {
502
+ if (isLatest()) {
484
503
  setArticles(data);
485
504
  }
486
505
  } catch (err) {
487
- if (mountedRef.current) {
506
+ if (isLatest()) {
488
507
  setError(err instanceof Error ? err : new Error(String(err)));
489
508
  }
490
509
  } finally {
491
- if (mountedRef.current) {
510
+ if (isLatest()) {
492
511
  setIsLoading(false);
493
512
  }
494
513
  }
495
- }, [client, categorySlug, limit, offset]);
496
- (0, import_react10.useEffect)(() => {
497
- mountedRef.current = true;
514
+ }, [client, categorySlug, limit, offset, startCall]);
515
+ (0, import_react11.useEffect)(() => {
498
516
  refresh();
499
- return () => {
500
- mountedRef.current = false;
501
- };
502
517
  }, [refresh]);
503
518
  return { articles, isLoading, error, refresh };
504
519
  }
505
520
 
506
521
  // src/library/useArticle.ts
507
- var import_react11 = require("react");
522
+ var import_react12 = require("react");
508
523
  function useArticle(slug) {
509
524
  const client = useLibraryClient();
510
- const [article, setArticle] = (0, import_react11.useState)(null);
511
- const [isLoading, setIsLoading] = (0, import_react11.useState)(true);
512
- const [error, setError] = (0, import_react11.useState)(null);
513
- const mountedRef = (0, import_react11.useRef)(true);
514
- const refresh = (0, import_react11.useCallback)(async () => {
525
+ const [article, setArticle] = (0, import_react12.useState)(null);
526
+ const [isLoading, setIsLoading] = (0, import_react12.useState)(true);
527
+ const [error, setError] = (0, import_react12.useState)(null);
528
+ const startCall = useLatestCall();
529
+ const refresh = (0, import_react12.useCallback)(async () => {
515
530
  if (!slug) return;
531
+ const isLatest = startCall();
516
532
  setIsLoading(true);
517
533
  setError(null);
518
534
  try {
519
535
  const data = await client.article(slug);
520
- if (mountedRef.current) {
536
+ if (isLatest()) {
521
537
  setArticle(data);
522
538
  }
523
539
  } catch (err) {
524
- if (mountedRef.current) {
540
+ if (isLatest()) {
525
541
  setError(err instanceof Error ? err : new Error(String(err)));
526
542
  }
527
543
  } finally {
528
- if (mountedRef.current) {
544
+ if (isLatest()) {
529
545
  setIsLoading(false);
530
546
  }
531
547
  }
532
- }, [client, slug]);
533
- const recordView = (0, import_react11.useCallback)(async () => {
548
+ }, [client, slug, startCall]);
549
+ const recordView = (0, import_react12.useCallback)(async () => {
534
550
  if (!slug) return;
535
551
  try {
536
552
  await client.recordView(slug);
537
553
  } catch {
538
554
  }
539
555
  }, [client, slug]);
540
- (0, import_react11.useEffect)(() => {
541
- mountedRef.current = true;
556
+ (0, import_react12.useEffect)(() => {
542
557
  if (!slug) {
558
+ startCall();
543
559
  setArticle(null);
544
560
  setIsLoading(false);
545
561
  return;
546
562
  }
547
563
  refresh();
548
- return () => {
549
- mountedRef.current = false;
550
- };
551
- }, [slug, refresh]);
564
+ }, [slug, refresh, startCall]);
552
565
  return { article, isLoading, error, refresh, recordView };
553
566
  }
554
567
 
555
568
  // src/library/useArticleSearch.ts
556
- var import_react12 = require("react");
569
+ var import_react13 = require("react");
557
570
  var DEBOUNCE_MS = 300;
558
571
  function useArticleSearch(query) {
559
572
  const client = useLibraryClient();
560
- const [results, setResults] = (0, import_react12.useState)([]);
561
- const [totalCount, setTotalCount] = (0, import_react12.useState)(0);
562
- const [isLoading, setIsLoading] = (0, import_react12.useState)(false);
563
- const [error, setError] = (0, import_react12.useState)(null);
564
- const mountedRef = (0, import_react12.useRef)(true);
565
- (0, import_react12.useEffect)(() => {
566
- mountedRef.current = true;
573
+ const [results, setResults] = (0, import_react13.useState)([]);
574
+ const [totalCount, setTotalCount] = (0, import_react13.useState)(0);
575
+ const [isLoading, setIsLoading] = (0, import_react13.useState)(false);
576
+ const [error, setError] = (0, import_react13.useState)(null);
577
+ (0, import_react13.useEffect)(() => {
578
+ let cancelled = false;
567
579
  const trimmed = query.trim();
568
580
  if (!trimmed) {
569
581
  setResults([]);
@@ -576,23 +588,23 @@ function useArticleSearch(query) {
576
588
  const timer = setTimeout(async () => {
577
589
  try {
578
590
  const result = await client.search(trimmed);
579
- if (mountedRef.current) {
591
+ if (!cancelled) {
580
592
  setResults(result.data);
581
593
  setTotalCount(result.count);
582
594
  setError(null);
583
595
  }
584
596
  } catch (err) {
585
- if (mountedRef.current) {
597
+ if (!cancelled) {
586
598
  setError(err instanceof Error ? err : new Error(String(err)));
587
599
  }
588
600
  } finally {
589
- if (mountedRef.current) {
601
+ if (!cancelled) {
590
602
  setIsLoading(false);
591
603
  }
592
604
  }
593
605
  }, DEBOUNCE_MS);
594
606
  return () => {
595
- mountedRef.current = false;
607
+ cancelled = true;
596
608
  clearTimeout(timer);
597
609
  };
598
610
  }, [client, query]);
@@ -600,11 +612,11 @@ function useArticleSearch(query) {
600
612
  }
601
613
 
602
614
  // src/community/CStarCommunityProvider.tsx
603
- var import_react13 = require("react");
615
+ var import_react14 = require("react");
604
616
  var import_community = require("@cstar.help/js/community");
605
617
  var import_jsx_runtime3 = require("react/jsx-runtime");
606
618
  function CStarCommunityProvider({ children, ...config }) {
607
- const clientRef = (0, import_react13.useRef)(null);
619
+ const clientRef = (0, import_react14.useRef)(null);
608
620
  if (!clientRef.current) {
609
621
  clientRef.current = new import_community.CommunityClient(config);
610
622
  }
@@ -612,14 +624,14 @@ function CStarCommunityProvider({ children, ...config }) {
612
624
  }
613
625
 
614
626
  // src/community/useTopics.ts
615
- var import_react14 = require("react");
627
+ var import_react15 = require("react");
616
628
  function useTopics() {
617
629
  const client = useCommunityClient();
618
- const [topics, setTopics] = (0, import_react14.useState)([]);
619
- const [isLoading, setIsLoading] = (0, import_react14.useState)(true);
620
- const [error, setError] = (0, import_react14.useState)(null);
621
- const mountedRef = (0, import_react14.useRef)(true);
622
- const refresh = (0, import_react14.useCallback)(async () => {
630
+ const [topics, setTopics] = (0, import_react15.useState)([]);
631
+ const [isLoading, setIsLoading] = (0, import_react15.useState)(true);
632
+ const [error, setError] = (0, import_react15.useState)(null);
633
+ const mountedRef = (0, import_react15.useRef)(true);
634
+ const refresh = (0, import_react15.useCallback)(async () => {
623
635
  setIsLoading(true);
624
636
  setError(null);
625
637
  try {
@@ -637,7 +649,7 @@ function useTopics() {
637
649
  }
638
650
  }
639
651
  }, [client]);
640
- (0, import_react14.useEffect)(() => {
652
+ (0, import_react15.useEffect)(() => {
641
653
  mountedRef.current = true;
642
654
  refresh();
643
655
  return () => {
@@ -648,131 +660,121 @@ function useTopics() {
648
660
  }
649
661
 
650
662
  // src/community/usePosts.ts
651
- var import_react15 = require("react");
663
+ var import_react16 = require("react");
652
664
  function usePosts(params) {
653
665
  const client = useCommunityClient();
654
- const [posts, setPosts] = (0, import_react15.useState)([]);
655
- const [count, setCount] = (0, import_react15.useState)(0);
656
- const [isLoading, setIsLoading] = (0, import_react15.useState)(true);
657
- const [error, setError] = (0, import_react15.useState)(null);
658
- const mountedRef = (0, import_react15.useRef)(true);
666
+ const [posts, setPosts] = (0, import_react16.useState)([]);
667
+ const [count, setCount] = (0, import_react16.useState)(0);
668
+ const [isLoading, setIsLoading] = (0, import_react16.useState)(true);
669
+ const [error, setError] = (0, import_react16.useState)(null);
670
+ const startCall = useLatestCall();
659
671
  const topicSlug = params?.topicSlug;
660
672
  const status = params?.status;
661
673
  const sort = params?.sort;
662
674
  const limit = params?.limit;
663
675
  const offset = params?.offset;
664
- const refresh = (0, import_react15.useCallback)(async () => {
676
+ const refresh = (0, import_react16.useCallback)(async () => {
677
+ const isLatest = startCall();
665
678
  setIsLoading(true);
666
679
  setError(null);
667
680
  try {
668
681
  const result = await client.posts({ topicSlug, status, sort, limit, offset });
669
- if (mountedRef.current) {
682
+ if (isLatest()) {
670
683
  setPosts(result.posts);
671
684
  setCount(result.count);
672
685
  }
673
686
  } catch (err) {
674
- if (mountedRef.current) {
687
+ if (isLatest()) {
675
688
  setError(err instanceof Error ? err : new Error(String(err)));
676
689
  }
677
690
  } finally {
678
- if (mountedRef.current) {
691
+ if (isLatest()) {
679
692
  setIsLoading(false);
680
693
  }
681
694
  }
682
- }, [client, topicSlug, status, sort, limit, offset]);
683
- (0, import_react15.useEffect)(() => {
684
- mountedRef.current = true;
695
+ }, [client, topicSlug, status, sort, limit, offset, startCall]);
696
+ (0, import_react16.useEffect)(() => {
685
697
  refresh();
686
- return () => {
687
- mountedRef.current = false;
688
- };
689
698
  }, [refresh]);
690
699
  return { posts, count, isLoading, error, refresh };
691
700
  }
692
701
 
693
702
  // src/community/usePost.ts
694
- var import_react16 = require("react");
703
+ var import_react17 = require("react");
695
704
  function usePost(slug) {
696
705
  const client = useCommunityClient();
697
- const [data, setData] = (0, import_react16.useState)(null);
698
- const [isLoading, setIsLoading] = (0, import_react16.useState)(true);
699
- const [error, setError] = (0, import_react16.useState)(null);
700
- const mountedRef = (0, import_react16.useRef)(true);
701
- const refresh = (0, import_react16.useCallback)(async () => {
706
+ const [data, setData] = (0, import_react17.useState)(null);
707
+ const [isLoading, setIsLoading] = (0, import_react17.useState)(true);
708
+ const [error, setError] = (0, import_react17.useState)(null);
709
+ const startCall = useLatestCall();
710
+ const refresh = (0, import_react17.useCallback)(async () => {
711
+ const isLatest = startCall();
702
712
  setIsLoading(true);
703
713
  setError(null);
704
714
  try {
705
715
  const result = await client.post(slug);
706
- if (mountedRef.current) {
716
+ if (isLatest()) {
707
717
  setData(result);
708
718
  }
709
719
  } catch (err) {
710
- if (mountedRef.current) {
720
+ if (isLatest()) {
711
721
  setError(err instanceof Error ? err : new Error(String(err)));
712
722
  }
713
723
  } finally {
714
- if (mountedRef.current) {
724
+ if (isLatest()) {
715
725
  setIsLoading(false);
716
726
  }
717
727
  }
718
- }, [client, slug]);
719
- (0, import_react16.useEffect)(() => {
720
- mountedRef.current = true;
728
+ }, [client, slug, startCall]);
729
+ (0, import_react17.useEffect)(() => {
721
730
  refresh();
722
- return () => {
723
- mountedRef.current = false;
724
- };
725
731
  }, [refresh]);
726
732
  return { data, isLoading, error, refresh };
727
733
  }
728
734
 
729
735
  // src/community/useCommunitySearch.ts
730
- var import_react17 = require("react");
736
+ var import_react18 = require("react");
731
737
  function useCommunitySearch() {
732
738
  const client = useCommunityClient();
733
- const [results, setResults] = (0, import_react17.useState)(null);
734
- const [isLoading, setIsLoading] = (0, import_react17.useState)(false);
735
- const [error, setError] = (0, import_react17.useState)(null);
736
- const mountedRef = (0, import_react17.useRef)(true);
737
- (0, import_react17.useEffect)(() => {
738
- mountedRef.current = true;
739
- return () => {
740
- mountedRef.current = false;
741
- };
742
- }, []);
743
- const search = (0, import_react17.useCallback)(
739
+ const [results, setResults] = (0, import_react18.useState)(null);
740
+ const [isLoading, setIsLoading] = (0, import_react18.useState)(false);
741
+ const [error, setError] = (0, import_react18.useState)(null);
742
+ const startCall = useLatestCall();
743
+ const search = (0, import_react18.useCallback)(
744
744
  async (query) => {
745
+ const isLatest = startCall();
745
746
  if (!query.trim()) {
746
747
  setResults(null);
748
+ setIsLoading(false);
747
749
  return;
748
750
  }
749
751
  setIsLoading(true);
750
752
  setError(null);
751
753
  try {
752
754
  const data = await client.search(query);
753
- if (mountedRef.current) {
755
+ if (isLatest()) {
754
756
  setResults(data);
755
757
  }
756
758
  } catch (err) {
757
- if (mountedRef.current) {
759
+ if (isLatest()) {
758
760
  setError(err instanceof Error ? err : new Error(String(err)));
759
761
  }
760
762
  } finally {
761
- if (mountedRef.current) {
763
+ if (isLatest()) {
762
764
  setIsLoading(false);
763
765
  }
764
766
  }
765
767
  },
766
- [client]
768
+ [client, startCall]
767
769
  );
768
770
  return { results, isLoading, error, search };
769
771
  }
770
772
 
771
773
  // src/dashboard/CStarDashboardProvider.tsx
772
- var import_react18 = require("react");
774
+ var import_react19 = require("react");
773
775
  var import_js = require("@cstar.help/js");
774
776
  var import_jsx_runtime4 = require("react/jsx-runtime");
775
- var CStarDashboardContext = (0, import_react18.createContext)(null);
777
+ var CStarDashboardContext = (0, import_react19.createContext)(null);
776
778
  function CStarDashboardProvider({
777
779
  config,
778
780
  client: providedClient,
@@ -783,7 +785,7 @@ function CStarDashboardProvider({
783
785
  "CStarDashboardProvider requires either a `config` prop (`{ apiKey, teamId }`, recommended) or a `client` prop (a pre-built CStarClient instance, deprecated). See https://www.cstar.help/developers/sdk/react#dashboard"
784
786
  );
785
787
  }
786
- const client = (0, import_react18.useMemo)(() => {
788
+ const client = (0, import_react19.useMemo)(() => {
787
789
  if (providedClient) return providedClient;
788
790
  return new import_js.CStarClient(config);
789
791
  }, [
@@ -795,12 +797,12 @@ function CStarDashboardProvider({
795
797
  config?.maxRetries,
796
798
  config?.timeout
797
799
  ]);
798
- const contextValue = (0, import_react18.useMemo)(() => ({ client }), [client]);
800
+ const contextValue = (0, import_react19.useMemo)(() => ({ client }), [client]);
799
801
  useDisconnectOnUnmount(providedClient ? null : client, (owned) => owned.realtime?.disconnect?.());
800
802
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CStarDashboardContext.Provider, { value: contextValue, children });
801
803
  }
802
804
  function useDashboardClient() {
803
- const ctx = (0, import_react18.useContext)(CStarDashboardContext);
805
+ const ctx = (0, import_react19.useContext)(CStarDashboardContext);
804
806
  if (!ctx) {
805
807
  throw new Error("useDashboardClient must be used within a <CStarDashboardProvider>");
806
808
  }
@@ -808,7 +810,7 @@ function useDashboardClient() {
808
810
  }
809
811
 
810
812
  // src/dashboard/useCStarQuery.ts
811
- var import_react19 = require("react");
813
+ var import_react20 = require("react");
812
814
  var import_js2 = require("@cstar.help/js");
813
815
  function resolveResource(client, path) {
814
816
  const parts = path.split(".");
@@ -827,12 +829,12 @@ function useCStarQuery(resource, params) {
827
829
  );
828
830
  }
829
831
  const client = useDashboardClient();
830
- const [data, setData] = (0, import_react19.useState)(null);
831
- const [loading, setLoading] = (0, import_react19.useState)(true);
832
- const [error, setError] = (0, import_react19.useState)(null);
833
- const subscriptionRef = (0, import_react19.useRef)(null);
832
+ const [data, setData] = (0, import_react20.useState)(null);
833
+ const [loading, setLoading] = (0, import_react20.useState)(true);
834
+ const [error, setError] = (0, import_react20.useState)(null);
835
+ const subscriptionRef = (0, import_react20.useRef)(null);
834
836
  const paramsKey = params ? JSON.stringify(params) : "";
835
- (0, import_react19.useEffect)(() => {
837
+ (0, import_react20.useEffect)(() => {
836
838
  const resolved = resolveResource(client, resource);
837
839
  if (!resolved) {
838
840
  setError(new Error(`Invalid resource path: ${resource}. Expected format: 'tickets.list'`));
@@ -855,7 +857,7 @@ function useCStarQuery(resource, params) {
855
857
  subscriptionRef.current = null;
856
858
  };
857
859
  }, [client, resource, paramsKey]);
858
- const refresh = (0, import_react19.useCallback)(async () => {
860
+ const refresh = (0, import_react20.useCallback)(async () => {
859
861
  if (subscriptionRef.current) {
860
862
  await subscriptionRef.current.refresh();
861
863
  }
@@ -864,37 +866,38 @@ function useCStarQuery(resource, params) {
864
866
  }
865
867
 
866
868
  // src/dashboard/useCStarMutation.ts
867
- var import_react20 = require("react");
869
+ var import_react21 = require("react");
868
870
  function resolveMutation(client, path) {
869
871
  const parts = path.split(".");
870
872
  if (parts.length < 2) return null;
871
- const resourceName = parts[0];
872
- const methodName = parts[1];
873
- const resource = client[resourceName];
874
- if (!resource || typeof resource !== "object") return null;
875
- const lookupName = methodName === "delete" ? "del" : methodName;
876
- const method = resource[lookupName];
877
- if (typeof method !== "function") return null;
878
- if (methodName === "update") {
879
- return (params) => {
880
- const p = params;
881
- const { id, ...rest } = p;
882
- return method.call(resource, id, rest);
883
- };
873
+ const last = parts[parts.length - 1];
874
+ const methodName = last === "delete" ? "del" : last;
875
+ let resource = client;
876
+ for (const part of parts.slice(0, -1)) {
877
+ resource = resource?.[part];
878
+ if (!resource || typeof resource !== "object") return null;
884
879
  }
885
- if (methodName === "del" || methodName === "delete") {
886
- return (params) => {
887
- const p = params;
888
- return method.call(resource, p.id);
889
- };
890
- }
891
- return (params) => method.call(resource, params);
880
+ const method = resource[methodName];
881
+ if (typeof method !== "function") return null;
882
+ const call = method;
883
+ const needsId = methodName === "del" || methodName === "update" && call.length >= 2;
884
+ return (params) => {
885
+ if (Array.isArray(params)) return call.apply(resource, params);
886
+ const { id, ...rest } = params ?? {};
887
+ if (typeof id === "string" && id) {
888
+ return Object.keys(rest).length > 0 ? call.call(resource, id, rest) : call.call(resource, id);
889
+ }
890
+ if (needsId) {
891
+ return Promise.reject(new Error(`Missing or invalid "id" for ${methodName} operation`));
892
+ }
893
+ return call.call(resource, params);
894
+ };
892
895
  }
893
896
  function useCStarMutation(resource) {
894
897
  const client = useDashboardClient();
895
- const [loading, setLoading] = (0, import_react20.useState)(false);
896
- const [error, setError] = (0, import_react20.useState)(null);
897
- const mutate = (0, import_react20.useCallback)(
898
+ const [loading, setLoading] = (0, import_react21.useState)(false);
899
+ const [error, setError] = (0, import_react21.useState)(null);
900
+ const mutate = (0, import_react21.useCallback)(
898
901
  async (params) => {
899
902
  const fn = resolveMutation(client, resource);
900
903
  if (!fn) {
@@ -919,14 +922,14 @@ function useCStarMutation(resource) {
919
922
  }
920
923
 
921
924
  // src/dashboard/useCStarEvents.ts
922
- var import_react21 = require("react");
925
+ var import_react22 = require("react");
923
926
  var MAX_EVENTS = 100;
924
927
  function useCStarEvents(types) {
925
928
  const client = useDashboardClient();
926
- const [events, setEvents] = (0, import_react21.useState)([]);
927
- const [connected, setConnected] = (0, import_react21.useState)(false);
929
+ const [events, setEvents] = (0, import_react22.useState)([]);
930
+ const [connected, setConnected] = (0, import_react22.useState)(false);
928
931
  const typesKey = types ? types.join(",") : "";
929
- (0, import_react21.useEffect)(() => {
932
+ (0, import_react22.useEffect)(() => {
930
933
  const realtime = client.realtime;
931
934
  const handler = (event) => {
932
935
  if (types && types.length > 0) {
@@ -958,14 +961,14 @@ function useCStarEvents(types) {
958
961
  }
959
962
 
960
963
  // src/dashboard/useBossBattle.ts
961
- var import_react22 = require("react");
964
+ var import_react23 = require("react");
962
965
  function useBossBattle() {
963
966
  const client = useDashboardClient();
964
- const [boss, setBoss] = (0, import_react22.useState)(null);
965
- const [loading, setLoading] = (0, import_react22.useState)(true);
966
- const [error, setError] = (0, import_react22.useState)(null);
967
- const subRef = (0, import_react22.useRef)(null);
968
- (0, import_react22.useEffect)(() => {
967
+ const [boss, setBoss] = (0, import_react23.useState)(null);
968
+ const [loading, setLoading] = (0, import_react23.useState)(true);
969
+ const [error, setError] = (0, import_react23.useState)(null);
970
+ const subRef = (0, import_react23.useRef)(null);
971
+ (0, import_react23.useEffect)(() => {
969
972
  const sub = client.game.subscribeBoss(client.realtime);
970
973
  subRef.current = sub;
971
974
  sub.on("change", (data) => {
@@ -982,21 +985,21 @@ function useBossBattle() {
982
985
  subRef.current = null;
983
986
  };
984
987
  }, [client]);
985
- const refresh = (0, import_react22.useCallback)(async () => {
988
+ const refresh = (0, import_react23.useCallback)(async () => {
986
989
  if (subRef.current) await subRef.current.refresh();
987
990
  }, []);
988
991
  return { boss, active: boss !== null, loading, error, refresh };
989
992
  }
990
993
 
991
994
  // src/dashboard/usePlayerStats.ts
992
- var import_react23 = require("react");
995
+ var import_react24 = require("react");
993
996
  function usePlayerStats(memberId) {
994
997
  const client = useDashboardClient();
995
- const [player, setPlayer] = (0, import_react23.useState)(null);
996
- const [loading, setLoading] = (0, import_react23.useState)(true);
997
- const [error, setError] = (0, import_react23.useState)(null);
998
- const subRef = (0, import_react23.useRef)(null);
999
- (0, import_react23.useEffect)(() => {
998
+ const [player, setPlayer] = (0, import_react24.useState)(null);
999
+ const [loading, setLoading] = (0, import_react24.useState)(true);
1000
+ const [error, setError] = (0, import_react24.useState)(null);
1001
+ const subRef = (0, import_react24.useRef)(null);
1002
+ (0, import_react24.useEffect)(() => {
1000
1003
  const sub = client.game.subscribePlayer(client.realtime, memberId);
1001
1004
  subRef.current = sub;
1002
1005
  sub.on("change", (data) => {
@@ -1013,21 +1016,21 @@ function usePlayerStats(memberId) {
1013
1016
  subRef.current = null;
1014
1017
  };
1015
1018
  }, [client, memberId]);
1016
- const refresh = (0, import_react23.useCallback)(async () => {
1019
+ const refresh = (0, import_react24.useCallback)(async () => {
1017
1020
  if (subRef.current) await subRef.current.refresh();
1018
1021
  }, []);
1019
1022
  return { player, loading, error, refresh };
1020
1023
  }
1021
1024
 
1022
1025
  // src/dashboard/useLeaderboard.ts
1023
- var import_react24 = require("react");
1026
+ var import_react25 = require("react");
1024
1027
  function useLeaderboard(period) {
1025
1028
  const client = useDashboardClient();
1026
- const [entries, setEntries] = (0, import_react24.useState)([]);
1027
- const [loading, setLoading] = (0, import_react24.useState)(true);
1028
- const [error, setError] = (0, import_react24.useState)(null);
1029
- const subRef = (0, import_react24.useRef)(null);
1030
- (0, import_react24.useEffect)(() => {
1029
+ const [entries, setEntries] = (0, import_react25.useState)([]);
1030
+ const [loading, setLoading] = (0, import_react25.useState)(true);
1031
+ const [error, setError] = (0, import_react25.useState)(null);
1032
+ const subRef = (0, import_react25.useRef)(null);
1033
+ (0, import_react25.useEffect)(() => {
1031
1034
  const sub = client.game.subscribeLeaderboard(client.realtime, period ? { period } : void 0);
1032
1035
  subRef.current = sub;
1033
1036
  sub.on("change", (data) => {
@@ -1044,21 +1047,21 @@ function useLeaderboard(period) {
1044
1047
  subRef.current = null;
1045
1048
  };
1046
1049
  }, [client, period]);
1047
- const refresh = (0, import_react24.useCallback)(async () => {
1050
+ const refresh = (0, import_react25.useCallback)(async () => {
1048
1051
  if (subRef.current) await subRef.current.refresh();
1049
1052
  }, []);
1050
1053
  return { entries, loading, error, refresh };
1051
1054
  }
1052
1055
 
1053
1056
  // src/dashboard/useGameActivity.ts
1054
- var import_react25 = require("react");
1057
+ var import_react26 = require("react");
1055
1058
  function useGameActivity() {
1056
1059
  const client = useDashboardClient();
1057
- const [events, setEvents] = (0, import_react25.useState)([]);
1058
- const [loading, setLoading] = (0, import_react25.useState)(true);
1059
- const [error, setError] = (0, import_react25.useState)(null);
1060
- const subRef = (0, import_react25.useRef)(null);
1061
- (0, import_react25.useEffect)(() => {
1060
+ const [events, setEvents] = (0, import_react26.useState)([]);
1061
+ const [loading, setLoading] = (0, import_react26.useState)(true);
1062
+ const [error, setError] = (0, import_react26.useState)(null);
1063
+ const subRef = (0, import_react26.useRef)(null);
1064
+ (0, import_react26.useEffect)(() => {
1062
1065
  const sub = client.game.subscribeActivity(client.realtime);
1063
1066
  subRef.current = sub;
1064
1067
  sub.on("change", (data) => {
@@ -1075,7 +1078,7 @@ function useGameActivity() {
1075
1078
  subRef.current = null;
1076
1079
  };
1077
1080
  }, [client]);
1078
- const refresh = (0, import_react25.useCallback)(async () => {
1081
+ const refresh = (0, import_react26.useCallback)(async () => {
1079
1082
  if (subRef.current) await subRef.current.refresh();
1080
1083
  }, []);
1081
1084
  return { events, loading, error, refresh };
package/dist/index.js CHANGED
@@ -411,95 +411,108 @@ function useCategories() {
411
411
  }
412
412
 
413
413
  // src/library/useArticles.ts
414
- import { useState as useState6, useEffect as useEffect7, useCallback as useCallback6, useRef as useRef8 } from "react";
414
+ import { useState as useState6, useEffect as useEffect8, useCallback as useCallback7 } from "react";
415
+
416
+ // src/useLatestCall.ts
417
+ import { useCallback as useCallback6, useEffect as useEffect7, useRef as useRef8 } from "react";
418
+ function useLatestCall() {
419
+ const latest = useRef8(0);
420
+ useEffect7(
421
+ () => () => {
422
+ latest.current += 1;
423
+ },
424
+ []
425
+ );
426
+ return useCallback6(() => {
427
+ const call = latest.current += 1;
428
+ return () => call === latest.current;
429
+ }, []);
430
+ }
431
+
432
+ // src/library/useArticles.ts
415
433
  function useArticles(params) {
416
434
  const client = useLibraryClient();
417
435
  const [articles, setArticles] = useState6([]);
418
436
  const [isLoading, setIsLoading] = useState6(true);
419
437
  const [error, setError] = useState6(null);
420
- const mountedRef = useRef8(true);
438
+ const startCall = useLatestCall();
421
439
  const categorySlug = params?.categorySlug;
422
440
  const limit = params?.limit;
423
441
  const offset = params?.offset;
424
- const refresh = useCallback6(async () => {
442
+ const refresh = useCallback7(async () => {
443
+ const isLatest = startCall();
425
444
  setIsLoading(true);
426
445
  setError(null);
427
446
  try {
428
447
  const data = await client.articles({ categorySlug, limit, offset });
429
- if (mountedRef.current) {
448
+ if (isLatest()) {
430
449
  setArticles(data);
431
450
  }
432
451
  } catch (err) {
433
- if (mountedRef.current) {
452
+ if (isLatest()) {
434
453
  setError(err instanceof Error ? err : new Error(String(err)));
435
454
  }
436
455
  } finally {
437
- if (mountedRef.current) {
456
+ if (isLatest()) {
438
457
  setIsLoading(false);
439
458
  }
440
459
  }
441
- }, [client, categorySlug, limit, offset]);
442
- useEffect7(() => {
443
- mountedRef.current = true;
460
+ }, [client, categorySlug, limit, offset, startCall]);
461
+ useEffect8(() => {
444
462
  refresh();
445
- return () => {
446
- mountedRef.current = false;
447
- };
448
463
  }, [refresh]);
449
464
  return { articles, isLoading, error, refresh };
450
465
  }
451
466
 
452
467
  // src/library/useArticle.ts
453
- import { useState as useState7, useEffect as useEffect8, useCallback as useCallback7, useRef as useRef9 } from "react";
468
+ import { useState as useState7, useEffect as useEffect9, useCallback as useCallback8 } from "react";
454
469
  function useArticle(slug) {
455
470
  const client = useLibraryClient();
456
471
  const [article, setArticle] = useState7(null);
457
472
  const [isLoading, setIsLoading] = useState7(true);
458
473
  const [error, setError] = useState7(null);
459
- const mountedRef = useRef9(true);
460
- const refresh = useCallback7(async () => {
474
+ const startCall = useLatestCall();
475
+ const refresh = useCallback8(async () => {
461
476
  if (!slug) return;
477
+ const isLatest = startCall();
462
478
  setIsLoading(true);
463
479
  setError(null);
464
480
  try {
465
481
  const data = await client.article(slug);
466
- if (mountedRef.current) {
482
+ if (isLatest()) {
467
483
  setArticle(data);
468
484
  }
469
485
  } catch (err) {
470
- if (mountedRef.current) {
486
+ if (isLatest()) {
471
487
  setError(err instanceof Error ? err : new Error(String(err)));
472
488
  }
473
489
  } finally {
474
- if (mountedRef.current) {
490
+ if (isLatest()) {
475
491
  setIsLoading(false);
476
492
  }
477
493
  }
478
- }, [client, slug]);
479
- const recordView = useCallback7(async () => {
494
+ }, [client, slug, startCall]);
495
+ const recordView = useCallback8(async () => {
480
496
  if (!slug) return;
481
497
  try {
482
498
  await client.recordView(slug);
483
499
  } catch {
484
500
  }
485
501
  }, [client, slug]);
486
- useEffect8(() => {
487
- mountedRef.current = true;
502
+ useEffect9(() => {
488
503
  if (!slug) {
504
+ startCall();
489
505
  setArticle(null);
490
506
  setIsLoading(false);
491
507
  return;
492
508
  }
493
509
  refresh();
494
- return () => {
495
- mountedRef.current = false;
496
- };
497
- }, [slug, refresh]);
510
+ }, [slug, refresh, startCall]);
498
511
  return { article, isLoading, error, refresh, recordView };
499
512
  }
500
513
 
501
514
  // src/library/useArticleSearch.ts
502
- import { useState as useState8, useEffect as useEffect9, useRef as useRef10 } from "react";
515
+ import { useState as useState8, useEffect as useEffect10 } from "react";
503
516
  var DEBOUNCE_MS = 300;
504
517
  function useArticleSearch(query) {
505
518
  const client = useLibraryClient();
@@ -507,9 +520,8 @@ function useArticleSearch(query) {
507
520
  const [totalCount, setTotalCount] = useState8(0);
508
521
  const [isLoading, setIsLoading] = useState8(false);
509
522
  const [error, setError] = useState8(null);
510
- const mountedRef = useRef10(true);
511
- useEffect9(() => {
512
- mountedRef.current = true;
523
+ useEffect10(() => {
524
+ let cancelled = false;
513
525
  const trimmed = query.trim();
514
526
  if (!trimmed) {
515
527
  setResults([]);
@@ -522,23 +534,23 @@ function useArticleSearch(query) {
522
534
  const timer = setTimeout(async () => {
523
535
  try {
524
536
  const result = await client.search(trimmed);
525
- if (mountedRef.current) {
537
+ if (!cancelled) {
526
538
  setResults(result.data);
527
539
  setTotalCount(result.count);
528
540
  setError(null);
529
541
  }
530
542
  } catch (err) {
531
- if (mountedRef.current) {
543
+ if (!cancelled) {
532
544
  setError(err instanceof Error ? err : new Error(String(err)));
533
545
  }
534
546
  } finally {
535
- if (mountedRef.current) {
547
+ if (!cancelled) {
536
548
  setIsLoading(false);
537
549
  }
538
550
  }
539
551
  }, DEBOUNCE_MS);
540
552
  return () => {
541
- mountedRef.current = false;
553
+ cancelled = true;
542
554
  clearTimeout(timer);
543
555
  };
544
556
  }, [client, query]);
@@ -546,11 +558,11 @@ function useArticleSearch(query) {
546
558
  }
547
559
 
548
560
  // src/community/CStarCommunityProvider.tsx
549
- import { useRef as useRef11 } from "react";
561
+ import { useRef as useRef9 } from "react";
550
562
  import { CommunityClient } from "@cstar.help/js/community";
551
563
  import { jsx as jsx3 } from "react/jsx-runtime";
552
564
  function CStarCommunityProvider({ children, ...config }) {
553
- const clientRef = useRef11(null);
565
+ const clientRef = useRef9(null);
554
566
  if (!clientRef.current) {
555
567
  clientRef.current = new CommunityClient(config);
556
568
  }
@@ -558,14 +570,14 @@ function CStarCommunityProvider({ children, ...config }) {
558
570
  }
559
571
 
560
572
  // src/community/useTopics.ts
561
- import { useState as useState9, useEffect as useEffect10, useCallback as useCallback8, useRef as useRef12 } from "react";
573
+ import { useState as useState9, useEffect as useEffect11, useCallback as useCallback9, useRef as useRef10 } from "react";
562
574
  function useTopics() {
563
575
  const client = useCommunityClient();
564
576
  const [topics, setTopics] = useState9([]);
565
577
  const [isLoading, setIsLoading] = useState9(true);
566
578
  const [error, setError] = useState9(null);
567
- const mountedRef = useRef12(true);
568
- const refresh = useCallback8(async () => {
579
+ const mountedRef = useRef10(true);
580
+ const refresh = useCallback9(async () => {
569
581
  setIsLoading(true);
570
582
  setError(null);
571
583
  try {
@@ -583,7 +595,7 @@ function useTopics() {
583
595
  }
584
596
  }
585
597
  }, [client]);
586
- useEffect10(() => {
598
+ useEffect11(() => {
587
599
  mountedRef.current = true;
588
600
  refresh();
589
601
  return () => {
@@ -594,122 +606,112 @@ function useTopics() {
594
606
  }
595
607
 
596
608
  // src/community/usePosts.ts
597
- import { useState as useState10, useEffect as useEffect11, useCallback as useCallback9, useRef as useRef13 } from "react";
609
+ import { useState as useState10, useEffect as useEffect12, useCallback as useCallback10 } from "react";
598
610
  function usePosts(params) {
599
611
  const client = useCommunityClient();
600
612
  const [posts, setPosts] = useState10([]);
601
613
  const [count, setCount] = useState10(0);
602
614
  const [isLoading, setIsLoading] = useState10(true);
603
615
  const [error, setError] = useState10(null);
604
- const mountedRef = useRef13(true);
616
+ const startCall = useLatestCall();
605
617
  const topicSlug = params?.topicSlug;
606
618
  const status = params?.status;
607
619
  const sort = params?.sort;
608
620
  const limit = params?.limit;
609
621
  const offset = params?.offset;
610
- const refresh = useCallback9(async () => {
622
+ const refresh = useCallback10(async () => {
623
+ const isLatest = startCall();
611
624
  setIsLoading(true);
612
625
  setError(null);
613
626
  try {
614
627
  const result = await client.posts({ topicSlug, status, sort, limit, offset });
615
- if (mountedRef.current) {
628
+ if (isLatest()) {
616
629
  setPosts(result.posts);
617
630
  setCount(result.count);
618
631
  }
619
632
  } catch (err) {
620
- if (mountedRef.current) {
633
+ if (isLatest()) {
621
634
  setError(err instanceof Error ? err : new Error(String(err)));
622
635
  }
623
636
  } finally {
624
- if (mountedRef.current) {
637
+ if (isLatest()) {
625
638
  setIsLoading(false);
626
639
  }
627
640
  }
628
- }, [client, topicSlug, status, sort, limit, offset]);
629
- useEffect11(() => {
630
- mountedRef.current = true;
641
+ }, [client, topicSlug, status, sort, limit, offset, startCall]);
642
+ useEffect12(() => {
631
643
  refresh();
632
- return () => {
633
- mountedRef.current = false;
634
- };
635
644
  }, [refresh]);
636
645
  return { posts, count, isLoading, error, refresh };
637
646
  }
638
647
 
639
648
  // src/community/usePost.ts
640
- import { useState as useState11, useEffect as useEffect12, useCallback as useCallback10, useRef as useRef14 } from "react";
649
+ import { useState as useState11, useEffect as useEffect13, useCallback as useCallback11 } from "react";
641
650
  function usePost(slug) {
642
651
  const client = useCommunityClient();
643
652
  const [data, setData] = useState11(null);
644
653
  const [isLoading, setIsLoading] = useState11(true);
645
654
  const [error, setError] = useState11(null);
646
- const mountedRef = useRef14(true);
647
- const refresh = useCallback10(async () => {
655
+ const startCall = useLatestCall();
656
+ const refresh = useCallback11(async () => {
657
+ const isLatest = startCall();
648
658
  setIsLoading(true);
649
659
  setError(null);
650
660
  try {
651
661
  const result = await client.post(slug);
652
- if (mountedRef.current) {
662
+ if (isLatest()) {
653
663
  setData(result);
654
664
  }
655
665
  } catch (err) {
656
- if (mountedRef.current) {
666
+ if (isLatest()) {
657
667
  setError(err instanceof Error ? err : new Error(String(err)));
658
668
  }
659
669
  } finally {
660
- if (mountedRef.current) {
670
+ if (isLatest()) {
661
671
  setIsLoading(false);
662
672
  }
663
673
  }
664
- }, [client, slug]);
665
- useEffect12(() => {
666
- mountedRef.current = true;
674
+ }, [client, slug, startCall]);
675
+ useEffect13(() => {
667
676
  refresh();
668
- return () => {
669
- mountedRef.current = false;
670
- };
671
677
  }, [refresh]);
672
678
  return { data, isLoading, error, refresh };
673
679
  }
674
680
 
675
681
  // src/community/useCommunitySearch.ts
676
- import { useState as useState12, useEffect as useEffect13, useCallback as useCallback11, useRef as useRef15 } from "react";
682
+ import { useState as useState12, useCallback as useCallback12 } from "react";
677
683
  function useCommunitySearch() {
678
684
  const client = useCommunityClient();
679
685
  const [results, setResults] = useState12(null);
680
686
  const [isLoading, setIsLoading] = useState12(false);
681
687
  const [error, setError] = useState12(null);
682
- const mountedRef = useRef15(true);
683
- useEffect13(() => {
684
- mountedRef.current = true;
685
- return () => {
686
- mountedRef.current = false;
687
- };
688
- }, []);
689
- const search = useCallback11(
688
+ const startCall = useLatestCall();
689
+ const search = useCallback12(
690
690
  async (query) => {
691
+ const isLatest = startCall();
691
692
  if (!query.trim()) {
692
693
  setResults(null);
694
+ setIsLoading(false);
693
695
  return;
694
696
  }
695
697
  setIsLoading(true);
696
698
  setError(null);
697
699
  try {
698
700
  const data = await client.search(query);
699
- if (mountedRef.current) {
701
+ if (isLatest()) {
700
702
  setResults(data);
701
703
  }
702
704
  } catch (err) {
703
- if (mountedRef.current) {
705
+ if (isLatest()) {
704
706
  setError(err instanceof Error ? err : new Error(String(err)));
705
707
  }
706
708
  } finally {
707
- if (mountedRef.current) {
709
+ if (isLatest()) {
708
710
  setIsLoading(false);
709
711
  }
710
712
  }
711
713
  },
712
- [client]
714
+ [client, startCall]
713
715
  );
714
716
  return { results, isLoading, error, search };
715
717
  }
@@ -754,7 +756,7 @@ function useDashboardClient() {
754
756
  }
755
757
 
756
758
  // src/dashboard/useCStarQuery.ts
757
- import { useState as useState13, useEffect as useEffect14, useRef as useRef16, useCallback as useCallback12 } from "react";
759
+ import { useState as useState13, useEffect as useEffect14, useRef as useRef11, useCallback as useCallback13 } from "react";
758
760
  import { CStarValidationError } from "@cstar.help/js";
759
761
  function resolveResource(client, path) {
760
762
  const parts = path.split(".");
@@ -776,7 +778,7 @@ function useCStarQuery(resource, params) {
776
778
  const [data, setData] = useState13(null);
777
779
  const [loading, setLoading] = useState13(true);
778
780
  const [error, setError] = useState13(null);
779
- const subscriptionRef = useRef16(null);
781
+ const subscriptionRef = useRef11(null);
780
782
  const paramsKey = params ? JSON.stringify(params) : "";
781
783
  useEffect14(() => {
782
784
  const resolved = resolveResource(client, resource);
@@ -801,7 +803,7 @@ function useCStarQuery(resource, params) {
801
803
  subscriptionRef.current = null;
802
804
  };
803
805
  }, [client, resource, paramsKey]);
804
- const refresh = useCallback12(async () => {
806
+ const refresh = useCallback13(async () => {
805
807
  if (subscriptionRef.current) {
806
808
  await subscriptionRef.current.refresh();
807
809
  }
@@ -810,37 +812,38 @@ function useCStarQuery(resource, params) {
810
812
  }
811
813
 
812
814
  // src/dashboard/useCStarMutation.ts
813
- import { useState as useState14, useCallback as useCallback13 } from "react";
815
+ import { useState as useState14, useCallback as useCallback14 } from "react";
814
816
  function resolveMutation(client, path) {
815
817
  const parts = path.split(".");
816
818
  if (parts.length < 2) return null;
817
- const resourceName = parts[0];
818
- const methodName = parts[1];
819
- const resource = client[resourceName];
820
- if (!resource || typeof resource !== "object") return null;
821
- const lookupName = methodName === "delete" ? "del" : methodName;
822
- const method = resource[lookupName];
823
- if (typeof method !== "function") return null;
824
- if (methodName === "update") {
825
- return (params) => {
826
- const p = params;
827
- const { id, ...rest } = p;
828
- return method.call(resource, id, rest);
829
- };
830
- }
831
- if (methodName === "del" || methodName === "delete") {
832
- return (params) => {
833
- const p = params;
834
- return method.call(resource, p.id);
835
- };
819
+ const last = parts[parts.length - 1];
820
+ const methodName = last === "delete" ? "del" : last;
821
+ let resource = client;
822
+ for (const part of parts.slice(0, -1)) {
823
+ resource = resource?.[part];
824
+ if (!resource || typeof resource !== "object") return null;
836
825
  }
837
- return (params) => method.call(resource, params);
826
+ const method = resource[methodName];
827
+ if (typeof method !== "function") return null;
828
+ const call = method;
829
+ const needsId = methodName === "del" || methodName === "update" && call.length >= 2;
830
+ return (params) => {
831
+ if (Array.isArray(params)) return call.apply(resource, params);
832
+ const { id, ...rest } = params ?? {};
833
+ if (typeof id === "string" && id) {
834
+ return Object.keys(rest).length > 0 ? call.call(resource, id, rest) : call.call(resource, id);
835
+ }
836
+ if (needsId) {
837
+ return Promise.reject(new Error(`Missing or invalid "id" for ${methodName} operation`));
838
+ }
839
+ return call.call(resource, params);
840
+ };
838
841
  }
839
842
  function useCStarMutation(resource) {
840
843
  const client = useDashboardClient();
841
844
  const [loading, setLoading] = useState14(false);
842
845
  const [error, setError] = useState14(null);
843
- const mutate = useCallback13(
846
+ const mutate = useCallback14(
844
847
  async (params) => {
845
848
  const fn = resolveMutation(client, resource);
846
849
  if (!fn) {
@@ -904,13 +907,13 @@ function useCStarEvents(types) {
904
907
  }
905
908
 
906
909
  // src/dashboard/useBossBattle.ts
907
- import { useState as useState16, useEffect as useEffect16, useRef as useRef17, useCallback as useCallback14 } from "react";
910
+ import { useState as useState16, useEffect as useEffect16, useRef as useRef12, useCallback as useCallback15 } from "react";
908
911
  function useBossBattle() {
909
912
  const client = useDashboardClient();
910
913
  const [boss, setBoss] = useState16(null);
911
914
  const [loading, setLoading] = useState16(true);
912
915
  const [error, setError] = useState16(null);
913
- const subRef = useRef17(null);
916
+ const subRef = useRef12(null);
914
917
  useEffect16(() => {
915
918
  const sub = client.game.subscribeBoss(client.realtime);
916
919
  subRef.current = sub;
@@ -928,20 +931,20 @@ function useBossBattle() {
928
931
  subRef.current = null;
929
932
  };
930
933
  }, [client]);
931
- const refresh = useCallback14(async () => {
934
+ const refresh = useCallback15(async () => {
932
935
  if (subRef.current) await subRef.current.refresh();
933
936
  }, []);
934
937
  return { boss, active: boss !== null, loading, error, refresh };
935
938
  }
936
939
 
937
940
  // src/dashboard/usePlayerStats.ts
938
- import { useState as useState17, useEffect as useEffect17, useRef as useRef18, useCallback as useCallback15 } from "react";
941
+ import { useState as useState17, useEffect as useEffect17, useRef as useRef13, useCallback as useCallback16 } from "react";
939
942
  function usePlayerStats(memberId) {
940
943
  const client = useDashboardClient();
941
944
  const [player, setPlayer] = useState17(null);
942
945
  const [loading, setLoading] = useState17(true);
943
946
  const [error, setError] = useState17(null);
944
- const subRef = useRef18(null);
947
+ const subRef = useRef13(null);
945
948
  useEffect17(() => {
946
949
  const sub = client.game.subscribePlayer(client.realtime, memberId);
947
950
  subRef.current = sub;
@@ -959,20 +962,20 @@ function usePlayerStats(memberId) {
959
962
  subRef.current = null;
960
963
  };
961
964
  }, [client, memberId]);
962
- const refresh = useCallback15(async () => {
965
+ const refresh = useCallback16(async () => {
963
966
  if (subRef.current) await subRef.current.refresh();
964
967
  }, []);
965
968
  return { player, loading, error, refresh };
966
969
  }
967
970
 
968
971
  // src/dashboard/useLeaderboard.ts
969
- import { useState as useState18, useEffect as useEffect18, useRef as useRef19, useCallback as useCallback16 } from "react";
972
+ import { useState as useState18, useEffect as useEffect18, useRef as useRef14, useCallback as useCallback17 } from "react";
970
973
  function useLeaderboard(period) {
971
974
  const client = useDashboardClient();
972
975
  const [entries, setEntries] = useState18([]);
973
976
  const [loading, setLoading] = useState18(true);
974
977
  const [error, setError] = useState18(null);
975
- const subRef = useRef19(null);
978
+ const subRef = useRef14(null);
976
979
  useEffect18(() => {
977
980
  const sub = client.game.subscribeLeaderboard(client.realtime, period ? { period } : void 0);
978
981
  subRef.current = sub;
@@ -990,20 +993,20 @@ function useLeaderboard(period) {
990
993
  subRef.current = null;
991
994
  };
992
995
  }, [client, period]);
993
- const refresh = useCallback16(async () => {
996
+ const refresh = useCallback17(async () => {
994
997
  if (subRef.current) await subRef.current.refresh();
995
998
  }, []);
996
999
  return { entries, loading, error, refresh };
997
1000
  }
998
1001
 
999
1002
  // src/dashboard/useGameActivity.ts
1000
- import { useState as useState19, useEffect as useEffect19, useRef as useRef20, useCallback as useCallback17 } from "react";
1003
+ import { useState as useState19, useEffect as useEffect19, useRef as useRef15, useCallback as useCallback18 } from "react";
1001
1004
  function useGameActivity() {
1002
1005
  const client = useDashboardClient();
1003
1006
  const [events, setEvents] = useState19([]);
1004
1007
  const [loading, setLoading] = useState19(true);
1005
1008
  const [error, setError] = useState19(null);
1006
- const subRef = useRef20(null);
1009
+ const subRef = useRef15(null);
1007
1010
  useEffect19(() => {
1008
1011
  const sub = client.game.subscribeActivity(client.realtime);
1009
1012
  subRef.current = sub;
@@ -1021,7 +1024,7 @@ function useGameActivity() {
1021
1024
  subRef.current = null;
1022
1025
  };
1023
1026
  }, [client]);
1024
- const refresh = useCallback17(async () => {
1027
+ const refresh = useCallback18(async () => {
1025
1028
  if (subRef.current) await subRef.current.refresh();
1026
1029
  }, []);
1027
1030
  return { events, loading, error, refresh };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cstar.help/react",
3
- "version": "0.10.4",
3
+ "version": "0.11.0",
4
4
  "description": "React hooks for the cStar customer support platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -30,12 +30,12 @@
30
30
  },
31
31
  "peerDependencies": {
32
32
  "react": ">=18.0.0",
33
- "@cstar.help/js": "^0.18.5"
33
+ "@cstar.help/js": "^0.19.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "react": "^18.3.1",
37
37
  "react-dom": "^18.3.1",
38
- "@cstar.help/js": "^0.18.5",
38
+ "@cstar.help/js": "^0.19.0",
39
39
  "@testing-library/react": "^16.1.0",
40
40
  "@types/react": "^18.3.0",
41
41
  "@types/react-dom": "^18.3.0",