@cstar.help/react 0.5.0 → 0.6.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.
- package/dist/index.cjs +306 -0
- package/dist/index.d.cts +159 -2
- package/dist/index.d.ts +159 -2
- package/dist/index.js +297 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -24,19 +24,28 @@ __export(src_exports, {
|
|
|
24
24
|
CStarChatProvider: () => CStarChatProvider,
|
|
25
25
|
CStarCommunityContext: () => CStarCommunityContext,
|
|
26
26
|
CStarCommunityProvider: () => CStarCommunityProvider,
|
|
27
|
+
CStarDashboardProvider: () => CStarDashboardProvider,
|
|
27
28
|
CStarLibraryContext: () => CStarLibraryContext,
|
|
28
29
|
CStarLibraryProvider: () => CStarLibraryProvider,
|
|
29
30
|
useArticle: () => useArticle,
|
|
30
31
|
useArticleSearch: () => useArticleSearch,
|
|
31
32
|
useArticles: () => useArticles,
|
|
33
|
+
useBossBattle: () => useBossBattle,
|
|
34
|
+
useCStarEvents: () => useCStarEvents,
|
|
35
|
+
useCStarMutation: () => useCStarMutation,
|
|
36
|
+
useCStarQuery: () => useCStarQuery,
|
|
32
37
|
useCategories: () => useCategories,
|
|
33
38
|
useChat: () => useChat,
|
|
34
39
|
useChatClient: () => useChatClient,
|
|
35
40
|
useCommunityClient: () => useCommunityClient,
|
|
36
41
|
useCommunitySearch: () => useCommunitySearch,
|
|
37
42
|
useConversations: () => useConversations,
|
|
43
|
+
useDashboardClient: () => useDashboardClient,
|
|
44
|
+
useGameActivity: () => useGameActivity,
|
|
45
|
+
useLeaderboard: () => useLeaderboard,
|
|
38
46
|
useLibraryClient: () => useLibraryClient,
|
|
39
47
|
useMessages: () => useMessages,
|
|
48
|
+
usePlayerStats: () => usePlayerStats,
|
|
40
49
|
usePost: () => usePost,
|
|
41
50
|
usePosts: () => usePosts,
|
|
42
51
|
useTopics: () => useTopics,
|
|
@@ -664,25 +673,322 @@ function useCommunitySearch() {
|
|
|
664
673
|
);
|
|
665
674
|
return { results, isLoading, error, search };
|
|
666
675
|
}
|
|
676
|
+
|
|
677
|
+
// src/dashboard/CStarDashboardProvider.tsx
|
|
678
|
+
var import_react17 = require("react");
|
|
679
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
680
|
+
var CStarDashboardContext = (0, import_react17.createContext)(null);
|
|
681
|
+
function CStarDashboardProvider({ client, children }) {
|
|
682
|
+
const contextValue = (0, import_react17.useRef)({ client }).current;
|
|
683
|
+
(0, import_react17.useEffect)(() => {
|
|
684
|
+
return () => {
|
|
685
|
+
client.realtime.disconnect();
|
|
686
|
+
};
|
|
687
|
+
}, [client]);
|
|
688
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CStarDashboardContext.Provider, { value: contextValue, children });
|
|
689
|
+
}
|
|
690
|
+
function useDashboardClient() {
|
|
691
|
+
const ctx = (0, import_react17.useContext)(CStarDashboardContext);
|
|
692
|
+
if (!ctx) {
|
|
693
|
+
throw new Error("useDashboardClient must be used within a <CStarDashboardProvider>");
|
|
694
|
+
}
|
|
695
|
+
return ctx.client;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// src/dashboard/useCStarQuery.ts
|
|
699
|
+
var import_react18 = require("react");
|
|
700
|
+
function resolveResource(client, path) {
|
|
701
|
+
const parts = path.split(".");
|
|
702
|
+
if (parts.length < 2 || parts[1] !== "list") return null;
|
|
703
|
+
const resourceName = parts[0];
|
|
704
|
+
const resource = client[resourceName];
|
|
705
|
+
if (!resource || typeof resource !== "object") return null;
|
|
706
|
+
const typed = resource;
|
|
707
|
+
if (typeof typed.list !== "function" || typeof typed.subscribe !== "function") return null;
|
|
708
|
+
return { resource, basePath: `/${resourceName}` };
|
|
709
|
+
}
|
|
710
|
+
function useCStarQuery(resource, params) {
|
|
711
|
+
const client = useDashboardClient();
|
|
712
|
+
const [data, setData] = (0, import_react18.useState)(null);
|
|
713
|
+
const [loading, setLoading] = (0, import_react18.useState)(true);
|
|
714
|
+
const [error, setError] = (0, import_react18.useState)(null);
|
|
715
|
+
const subscriptionRef = (0, import_react18.useRef)(null);
|
|
716
|
+
const paramsKey = params ? JSON.stringify(params) : "";
|
|
717
|
+
(0, import_react18.useEffect)(() => {
|
|
718
|
+
const resolved = resolveResource(client, resource);
|
|
719
|
+
if (!resolved) {
|
|
720
|
+
setError(new Error(`Invalid resource path: ${resource}. Expected format: 'tickets.list'`));
|
|
721
|
+
setLoading(false);
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
const sub = resolved.resource.subscribe(client.realtime, params);
|
|
725
|
+
subscriptionRef.current = sub;
|
|
726
|
+
sub.on("change", (newData) => {
|
|
727
|
+
setData(newData);
|
|
728
|
+
setLoading(false);
|
|
729
|
+
setError(null);
|
|
730
|
+
});
|
|
731
|
+
sub.on("error", (err) => {
|
|
732
|
+
setError(err);
|
|
733
|
+
setLoading(false);
|
|
734
|
+
});
|
|
735
|
+
return () => {
|
|
736
|
+
sub.unsubscribe();
|
|
737
|
+
subscriptionRef.current = null;
|
|
738
|
+
};
|
|
739
|
+
}, [client, resource, paramsKey]);
|
|
740
|
+
const refresh = (0, import_react18.useCallback)(async () => {
|
|
741
|
+
if (subscriptionRef.current) {
|
|
742
|
+
await subscriptionRef.current.refresh();
|
|
743
|
+
}
|
|
744
|
+
}, []);
|
|
745
|
+
return { data, loading, error, refresh };
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// src/dashboard/useCStarMutation.ts
|
|
749
|
+
var import_react19 = require("react");
|
|
750
|
+
function resolveMutation(client, path) {
|
|
751
|
+
const parts = path.split(".");
|
|
752
|
+
if (parts.length < 2) return null;
|
|
753
|
+
const resourceName = parts[0];
|
|
754
|
+
const methodName = parts[1];
|
|
755
|
+
const resource = client[resourceName];
|
|
756
|
+
if (!resource || typeof resource !== "object") return null;
|
|
757
|
+
const method = resource[methodName];
|
|
758
|
+
if (typeof method !== "function") return null;
|
|
759
|
+
if (methodName === "update") {
|
|
760
|
+
return (params) => {
|
|
761
|
+
const p = params;
|
|
762
|
+
const { id, ...rest } = p;
|
|
763
|
+
return method.call(resource, id, rest);
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
if (methodName === "del" || methodName === "delete") {
|
|
767
|
+
return (params) => {
|
|
768
|
+
const p = params;
|
|
769
|
+
return method.call(resource, p.id);
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
return (params) => method.call(resource, params);
|
|
773
|
+
}
|
|
774
|
+
function useCStarMutation(resource) {
|
|
775
|
+
const client = useDashboardClient();
|
|
776
|
+
const [loading, setLoading] = (0, import_react19.useState)(false);
|
|
777
|
+
const [error, setError] = (0, import_react19.useState)(null);
|
|
778
|
+
const mutate = (0, import_react19.useCallback)(
|
|
779
|
+
async (params) => {
|
|
780
|
+
const fn = resolveMutation(client, resource);
|
|
781
|
+
if (!fn) {
|
|
782
|
+
throw new Error(`Invalid mutation path: ${resource}. Expected format: 'tickets.create'`);
|
|
783
|
+
}
|
|
784
|
+
setLoading(true);
|
|
785
|
+
setError(null);
|
|
786
|
+
try {
|
|
787
|
+
const result = await fn(params);
|
|
788
|
+
setLoading(false);
|
|
789
|
+
return result;
|
|
790
|
+
} catch (err) {
|
|
791
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
792
|
+
setError(error2);
|
|
793
|
+
setLoading(false);
|
|
794
|
+
throw error2;
|
|
795
|
+
}
|
|
796
|
+
},
|
|
797
|
+
[client, resource]
|
|
798
|
+
);
|
|
799
|
+
return { mutate, loading, error };
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// src/dashboard/useCStarEvents.ts
|
|
803
|
+
var import_react20 = require("react");
|
|
804
|
+
var MAX_EVENTS = 100;
|
|
805
|
+
function useCStarEvents(types) {
|
|
806
|
+
const client = useDashboardClient();
|
|
807
|
+
const [events, setEvents] = (0, import_react20.useState)([]);
|
|
808
|
+
const [connected, setConnected] = (0, import_react20.useState)(false);
|
|
809
|
+
const typesKey = types ? types.join(",") : "";
|
|
810
|
+
(0, import_react20.useEffect)(() => {
|
|
811
|
+
const realtime = client.realtime;
|
|
812
|
+
const handler = (event) => {
|
|
813
|
+
if (types && types.length > 0) {
|
|
814
|
+
const matches = types.some((pattern) => {
|
|
815
|
+
if (pattern.endsWith(".*")) {
|
|
816
|
+
return event.type.startsWith(pattern.slice(0, -2) + ".");
|
|
817
|
+
}
|
|
818
|
+
return event.type === pattern;
|
|
819
|
+
});
|
|
820
|
+
if (!matches) return;
|
|
821
|
+
}
|
|
822
|
+
setEvents((prev) => [event, ...prev].slice(0, MAX_EVENTS));
|
|
823
|
+
};
|
|
824
|
+
const connHandler = (isConnected) => {
|
|
825
|
+
setConnected(isConnected);
|
|
826
|
+
};
|
|
827
|
+
realtime.onAny(handler);
|
|
828
|
+
realtime.onConnectionChange(connHandler);
|
|
829
|
+
if (!realtime.connected) {
|
|
830
|
+
realtime.connect();
|
|
831
|
+
}
|
|
832
|
+
setConnected(realtime.connected);
|
|
833
|
+
return () => {
|
|
834
|
+
realtime.offAny(handler);
|
|
835
|
+
realtime.offConnectionChange(connHandler);
|
|
836
|
+
};
|
|
837
|
+
}, [client, typesKey]);
|
|
838
|
+
return { events, connected };
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// src/dashboard/useBossBattle.ts
|
|
842
|
+
var import_react21 = require("react");
|
|
843
|
+
function useBossBattle() {
|
|
844
|
+
const client = useDashboardClient();
|
|
845
|
+
const [boss, setBoss] = (0, import_react21.useState)(null);
|
|
846
|
+
const [loading, setLoading] = (0, import_react21.useState)(true);
|
|
847
|
+
const [error, setError] = (0, import_react21.useState)(null);
|
|
848
|
+
const subRef = (0, import_react21.useRef)(null);
|
|
849
|
+
(0, import_react21.useEffect)(() => {
|
|
850
|
+
const sub = client.game.subscribeBoss(client.realtime);
|
|
851
|
+
subRef.current = sub;
|
|
852
|
+
sub.on("change", (data) => {
|
|
853
|
+
setBoss(data.length > 0 ? data[0] : null);
|
|
854
|
+
setLoading(false);
|
|
855
|
+
setError(null);
|
|
856
|
+
});
|
|
857
|
+
sub.on("error", (err) => {
|
|
858
|
+
setError(err);
|
|
859
|
+
setLoading(false);
|
|
860
|
+
});
|
|
861
|
+
return () => {
|
|
862
|
+
sub.unsubscribe();
|
|
863
|
+
subRef.current = null;
|
|
864
|
+
};
|
|
865
|
+
}, [client]);
|
|
866
|
+
const refresh = (0, import_react21.useCallback)(async () => {
|
|
867
|
+
if (subRef.current) await subRef.current.refresh();
|
|
868
|
+
}, []);
|
|
869
|
+
return { boss, active: boss?.active ?? false, loading, error, refresh };
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// src/dashboard/usePlayerStats.ts
|
|
873
|
+
var import_react22 = require("react");
|
|
874
|
+
function usePlayerStats(memberId) {
|
|
875
|
+
const client = useDashboardClient();
|
|
876
|
+
const [player, setPlayer] = (0, import_react22.useState)(null);
|
|
877
|
+
const [loading, setLoading] = (0, import_react22.useState)(true);
|
|
878
|
+
const [error, setError] = (0, import_react22.useState)(null);
|
|
879
|
+
const subRef = (0, import_react22.useRef)(null);
|
|
880
|
+
(0, import_react22.useEffect)(() => {
|
|
881
|
+
const sub = client.game.subscribePlayer(client.realtime, memberId);
|
|
882
|
+
subRef.current = sub;
|
|
883
|
+
sub.on("change", (data) => {
|
|
884
|
+
setPlayer(data.length > 0 ? data[0] : null);
|
|
885
|
+
setLoading(false);
|
|
886
|
+
setError(null);
|
|
887
|
+
});
|
|
888
|
+
sub.on("error", (err) => {
|
|
889
|
+
setError(err);
|
|
890
|
+
setLoading(false);
|
|
891
|
+
});
|
|
892
|
+
return () => {
|
|
893
|
+
sub.unsubscribe();
|
|
894
|
+
subRef.current = null;
|
|
895
|
+
};
|
|
896
|
+
}, [client, memberId]);
|
|
897
|
+
const refresh = (0, import_react22.useCallback)(async () => {
|
|
898
|
+
if (subRef.current) await subRef.current.refresh();
|
|
899
|
+
}, []);
|
|
900
|
+
return { player, loading, error, refresh };
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// src/dashboard/useLeaderboard.ts
|
|
904
|
+
var import_react23 = require("react");
|
|
905
|
+
function useLeaderboard(period) {
|
|
906
|
+
const client = useDashboardClient();
|
|
907
|
+
const [entries, setEntries] = (0, import_react23.useState)([]);
|
|
908
|
+
const [loading, setLoading] = (0, import_react23.useState)(true);
|
|
909
|
+
const [error, setError] = (0, import_react23.useState)(null);
|
|
910
|
+
const subRef = (0, import_react23.useRef)(null);
|
|
911
|
+
(0, import_react23.useEffect)(() => {
|
|
912
|
+
const sub = client.game.subscribeLeaderboard(client.realtime, period ? { period } : void 0);
|
|
913
|
+
subRef.current = sub;
|
|
914
|
+
sub.on("change", (data) => {
|
|
915
|
+
setEntries(data);
|
|
916
|
+
setLoading(false);
|
|
917
|
+
setError(null);
|
|
918
|
+
});
|
|
919
|
+
sub.on("error", (err) => {
|
|
920
|
+
setError(err);
|
|
921
|
+
setLoading(false);
|
|
922
|
+
});
|
|
923
|
+
return () => {
|
|
924
|
+
sub.unsubscribe();
|
|
925
|
+
subRef.current = null;
|
|
926
|
+
};
|
|
927
|
+
}, [client, period]);
|
|
928
|
+
const refresh = (0, import_react23.useCallback)(async () => {
|
|
929
|
+
if (subRef.current) await subRef.current.refresh();
|
|
930
|
+
}, []);
|
|
931
|
+
return { entries, loading, error, refresh };
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// src/dashboard/useGameActivity.ts
|
|
935
|
+
var import_react24 = require("react");
|
|
936
|
+
function useGameActivity() {
|
|
937
|
+
const client = useDashboardClient();
|
|
938
|
+
const [events, setEvents] = (0, import_react24.useState)([]);
|
|
939
|
+
const [loading, setLoading] = (0, import_react24.useState)(true);
|
|
940
|
+
const [error, setError] = (0, import_react24.useState)(null);
|
|
941
|
+
const subRef = (0, import_react24.useRef)(null);
|
|
942
|
+
(0, import_react24.useEffect)(() => {
|
|
943
|
+
const sub = client.game.subscribeActivity(client.realtime);
|
|
944
|
+
subRef.current = sub;
|
|
945
|
+
sub.on("change", (data) => {
|
|
946
|
+
setEvents(data);
|
|
947
|
+
setLoading(false);
|
|
948
|
+
setError(null);
|
|
949
|
+
});
|
|
950
|
+
sub.on("error", (err) => {
|
|
951
|
+
setError(err);
|
|
952
|
+
setLoading(false);
|
|
953
|
+
});
|
|
954
|
+
return () => {
|
|
955
|
+
sub.unsubscribe();
|
|
956
|
+
subRef.current = null;
|
|
957
|
+
};
|
|
958
|
+
}, [client]);
|
|
959
|
+
const refresh = (0, import_react24.useCallback)(async () => {
|
|
960
|
+
if (subRef.current) await subRef.current.refresh();
|
|
961
|
+
}, []);
|
|
962
|
+
return { events, loading, error, refresh };
|
|
963
|
+
}
|
|
667
964
|
// Annotate the CommonJS export names for ESM import in node:
|
|
668
965
|
0 && (module.exports = {
|
|
669
966
|
CStarChatContext,
|
|
670
967
|
CStarChatProvider,
|
|
671
968
|
CStarCommunityContext,
|
|
672
969
|
CStarCommunityProvider,
|
|
970
|
+
CStarDashboardProvider,
|
|
673
971
|
CStarLibraryContext,
|
|
674
972
|
CStarLibraryProvider,
|
|
675
973
|
useArticle,
|
|
676
974
|
useArticleSearch,
|
|
677
975
|
useArticles,
|
|
976
|
+
useBossBattle,
|
|
977
|
+
useCStarEvents,
|
|
978
|
+
useCStarMutation,
|
|
979
|
+
useCStarQuery,
|
|
678
980
|
useCategories,
|
|
679
981
|
useChat,
|
|
680
982
|
useChatClient,
|
|
681
983
|
useCommunityClient,
|
|
682
984
|
useCommunitySearch,
|
|
683
985
|
useConversations,
|
|
986
|
+
useDashboardClient,
|
|
987
|
+
useGameActivity,
|
|
988
|
+
useLeaderboard,
|
|
684
989
|
useLibraryClient,
|
|
685
990
|
useMessages,
|
|
991
|
+
usePlayerStats,
|
|
686
992
|
usePost,
|
|
687
993
|
usePosts,
|
|
688
994
|
useTopics,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
2
|
+
import react__default, { ReactNode } from 'react';
|
|
3
3
|
import { ChatClient, ChatConfig, IdentifyParams, IdentifyResult, Conversation, ConversationCreateParams, WidgetMessage } from '@cstar.help/js/chat';
|
|
4
4
|
export { ChatConfig, Conversation, ConversationCreateParams, ConversationListResponse, IdentifyParams, IdentifyResult, TypingPayload, WidgetMessage } from '@cstar.help/js/chat';
|
|
5
5
|
import { LibraryClient, LibraryConfig, Category, LibraryArticle, LibraryArticleListParams } from '@cstar.help/js/library';
|
|
@@ -7,6 +7,7 @@ export { Category, LibraryArticle, LibraryArticleListParams, LibraryConfig, Libr
|
|
|
7
7
|
import { CommunityClient, CommunityConfig, CommunityTopic, CommunityPost, CommunityPostListParams, CommunityPostDetail, CommunitySearchResult } from '@cstar.help/js/community';
|
|
8
8
|
export { CommunityComment, CommunityConfig, CommunityPost, CommunityPostDetail, CommunityPostListParams, CommunitySearchResult, CommunityTopic } from '@cstar.help/js/community';
|
|
9
9
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
10
|
+
import { CStarClient, RealtimeEvent, Boss, Player, LeaderboardEntry } from '@cstar.help/js';
|
|
10
11
|
|
|
11
12
|
declare const CStarChatContext: react.Context<ChatClient | null>;
|
|
12
13
|
declare const CStarLibraryContext: react.Context<LibraryClient | null>;
|
|
@@ -320,4 +321,160 @@ interface UseCommunitySearchReturn {
|
|
|
320
321
|
*/
|
|
321
322
|
declare function useCommunitySearch(): UseCommunitySearchReturn;
|
|
322
323
|
|
|
323
|
-
|
|
324
|
+
interface CStarDashboardProviderProps {
|
|
325
|
+
/** A pre-configured CStarClient instance (server-side, secret key). */
|
|
326
|
+
client: CStarClient;
|
|
327
|
+
children: react__default.ReactNode;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Provides a CStarClient to dashboard hooks.
|
|
331
|
+
*
|
|
332
|
+
* Unlike `CStarChatProvider` (which uses a publishable key for customer-facing
|
|
333
|
+
* chat), this provider wraps a full admin client with a secret key for building
|
|
334
|
+
* custom dashboards.
|
|
335
|
+
*
|
|
336
|
+
* ```tsx
|
|
337
|
+
* const client = new CStarClient({ apiKey: 'sk_test_...', teamId: '...' });
|
|
338
|
+
*
|
|
339
|
+
* <CStarDashboardProvider client={client}>
|
|
340
|
+
* <TicketList />
|
|
341
|
+
* </CStarDashboardProvider>
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
declare function CStarDashboardProvider({ client, children }: CStarDashboardProviderProps): react_jsx_runtime.JSX.Element;
|
|
345
|
+
/**
|
|
346
|
+
* Access the CStarClient from the nearest CStarDashboardProvider.
|
|
347
|
+
* Throws if used outside a provider.
|
|
348
|
+
*/
|
|
349
|
+
declare function useDashboardClient(): CStarClient;
|
|
350
|
+
|
|
351
|
+
interface UseCStarQueryReturn<T> {
|
|
352
|
+
/** Current data (auto-updated via SSE). Null until first fetch completes. */
|
|
353
|
+
data: T[] | null;
|
|
354
|
+
/** True during initial data fetch. */
|
|
355
|
+
loading: boolean;
|
|
356
|
+
/** Last error, if any. */
|
|
357
|
+
error: Error | null;
|
|
358
|
+
/** Manually refresh data from the server. */
|
|
359
|
+
refresh: () => Promise<void>;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Subscribe to a real-time resource query. Data auto-updates via SSE.
|
|
363
|
+
*
|
|
364
|
+
* ```tsx
|
|
365
|
+
* const { data: tickets, loading } = useCStarQuery('tickets.list', { status: 'open' });
|
|
366
|
+
* ```
|
|
367
|
+
*
|
|
368
|
+
* @param resource - Dot-path resource method (e.g., 'tickets.list', 'customers.list')
|
|
369
|
+
* @param params - Optional filter/pagination params
|
|
370
|
+
*/
|
|
371
|
+
declare function useCStarQuery<T = unknown>(resource: string, params?: Record<string, unknown>): UseCStarQueryReturn<T>;
|
|
372
|
+
|
|
373
|
+
interface UseCStarMutationReturn<TParams, TResult> {
|
|
374
|
+
/** Execute the mutation. */
|
|
375
|
+
mutate: (params: TParams) => Promise<TResult>;
|
|
376
|
+
/** True while the mutation is in flight. */
|
|
377
|
+
loading: boolean;
|
|
378
|
+
/** Last error, if any. */
|
|
379
|
+
error: Error | null;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Create a mutation function for a resource method.
|
|
383
|
+
*
|
|
384
|
+
* ```tsx
|
|
385
|
+
* const { mutate: createTicket, loading } = useCStarMutation('tickets.create');
|
|
386
|
+
* await createTicket({ title: 'New ticket', customerId: 'cus_123' });
|
|
387
|
+
* ```
|
|
388
|
+
*
|
|
389
|
+
* @param resource - Dot-path resource method (e.g., 'tickets.create', 'tickets.update')
|
|
390
|
+
*/
|
|
391
|
+
declare function useCStarMutation<TParams = Record<string, unknown>, TResult = unknown>(resource: string): UseCStarMutationReturn<TParams, TResult>;
|
|
392
|
+
|
|
393
|
+
interface UseCStarEventsReturn {
|
|
394
|
+
/** Rolling buffer of recent events (newest first). */
|
|
395
|
+
events: RealtimeEvent[];
|
|
396
|
+
/** Whether the SSE connection is active. */
|
|
397
|
+
connected: boolean;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Access the raw SSE event stream for custom real-time UIs.
|
|
401
|
+
*
|
|
402
|
+
* ```tsx
|
|
403
|
+
* const { events, connected } = useCStarEvents(['boss.*', 'achievement.*']);
|
|
404
|
+
* ```
|
|
405
|
+
*
|
|
406
|
+
* @param types - Optional event type filter (supports wildcards)
|
|
407
|
+
*/
|
|
408
|
+
declare function useCStarEvents(types?: string[]): UseCStarEventsReturn;
|
|
409
|
+
|
|
410
|
+
interface UseBossBattleReturn {
|
|
411
|
+
/** Current boss state (null if no boss active or loading). */
|
|
412
|
+
boss: Boss | null;
|
|
413
|
+
/** Whether a boss is currently active. */
|
|
414
|
+
active: boolean;
|
|
415
|
+
/** True during initial data fetch. */
|
|
416
|
+
loading: boolean;
|
|
417
|
+
/** Last error, if any. */
|
|
418
|
+
error: Error | null;
|
|
419
|
+
/** Manually refresh boss data. */
|
|
420
|
+
refresh: () => Promise<void>;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Subscribe to live boss battle state.
|
|
424
|
+
*
|
|
425
|
+
* ```tsx
|
|
426
|
+
* const { boss, active, loading, error } = useBossBattle();
|
|
427
|
+
* if (active) {
|
|
428
|
+
* return <BossHPBar hp={boss.health} max={boss.maxHealth} />;
|
|
429
|
+
* }
|
|
430
|
+
* ```
|
|
431
|
+
*/
|
|
432
|
+
declare function useBossBattle(): UseBossBattleReturn;
|
|
433
|
+
|
|
434
|
+
interface UsePlayerStatsReturn {
|
|
435
|
+
player: Player | null;
|
|
436
|
+
loading: boolean;
|
|
437
|
+
error: Error | null;
|
|
438
|
+
refresh: () => Promise<void>;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Subscribe to player stats (XP, level, streaks).
|
|
442
|
+
*
|
|
443
|
+
* ```tsx
|
|
444
|
+
* const { player, loading, error } = usePlayerStats('user_123');
|
|
445
|
+
* ```
|
|
446
|
+
*/
|
|
447
|
+
declare function usePlayerStats(memberId?: string): UsePlayerStatsReturn;
|
|
448
|
+
|
|
449
|
+
interface UseLeaderboardReturn {
|
|
450
|
+
entries: LeaderboardEntry[];
|
|
451
|
+
loading: boolean;
|
|
452
|
+
error: Error | null;
|
|
453
|
+
refresh: () => Promise<void>;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Subscribe to team leaderboard rankings.
|
|
457
|
+
*
|
|
458
|
+
* ```tsx
|
|
459
|
+
* const { entries, loading, error } = useLeaderboard('weekly');
|
|
460
|
+
* ```
|
|
461
|
+
*/
|
|
462
|
+
declare function useLeaderboard(period?: 'daily' | 'weekly' | 'allTime'): UseLeaderboardReturn;
|
|
463
|
+
|
|
464
|
+
interface UseGameActivityReturn {
|
|
465
|
+
/** Rolling feed of recent game events. */
|
|
466
|
+
events: Record<string, unknown>[];
|
|
467
|
+
loading: boolean;
|
|
468
|
+
error: Error | null;
|
|
469
|
+
refresh: () => Promise<void>;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Subscribe to the team game activity feed (achievements, boss defeats, level ups).
|
|
473
|
+
*
|
|
474
|
+
* ```tsx
|
|
475
|
+
* const { events, loading } = useGameActivity();
|
|
476
|
+
* ```
|
|
477
|
+
*/
|
|
478
|
+
declare function useGameActivity(): UseGameActivityReturn;
|
|
479
|
+
|
|
480
|
+
export { CStarChatContext, CStarChatProvider, type CStarChatProviderProps, CStarCommunityContext, CStarCommunityProvider, type CStarCommunityProviderProps, CStarDashboardProvider, type CStarDashboardProviderProps, CStarLibraryContext, CStarLibraryProvider, type CStarLibraryProviderProps, type TypingAgent, type UseArticleReturn, type UseArticleSearchReturn, type UseArticlesReturn, type UseBossBattleReturn, type UseCStarEventsReturn, type UseCStarMutationReturn, type UseCStarQueryReturn, type UseCategoriesReturn, type UseChatReturn, type UseCommunitySearchReturn, type UseConversationsReturn, type UseGameActivityReturn, type UseLeaderboardReturn, type UseMessagesReturn, type UsePlayerStatsReturn, type UsePostReturn, type UsePostsReturn, type UseTopicsReturn, type UseTypingReturn, useArticle, useArticleSearch, useArticles, useBossBattle, useCStarEvents, useCStarMutation, useCStarQuery, useCategories, useChat, useChatClient, useCommunityClient, useCommunitySearch, useConversations, useDashboardClient, useGameActivity, useLeaderboard, useLibraryClient, useMessages, usePlayerStats, usePost, usePosts, useTopics, useTyping };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
2
|
+
import react__default, { ReactNode } from 'react';
|
|
3
3
|
import { ChatClient, ChatConfig, IdentifyParams, IdentifyResult, Conversation, ConversationCreateParams, WidgetMessage } from '@cstar.help/js/chat';
|
|
4
4
|
export { ChatConfig, Conversation, ConversationCreateParams, ConversationListResponse, IdentifyParams, IdentifyResult, TypingPayload, WidgetMessage } from '@cstar.help/js/chat';
|
|
5
5
|
import { LibraryClient, LibraryConfig, Category, LibraryArticle, LibraryArticleListParams } from '@cstar.help/js/library';
|
|
@@ -7,6 +7,7 @@ export { Category, LibraryArticle, LibraryArticleListParams, LibraryConfig, Libr
|
|
|
7
7
|
import { CommunityClient, CommunityConfig, CommunityTopic, CommunityPost, CommunityPostListParams, CommunityPostDetail, CommunitySearchResult } from '@cstar.help/js/community';
|
|
8
8
|
export { CommunityComment, CommunityConfig, CommunityPost, CommunityPostDetail, CommunityPostListParams, CommunitySearchResult, CommunityTopic } from '@cstar.help/js/community';
|
|
9
9
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
10
|
+
import { CStarClient, RealtimeEvent, Boss, Player, LeaderboardEntry } from '@cstar.help/js';
|
|
10
11
|
|
|
11
12
|
declare const CStarChatContext: react.Context<ChatClient | null>;
|
|
12
13
|
declare const CStarLibraryContext: react.Context<LibraryClient | null>;
|
|
@@ -320,4 +321,160 @@ interface UseCommunitySearchReturn {
|
|
|
320
321
|
*/
|
|
321
322
|
declare function useCommunitySearch(): UseCommunitySearchReturn;
|
|
322
323
|
|
|
323
|
-
|
|
324
|
+
interface CStarDashboardProviderProps {
|
|
325
|
+
/** A pre-configured CStarClient instance (server-side, secret key). */
|
|
326
|
+
client: CStarClient;
|
|
327
|
+
children: react__default.ReactNode;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Provides a CStarClient to dashboard hooks.
|
|
331
|
+
*
|
|
332
|
+
* Unlike `CStarChatProvider` (which uses a publishable key for customer-facing
|
|
333
|
+
* chat), this provider wraps a full admin client with a secret key for building
|
|
334
|
+
* custom dashboards.
|
|
335
|
+
*
|
|
336
|
+
* ```tsx
|
|
337
|
+
* const client = new CStarClient({ apiKey: 'sk_test_...', teamId: '...' });
|
|
338
|
+
*
|
|
339
|
+
* <CStarDashboardProvider client={client}>
|
|
340
|
+
* <TicketList />
|
|
341
|
+
* </CStarDashboardProvider>
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
declare function CStarDashboardProvider({ client, children }: CStarDashboardProviderProps): react_jsx_runtime.JSX.Element;
|
|
345
|
+
/**
|
|
346
|
+
* Access the CStarClient from the nearest CStarDashboardProvider.
|
|
347
|
+
* Throws if used outside a provider.
|
|
348
|
+
*/
|
|
349
|
+
declare function useDashboardClient(): CStarClient;
|
|
350
|
+
|
|
351
|
+
interface UseCStarQueryReturn<T> {
|
|
352
|
+
/** Current data (auto-updated via SSE). Null until first fetch completes. */
|
|
353
|
+
data: T[] | null;
|
|
354
|
+
/** True during initial data fetch. */
|
|
355
|
+
loading: boolean;
|
|
356
|
+
/** Last error, if any. */
|
|
357
|
+
error: Error | null;
|
|
358
|
+
/** Manually refresh data from the server. */
|
|
359
|
+
refresh: () => Promise<void>;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Subscribe to a real-time resource query. Data auto-updates via SSE.
|
|
363
|
+
*
|
|
364
|
+
* ```tsx
|
|
365
|
+
* const { data: tickets, loading } = useCStarQuery('tickets.list', { status: 'open' });
|
|
366
|
+
* ```
|
|
367
|
+
*
|
|
368
|
+
* @param resource - Dot-path resource method (e.g., 'tickets.list', 'customers.list')
|
|
369
|
+
* @param params - Optional filter/pagination params
|
|
370
|
+
*/
|
|
371
|
+
declare function useCStarQuery<T = unknown>(resource: string, params?: Record<string, unknown>): UseCStarQueryReturn<T>;
|
|
372
|
+
|
|
373
|
+
interface UseCStarMutationReturn<TParams, TResult> {
|
|
374
|
+
/** Execute the mutation. */
|
|
375
|
+
mutate: (params: TParams) => Promise<TResult>;
|
|
376
|
+
/** True while the mutation is in flight. */
|
|
377
|
+
loading: boolean;
|
|
378
|
+
/** Last error, if any. */
|
|
379
|
+
error: Error | null;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Create a mutation function for a resource method.
|
|
383
|
+
*
|
|
384
|
+
* ```tsx
|
|
385
|
+
* const { mutate: createTicket, loading } = useCStarMutation('tickets.create');
|
|
386
|
+
* await createTicket({ title: 'New ticket', customerId: 'cus_123' });
|
|
387
|
+
* ```
|
|
388
|
+
*
|
|
389
|
+
* @param resource - Dot-path resource method (e.g., 'tickets.create', 'tickets.update')
|
|
390
|
+
*/
|
|
391
|
+
declare function useCStarMutation<TParams = Record<string, unknown>, TResult = unknown>(resource: string): UseCStarMutationReturn<TParams, TResult>;
|
|
392
|
+
|
|
393
|
+
interface UseCStarEventsReturn {
|
|
394
|
+
/** Rolling buffer of recent events (newest first). */
|
|
395
|
+
events: RealtimeEvent[];
|
|
396
|
+
/** Whether the SSE connection is active. */
|
|
397
|
+
connected: boolean;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Access the raw SSE event stream for custom real-time UIs.
|
|
401
|
+
*
|
|
402
|
+
* ```tsx
|
|
403
|
+
* const { events, connected } = useCStarEvents(['boss.*', 'achievement.*']);
|
|
404
|
+
* ```
|
|
405
|
+
*
|
|
406
|
+
* @param types - Optional event type filter (supports wildcards)
|
|
407
|
+
*/
|
|
408
|
+
declare function useCStarEvents(types?: string[]): UseCStarEventsReturn;
|
|
409
|
+
|
|
410
|
+
interface UseBossBattleReturn {
|
|
411
|
+
/** Current boss state (null if no boss active or loading). */
|
|
412
|
+
boss: Boss | null;
|
|
413
|
+
/** Whether a boss is currently active. */
|
|
414
|
+
active: boolean;
|
|
415
|
+
/** True during initial data fetch. */
|
|
416
|
+
loading: boolean;
|
|
417
|
+
/** Last error, if any. */
|
|
418
|
+
error: Error | null;
|
|
419
|
+
/** Manually refresh boss data. */
|
|
420
|
+
refresh: () => Promise<void>;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Subscribe to live boss battle state.
|
|
424
|
+
*
|
|
425
|
+
* ```tsx
|
|
426
|
+
* const { boss, active, loading, error } = useBossBattle();
|
|
427
|
+
* if (active) {
|
|
428
|
+
* return <BossHPBar hp={boss.health} max={boss.maxHealth} />;
|
|
429
|
+
* }
|
|
430
|
+
* ```
|
|
431
|
+
*/
|
|
432
|
+
declare function useBossBattle(): UseBossBattleReturn;
|
|
433
|
+
|
|
434
|
+
interface UsePlayerStatsReturn {
|
|
435
|
+
player: Player | null;
|
|
436
|
+
loading: boolean;
|
|
437
|
+
error: Error | null;
|
|
438
|
+
refresh: () => Promise<void>;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Subscribe to player stats (XP, level, streaks).
|
|
442
|
+
*
|
|
443
|
+
* ```tsx
|
|
444
|
+
* const { player, loading, error } = usePlayerStats('user_123');
|
|
445
|
+
* ```
|
|
446
|
+
*/
|
|
447
|
+
declare function usePlayerStats(memberId?: string): UsePlayerStatsReturn;
|
|
448
|
+
|
|
449
|
+
interface UseLeaderboardReturn {
|
|
450
|
+
entries: LeaderboardEntry[];
|
|
451
|
+
loading: boolean;
|
|
452
|
+
error: Error | null;
|
|
453
|
+
refresh: () => Promise<void>;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Subscribe to team leaderboard rankings.
|
|
457
|
+
*
|
|
458
|
+
* ```tsx
|
|
459
|
+
* const { entries, loading, error } = useLeaderboard('weekly');
|
|
460
|
+
* ```
|
|
461
|
+
*/
|
|
462
|
+
declare function useLeaderboard(period?: 'daily' | 'weekly' | 'allTime'): UseLeaderboardReturn;
|
|
463
|
+
|
|
464
|
+
interface UseGameActivityReturn {
|
|
465
|
+
/** Rolling feed of recent game events. */
|
|
466
|
+
events: Record<string, unknown>[];
|
|
467
|
+
loading: boolean;
|
|
468
|
+
error: Error | null;
|
|
469
|
+
refresh: () => Promise<void>;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Subscribe to the team game activity feed (achievements, boss defeats, level ups).
|
|
473
|
+
*
|
|
474
|
+
* ```tsx
|
|
475
|
+
* const { events, loading } = useGameActivity();
|
|
476
|
+
* ```
|
|
477
|
+
*/
|
|
478
|
+
declare function useGameActivity(): UseGameActivityReturn;
|
|
479
|
+
|
|
480
|
+
export { CStarChatContext, CStarChatProvider, type CStarChatProviderProps, CStarCommunityContext, CStarCommunityProvider, type CStarCommunityProviderProps, CStarDashboardProvider, type CStarDashboardProviderProps, CStarLibraryContext, CStarLibraryProvider, type CStarLibraryProviderProps, type TypingAgent, type UseArticleReturn, type UseArticleSearchReturn, type UseArticlesReturn, type UseBossBattleReturn, type UseCStarEventsReturn, type UseCStarMutationReturn, type UseCStarQueryReturn, type UseCategoriesReturn, type UseChatReturn, type UseCommunitySearchReturn, type UseConversationsReturn, type UseGameActivityReturn, type UseLeaderboardReturn, type UseMessagesReturn, type UsePlayerStatsReturn, type UsePostReturn, type UsePostsReturn, type UseTopicsReturn, type UseTypingReturn, useArticle, useArticleSearch, useArticles, useBossBattle, useCStarEvents, useCStarMutation, useCStarQuery, useCategories, useChat, useChatClient, useCommunityClient, useCommunitySearch, useConversations, useDashboardClient, useGameActivity, useLeaderboard, useLibraryClient, useMessages, usePlayerStats, usePost, usePosts, useTopics, useTyping };
|
package/dist/index.js
CHANGED
|
@@ -618,24 +618,321 @@ function useCommunitySearch() {
|
|
|
618
618
|
);
|
|
619
619
|
return { results, isLoading, error, search };
|
|
620
620
|
}
|
|
621
|
+
|
|
622
|
+
// src/dashboard/CStarDashboardProvider.tsx
|
|
623
|
+
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect13, useRef as useRef15 } from "react";
|
|
624
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
625
|
+
var CStarDashboardContext = createContext2(null);
|
|
626
|
+
function CStarDashboardProvider({ client, children }) {
|
|
627
|
+
const contextValue = useRef15({ client }).current;
|
|
628
|
+
useEffect13(() => {
|
|
629
|
+
return () => {
|
|
630
|
+
client.realtime.disconnect();
|
|
631
|
+
};
|
|
632
|
+
}, [client]);
|
|
633
|
+
return /* @__PURE__ */ jsx4(CStarDashboardContext.Provider, { value: contextValue, children });
|
|
634
|
+
}
|
|
635
|
+
function useDashboardClient() {
|
|
636
|
+
const ctx = useContext2(CStarDashboardContext);
|
|
637
|
+
if (!ctx) {
|
|
638
|
+
throw new Error("useDashboardClient must be used within a <CStarDashboardProvider>");
|
|
639
|
+
}
|
|
640
|
+
return ctx.client;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// src/dashboard/useCStarQuery.ts
|
|
644
|
+
import { useState as useState13, useEffect as useEffect14, useRef as useRef16, useCallback as useCallback12 } from "react";
|
|
645
|
+
function resolveResource(client, path) {
|
|
646
|
+
const parts = path.split(".");
|
|
647
|
+
if (parts.length < 2 || parts[1] !== "list") return null;
|
|
648
|
+
const resourceName = parts[0];
|
|
649
|
+
const resource = client[resourceName];
|
|
650
|
+
if (!resource || typeof resource !== "object") return null;
|
|
651
|
+
const typed = resource;
|
|
652
|
+
if (typeof typed.list !== "function" || typeof typed.subscribe !== "function") return null;
|
|
653
|
+
return { resource, basePath: `/${resourceName}` };
|
|
654
|
+
}
|
|
655
|
+
function useCStarQuery(resource, params) {
|
|
656
|
+
const client = useDashboardClient();
|
|
657
|
+
const [data, setData] = useState13(null);
|
|
658
|
+
const [loading, setLoading] = useState13(true);
|
|
659
|
+
const [error, setError] = useState13(null);
|
|
660
|
+
const subscriptionRef = useRef16(null);
|
|
661
|
+
const paramsKey = params ? JSON.stringify(params) : "";
|
|
662
|
+
useEffect14(() => {
|
|
663
|
+
const resolved = resolveResource(client, resource);
|
|
664
|
+
if (!resolved) {
|
|
665
|
+
setError(new Error(`Invalid resource path: ${resource}. Expected format: 'tickets.list'`));
|
|
666
|
+
setLoading(false);
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
const sub = resolved.resource.subscribe(client.realtime, params);
|
|
670
|
+
subscriptionRef.current = sub;
|
|
671
|
+
sub.on("change", (newData) => {
|
|
672
|
+
setData(newData);
|
|
673
|
+
setLoading(false);
|
|
674
|
+
setError(null);
|
|
675
|
+
});
|
|
676
|
+
sub.on("error", (err) => {
|
|
677
|
+
setError(err);
|
|
678
|
+
setLoading(false);
|
|
679
|
+
});
|
|
680
|
+
return () => {
|
|
681
|
+
sub.unsubscribe();
|
|
682
|
+
subscriptionRef.current = null;
|
|
683
|
+
};
|
|
684
|
+
}, [client, resource, paramsKey]);
|
|
685
|
+
const refresh = useCallback12(async () => {
|
|
686
|
+
if (subscriptionRef.current) {
|
|
687
|
+
await subscriptionRef.current.refresh();
|
|
688
|
+
}
|
|
689
|
+
}, []);
|
|
690
|
+
return { data, loading, error, refresh };
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// src/dashboard/useCStarMutation.ts
|
|
694
|
+
import { useState as useState14, useCallback as useCallback13 } from "react";
|
|
695
|
+
function resolveMutation(client, path) {
|
|
696
|
+
const parts = path.split(".");
|
|
697
|
+
if (parts.length < 2) return null;
|
|
698
|
+
const resourceName = parts[0];
|
|
699
|
+
const methodName = parts[1];
|
|
700
|
+
const resource = client[resourceName];
|
|
701
|
+
if (!resource || typeof resource !== "object") return null;
|
|
702
|
+
const method = resource[methodName];
|
|
703
|
+
if (typeof method !== "function") return null;
|
|
704
|
+
if (methodName === "update") {
|
|
705
|
+
return (params) => {
|
|
706
|
+
const p = params;
|
|
707
|
+
const { id, ...rest } = p;
|
|
708
|
+
return method.call(resource, id, rest);
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
if (methodName === "del" || methodName === "delete") {
|
|
712
|
+
return (params) => {
|
|
713
|
+
const p = params;
|
|
714
|
+
return method.call(resource, p.id);
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
return (params) => method.call(resource, params);
|
|
718
|
+
}
|
|
719
|
+
function useCStarMutation(resource) {
|
|
720
|
+
const client = useDashboardClient();
|
|
721
|
+
const [loading, setLoading] = useState14(false);
|
|
722
|
+
const [error, setError] = useState14(null);
|
|
723
|
+
const mutate = useCallback13(
|
|
724
|
+
async (params) => {
|
|
725
|
+
const fn = resolveMutation(client, resource);
|
|
726
|
+
if (!fn) {
|
|
727
|
+
throw new Error(`Invalid mutation path: ${resource}. Expected format: 'tickets.create'`);
|
|
728
|
+
}
|
|
729
|
+
setLoading(true);
|
|
730
|
+
setError(null);
|
|
731
|
+
try {
|
|
732
|
+
const result = await fn(params);
|
|
733
|
+
setLoading(false);
|
|
734
|
+
return result;
|
|
735
|
+
} catch (err) {
|
|
736
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
737
|
+
setError(error2);
|
|
738
|
+
setLoading(false);
|
|
739
|
+
throw error2;
|
|
740
|
+
}
|
|
741
|
+
},
|
|
742
|
+
[client, resource]
|
|
743
|
+
);
|
|
744
|
+
return { mutate, loading, error };
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// src/dashboard/useCStarEvents.ts
|
|
748
|
+
import { useState as useState15, useEffect as useEffect15 } from "react";
|
|
749
|
+
var MAX_EVENTS = 100;
|
|
750
|
+
function useCStarEvents(types) {
|
|
751
|
+
const client = useDashboardClient();
|
|
752
|
+
const [events, setEvents] = useState15([]);
|
|
753
|
+
const [connected, setConnected] = useState15(false);
|
|
754
|
+
const typesKey = types ? types.join(",") : "";
|
|
755
|
+
useEffect15(() => {
|
|
756
|
+
const realtime = client.realtime;
|
|
757
|
+
const handler = (event) => {
|
|
758
|
+
if (types && types.length > 0) {
|
|
759
|
+
const matches = types.some((pattern) => {
|
|
760
|
+
if (pattern.endsWith(".*")) {
|
|
761
|
+
return event.type.startsWith(pattern.slice(0, -2) + ".");
|
|
762
|
+
}
|
|
763
|
+
return event.type === pattern;
|
|
764
|
+
});
|
|
765
|
+
if (!matches) return;
|
|
766
|
+
}
|
|
767
|
+
setEvents((prev) => [event, ...prev].slice(0, MAX_EVENTS));
|
|
768
|
+
};
|
|
769
|
+
const connHandler = (isConnected) => {
|
|
770
|
+
setConnected(isConnected);
|
|
771
|
+
};
|
|
772
|
+
realtime.onAny(handler);
|
|
773
|
+
realtime.onConnectionChange(connHandler);
|
|
774
|
+
if (!realtime.connected) {
|
|
775
|
+
realtime.connect();
|
|
776
|
+
}
|
|
777
|
+
setConnected(realtime.connected);
|
|
778
|
+
return () => {
|
|
779
|
+
realtime.offAny(handler);
|
|
780
|
+
realtime.offConnectionChange(connHandler);
|
|
781
|
+
};
|
|
782
|
+
}, [client, typesKey]);
|
|
783
|
+
return { events, connected };
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// src/dashboard/useBossBattle.ts
|
|
787
|
+
import { useState as useState16, useEffect as useEffect16, useRef as useRef17, useCallback as useCallback14 } from "react";
|
|
788
|
+
function useBossBattle() {
|
|
789
|
+
const client = useDashboardClient();
|
|
790
|
+
const [boss, setBoss] = useState16(null);
|
|
791
|
+
const [loading, setLoading] = useState16(true);
|
|
792
|
+
const [error, setError] = useState16(null);
|
|
793
|
+
const subRef = useRef17(null);
|
|
794
|
+
useEffect16(() => {
|
|
795
|
+
const sub = client.game.subscribeBoss(client.realtime);
|
|
796
|
+
subRef.current = sub;
|
|
797
|
+
sub.on("change", (data) => {
|
|
798
|
+
setBoss(data.length > 0 ? data[0] : null);
|
|
799
|
+
setLoading(false);
|
|
800
|
+
setError(null);
|
|
801
|
+
});
|
|
802
|
+
sub.on("error", (err) => {
|
|
803
|
+
setError(err);
|
|
804
|
+
setLoading(false);
|
|
805
|
+
});
|
|
806
|
+
return () => {
|
|
807
|
+
sub.unsubscribe();
|
|
808
|
+
subRef.current = null;
|
|
809
|
+
};
|
|
810
|
+
}, [client]);
|
|
811
|
+
const refresh = useCallback14(async () => {
|
|
812
|
+
if (subRef.current) await subRef.current.refresh();
|
|
813
|
+
}, []);
|
|
814
|
+
return { boss, active: boss?.active ?? false, loading, error, refresh };
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// src/dashboard/usePlayerStats.ts
|
|
818
|
+
import { useState as useState17, useEffect as useEffect17, useRef as useRef18, useCallback as useCallback15 } from "react";
|
|
819
|
+
function usePlayerStats(memberId) {
|
|
820
|
+
const client = useDashboardClient();
|
|
821
|
+
const [player, setPlayer] = useState17(null);
|
|
822
|
+
const [loading, setLoading] = useState17(true);
|
|
823
|
+
const [error, setError] = useState17(null);
|
|
824
|
+
const subRef = useRef18(null);
|
|
825
|
+
useEffect17(() => {
|
|
826
|
+
const sub = client.game.subscribePlayer(client.realtime, memberId);
|
|
827
|
+
subRef.current = sub;
|
|
828
|
+
sub.on("change", (data) => {
|
|
829
|
+
setPlayer(data.length > 0 ? data[0] : null);
|
|
830
|
+
setLoading(false);
|
|
831
|
+
setError(null);
|
|
832
|
+
});
|
|
833
|
+
sub.on("error", (err) => {
|
|
834
|
+
setError(err);
|
|
835
|
+
setLoading(false);
|
|
836
|
+
});
|
|
837
|
+
return () => {
|
|
838
|
+
sub.unsubscribe();
|
|
839
|
+
subRef.current = null;
|
|
840
|
+
};
|
|
841
|
+
}, [client, memberId]);
|
|
842
|
+
const refresh = useCallback15(async () => {
|
|
843
|
+
if (subRef.current) await subRef.current.refresh();
|
|
844
|
+
}, []);
|
|
845
|
+
return { player, loading, error, refresh };
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// src/dashboard/useLeaderboard.ts
|
|
849
|
+
import { useState as useState18, useEffect as useEffect18, useRef as useRef19, useCallback as useCallback16 } from "react";
|
|
850
|
+
function useLeaderboard(period) {
|
|
851
|
+
const client = useDashboardClient();
|
|
852
|
+
const [entries, setEntries] = useState18([]);
|
|
853
|
+
const [loading, setLoading] = useState18(true);
|
|
854
|
+
const [error, setError] = useState18(null);
|
|
855
|
+
const subRef = useRef19(null);
|
|
856
|
+
useEffect18(() => {
|
|
857
|
+
const sub = client.game.subscribeLeaderboard(client.realtime, period ? { period } : void 0);
|
|
858
|
+
subRef.current = sub;
|
|
859
|
+
sub.on("change", (data) => {
|
|
860
|
+
setEntries(data);
|
|
861
|
+
setLoading(false);
|
|
862
|
+
setError(null);
|
|
863
|
+
});
|
|
864
|
+
sub.on("error", (err) => {
|
|
865
|
+
setError(err);
|
|
866
|
+
setLoading(false);
|
|
867
|
+
});
|
|
868
|
+
return () => {
|
|
869
|
+
sub.unsubscribe();
|
|
870
|
+
subRef.current = null;
|
|
871
|
+
};
|
|
872
|
+
}, [client, period]);
|
|
873
|
+
const refresh = useCallback16(async () => {
|
|
874
|
+
if (subRef.current) await subRef.current.refresh();
|
|
875
|
+
}, []);
|
|
876
|
+
return { entries, loading, error, refresh };
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// src/dashboard/useGameActivity.ts
|
|
880
|
+
import { useState as useState19, useEffect as useEffect19, useRef as useRef20, useCallback as useCallback17 } from "react";
|
|
881
|
+
function useGameActivity() {
|
|
882
|
+
const client = useDashboardClient();
|
|
883
|
+
const [events, setEvents] = useState19([]);
|
|
884
|
+
const [loading, setLoading] = useState19(true);
|
|
885
|
+
const [error, setError] = useState19(null);
|
|
886
|
+
const subRef = useRef20(null);
|
|
887
|
+
useEffect19(() => {
|
|
888
|
+
const sub = client.game.subscribeActivity(client.realtime);
|
|
889
|
+
subRef.current = sub;
|
|
890
|
+
sub.on("change", (data) => {
|
|
891
|
+
setEvents(data);
|
|
892
|
+
setLoading(false);
|
|
893
|
+
setError(null);
|
|
894
|
+
});
|
|
895
|
+
sub.on("error", (err) => {
|
|
896
|
+
setError(err);
|
|
897
|
+
setLoading(false);
|
|
898
|
+
});
|
|
899
|
+
return () => {
|
|
900
|
+
sub.unsubscribe();
|
|
901
|
+
subRef.current = null;
|
|
902
|
+
};
|
|
903
|
+
}, [client]);
|
|
904
|
+
const refresh = useCallback17(async () => {
|
|
905
|
+
if (subRef.current) await subRef.current.refresh();
|
|
906
|
+
}, []);
|
|
907
|
+
return { events, loading, error, refresh };
|
|
908
|
+
}
|
|
621
909
|
export {
|
|
622
910
|
CStarChatContext,
|
|
623
911
|
CStarChatProvider,
|
|
624
912
|
CStarCommunityContext,
|
|
625
913
|
CStarCommunityProvider,
|
|
914
|
+
CStarDashboardProvider,
|
|
626
915
|
CStarLibraryContext,
|
|
627
916
|
CStarLibraryProvider,
|
|
628
917
|
useArticle,
|
|
629
918
|
useArticleSearch,
|
|
630
919
|
useArticles,
|
|
920
|
+
useBossBattle,
|
|
921
|
+
useCStarEvents,
|
|
922
|
+
useCStarMutation,
|
|
923
|
+
useCStarQuery,
|
|
631
924
|
useCategories,
|
|
632
925
|
useChat,
|
|
633
926
|
useChatClient,
|
|
634
927
|
useCommunityClient,
|
|
635
928
|
useCommunitySearch,
|
|
636
929
|
useConversations,
|
|
930
|
+
useDashboardClient,
|
|
931
|
+
useGameActivity,
|
|
932
|
+
useLeaderboard,
|
|
637
933
|
useLibraryClient,
|
|
638
934
|
useMessages,
|
|
935
|
+
usePlayerStats,
|
|
639
936
|
usePost,
|
|
640
937
|
usePosts,
|
|
641
938
|
useTopics,
|