@stigmer/react 0.0.101 → 0.1.1

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 (262) hide show
  1. package/agent/AgentPicker.js +1 -1
  2. package/agent/AgentPicker.js.map +1 -1
  3. package/agent/__tests__/useDefaultAgent.test.d.ts +2 -0
  4. package/agent/__tests__/useDefaultAgent.test.d.ts.map +1 -0
  5. package/agent/__tests__/useDefaultAgent.test.js +252 -0
  6. package/agent/__tests__/useDefaultAgent.test.js.map +1 -0
  7. package/agent/useAgent.d.ts +2 -0
  8. package/agent/useAgent.d.ts.map +1 -1
  9. package/agent/useAgent.js +14 -37
  10. package/agent/useAgent.js.map +1 -1
  11. package/agent/useAgentCount.d.ts +1 -1
  12. package/agent/useAgentCount.d.ts.map +1 -1
  13. package/agent/useAgentList.d.ts +2 -2
  14. package/agent/useAgentList.d.ts.map +1 -1
  15. package/agent/useDefaultAgent.d.ts +6 -2
  16. package/agent/useDefaultAgent.d.ts.map +1 -1
  17. package/agent/useDefaultAgent.js +51 -31
  18. package/agent/useDefaultAgent.js.map +1 -1
  19. package/agent-instance/useAgentInstance.d.ts +2 -0
  20. package/agent-instance/useAgentInstance.d.ts.map +1 -1
  21. package/agent-instance/useAgentInstance.js +6 -33
  22. package/agent-instance/useAgentInstance.js.map +1 -1
  23. package/agent-instance/useAgentInstanceList.d.ts +2 -0
  24. package/agent-instance/useAgentInstanceList.d.ts.map +1 -1
  25. package/agent-instance/useAgentInstanceList.js +22 -40
  26. package/agent-instance/useAgentInstanceList.js.map +1 -1
  27. package/api-key/useApiKeyList.d.ts +2 -0
  28. package/api-key/useApiKeyList.d.ts.map +1 -1
  29. package/api-key/useApiKeyList.js +3 -27
  30. package/api-key/useApiKeyList.js.map +1 -1
  31. package/composer/ComposerToolbar.d.ts +1 -5
  32. package/composer/ComposerToolbar.d.ts.map +1 -1
  33. package/composer/ComposerToolbar.js +3 -4
  34. package/composer/ComposerToolbar.js.map +1 -1
  35. package/composer/ContextChip.d.ts +1 -1
  36. package/composer/ContextChip.d.ts.map +1 -1
  37. package/composer/ContextChip.js +1 -0
  38. package/composer/ContextChip.js.map +1 -1
  39. package/composer/SessionComposer.d.ts.map +1 -1
  40. package/composer/SessionComposer.js +77 -4
  41. package/composer/SessionComposer.js.map +1 -1
  42. package/composer/icons.d.ts +1 -0
  43. package/composer/icons.d.ts.map +1 -1
  44. package/composer/icons.js +3 -0
  45. package/composer/icons.js.map +1 -1
  46. package/environment/useEnvironment.d.ts +2 -0
  47. package/environment/useEnvironment.d.ts.map +1 -1
  48. package/environment/useEnvironment.js +6 -33
  49. package/environment/useEnvironment.js.map +1 -1
  50. package/environment/useEnvironmentList.d.ts +2 -0
  51. package/environment/useEnvironmentList.d.ts.map +1 -1
  52. package/environment/useEnvironmentList.js +23 -53
  53. package/environment/useEnvironmentList.js.map +1 -1
  54. package/execution/ArtifactPreviewModal.js +1 -1
  55. package/execution/ArtifactPreviewModal.js.map +1 -1
  56. package/execution/useArtifactContent.d.ts +4 -2
  57. package/execution/useArtifactContent.d.ts.map +1 -1
  58. package/execution/useArtifactContent.js +23 -45
  59. package/execution/useArtifactContent.js.map +1 -1
  60. package/iam-policy/usePrincipalsCount.d.ts +2 -0
  61. package/iam-policy/usePrincipalsCount.d.ts.map +1 -1
  62. package/iam-policy/usePrincipalsCount.js +7 -46
  63. package/iam-policy/usePrincipalsCount.js.map +1 -1
  64. package/iam-policy/useResourceAccess.d.ts +2 -0
  65. package/iam-policy/useResourceAccess.d.ts.map +1 -1
  66. package/iam-policy/useResourceAccess.js +12 -47
  67. package/iam-policy/useResourceAccess.js.map +1 -1
  68. package/identity-provider/useIdentityProvider.d.ts +2 -0
  69. package/identity-provider/useIdentityProvider.d.ts.map +1 -1
  70. package/identity-provider/useIdentityProvider.js +3 -33
  71. package/identity-provider/useIdentityProvider.js.map +1 -1
  72. package/identity-provider/useIdentityProviderList.d.ts +2 -0
  73. package/identity-provider/useIdentityProviderList.d.ts.map +1 -1
  74. package/identity-provider/useIdentityProviderList.js +7 -33
  75. package/identity-provider/useIdentityProviderList.js.map +1 -1
  76. package/index.d.ts +2 -2
  77. package/index.d.ts.map +1 -1
  78. package/index.js +1 -1
  79. package/index.js.map +1 -1
  80. package/internal/__tests__/useFetch.test.d.ts +2 -0
  81. package/internal/__tests__/useFetch.test.d.ts.map +1 -0
  82. package/internal/__tests__/useFetch.test.js +95 -0
  83. package/internal/__tests__/useFetch.test.js.map +1 -0
  84. package/internal/useFetch.d.ts +51 -0
  85. package/internal/useFetch.d.ts.map +1 -0
  86. package/internal/useFetch.js +75 -0
  87. package/internal/useFetch.js.map +1 -0
  88. package/invitation/useInvitationPreview.d.ts +2 -0
  89. package/invitation/useInvitationPreview.d.ts.map +1 -1
  90. package/invitation/useInvitationPreview.js +5 -35
  91. package/invitation/useInvitationPreview.js.map +1 -1
  92. package/invitation/useOrgInvitations.d.ts +2 -0
  93. package/invitation/useOrgInvitations.d.ts.map +1 -1
  94. package/invitation/useOrgInvitations.js +6 -34
  95. package/invitation/useOrgInvitations.js.map +1 -1
  96. package/library/ResourceListView.d.ts +2 -2
  97. package/library/ResourceListView.d.ts.map +1 -1
  98. package/library/ResourceListView.js +1 -1
  99. package/library/ResourceListView.js.map +1 -1
  100. package/library/useDetectSkillPackage.d.ts +1 -1
  101. package/library/useDetectSkillPackage.d.ts.map +1 -1
  102. package/mcp-server/McpServerPicker.js +1 -1
  103. package/mcp-server/McpServerPicker.js.map +1 -1
  104. package/mcp-server/useMcpServer.d.ts +2 -0
  105. package/mcp-server/useMcpServer.d.ts.map +1 -1
  106. package/mcp-server/useMcpServer.js +13 -37
  107. package/mcp-server/useMcpServer.js.map +1 -1
  108. package/mcp-server/useMcpServerCount.d.ts +1 -1
  109. package/mcp-server/useMcpServerCount.d.ts.map +1 -1
  110. package/mcp-server/useMcpServerList.d.ts +2 -2
  111. package/mcp-server/useMcpServerList.d.ts.map +1 -1
  112. package/mcp-server/useOAuthGrantStatus.d.ts +2 -0
  113. package/mcp-server/useOAuthGrantStatus.d.ts.map +1 -1
  114. package/mcp-server/useOAuthGrantStatus.js +14 -61
  115. package/mcp-server/useOAuthGrantStatus.js.map +1 -1
  116. package/mcp-server/useOrgOAuthApp.d.ts +2 -0
  117. package/mcp-server/useOrgOAuthApp.d.ts.map +1 -1
  118. package/mcp-server/useOrgOAuthApp.js +19 -43
  119. package/mcp-server/useOrgOAuthApp.js.map +1 -1
  120. package/oauth-app/useOAuthAppList.d.ts +2 -0
  121. package/oauth-app/useOAuthAppList.d.ts.map +1 -1
  122. package/oauth-app/useOAuthAppList.js +6 -34
  123. package/oauth-app/useOAuthAppList.js.map +1 -1
  124. package/organization/useOrganization.d.ts +2 -0
  125. package/organization/useOrganization.d.ts.map +1 -1
  126. package/organization/useOrganization.js +3 -33
  127. package/organization/useOrganization.js.map +1 -1
  128. package/package.json +4 -4
  129. package/platform-client/usePlatformClient.d.ts +2 -0
  130. package/platform-client/usePlatformClient.d.ts.map +1 -1
  131. package/platform-client/usePlatformClient.js +3 -33
  132. package/platform-client/usePlatformClient.js.map +1 -1
  133. package/platform-client/usePlatformClientList.d.ts +2 -0
  134. package/platform-client/usePlatformClientList.d.ts.map +1 -1
  135. package/platform-client/usePlatformClientList.js +6 -34
  136. package/platform-client/usePlatformClientList.js.map +1 -1
  137. package/runner/RunnerListPanel.d.ts.map +1 -1
  138. package/runner/RunnerListPanel.js +21 -5
  139. package/runner/RunnerListPanel.js.map +1 -1
  140. package/runner/__tests__/phase.test.d.ts +2 -0
  141. package/runner/__tests__/phase.test.d.ts.map +1 -0
  142. package/runner/__tests__/phase.test.js +33 -0
  143. package/runner/__tests__/phase.test.js.map +1 -0
  144. package/runner/__tests__/useRunnerList.test.d.ts +2 -0
  145. package/runner/__tests__/useRunnerList.test.d.ts.map +1 -0
  146. package/runner/__tests__/useRunnerList.test.js +68 -0
  147. package/runner/__tests__/useRunnerList.test.js.map +1 -0
  148. package/runner/index.d.ts +3 -1
  149. package/runner/index.d.ts.map +1 -1
  150. package/runner/index.js +2 -1
  151. package/runner/index.js.map +1 -1
  152. package/runner/phase.d.ts +13 -0
  153. package/runner/phase.d.ts.map +1 -1
  154. package/runner/phase.js +15 -0
  155. package/runner/phase.js.map +1 -1
  156. package/runner/useRunnerCredential.d.ts +66 -0
  157. package/runner/useRunnerCredential.d.ts.map +1 -0
  158. package/runner/useRunnerCredential.js +50 -0
  159. package/runner/useRunnerCredential.js.map +1 -0
  160. package/runner/useRunnerList.d.ts +21 -0
  161. package/runner/useRunnerList.d.ts.map +1 -1
  162. package/runner/useRunnerList.js +9 -36
  163. package/runner/useRunnerList.js.map +1 -1
  164. package/search/useResourceCount.d.ts +2 -1
  165. package/search/useResourceCount.d.ts.map +1 -1
  166. package/search/useResourceCount.js +13 -37
  167. package/search/useResourceCount.js.map +1 -1
  168. package/search/useResourceList.d.ts +2 -1
  169. package/search/useResourceList.d.ts.map +1 -1
  170. package/search/useResourceList.js +26 -46
  171. package/search/useResourceList.js.map +1 -1
  172. package/search/useResourceSearch.d.ts +4 -2
  173. package/search/useResourceSearch.d.ts.map +1 -1
  174. package/search/useResourceSearch.js +7 -27
  175. package/search/useResourceSearch.js.map +1 -1
  176. package/session/useNewSessionFlow.d.ts.map +1 -1
  177. package/session/useNewSessionFlow.js +26 -1
  178. package/session/useNewSessionFlow.js.map +1 -1
  179. package/session/useSession.d.ts +3 -1
  180. package/session/useSession.d.ts.map +1 -1
  181. package/session/useSession.js +3 -33
  182. package/session/useSession.js.map +1 -1
  183. package/session/useSessionExecutions.d.ts +3 -1
  184. package/session/useSessionExecutions.d.ts.map +1 -1
  185. package/session/useSessionExecutions.js +6 -34
  186. package/session/useSessionExecutions.js.map +1 -1
  187. package/session/useSessionList.d.ts +5 -3
  188. package/session/useSessionList.d.ts.map +1 -1
  189. package/session/useSessionList.js +9 -31
  190. package/session/useSessionList.js.map +1 -1
  191. package/skill/SkillPicker.js +1 -1
  192. package/skill/SkillPicker.js.map +1 -1
  193. package/skill/useSkill.d.ts +2 -0
  194. package/skill/useSkill.d.ts.map +1 -1
  195. package/skill/useSkill.js +13 -37
  196. package/skill/useSkill.js.map +1 -1
  197. package/skill/useSkillCount.d.ts +1 -1
  198. package/skill/useSkillCount.d.ts.map +1 -1
  199. package/skill/useSkillList.d.ts +2 -2
  200. package/skill/useSkillList.d.ts.map +1 -1
  201. package/src/agent/AgentPicker.tsx +1 -1
  202. package/src/agent/__tests__/useDefaultAgent.test.tsx +308 -0
  203. package/src/agent/useAgent.ts +19 -41
  204. package/src/agent/useAgentCount.ts +1 -1
  205. package/src/agent/useAgentList.ts +2 -2
  206. package/src/agent/useDefaultAgent.ts +67 -35
  207. package/src/agent-instance/useAgentInstance.ts +13 -37
  208. package/src/agent-instance/useAgentInstanceList.ts +31 -47
  209. package/src/api-key/useApiKeyList.ts +9 -32
  210. package/src/composer/ComposerToolbar.tsx +1 -22
  211. package/src/composer/ContextChip.tsx +2 -1
  212. package/src/composer/SessionComposer.tsx +206 -5
  213. package/src/composer/icons.tsx +27 -0
  214. package/src/environment/useEnvironment.ts +13 -37
  215. package/src/environment/useEnvironmentList.ts +31 -58
  216. package/src/execution/ArtifactPreviewModal.tsx +2 -2
  217. package/src/execution/useArtifactContent.ts +48 -65
  218. package/src/iam-policy/usePrincipalsCount.ts +17 -53
  219. package/src/iam-policy/useResourceAccess.ts +18 -55
  220. package/src/identity-provider/useIdentityProvider.ts +9 -39
  221. package/src/identity-provider/useIdentityProviderList.ts +14 -40
  222. package/src/index.ts +4 -0
  223. package/src/internal/__tests__/useFetch.test.ts +133 -0
  224. package/src/internal/useFetch.ts +121 -0
  225. package/src/invitation/useInvitationPreview.ts +14 -40
  226. package/src/invitation/useOrgInvitations.ts +15 -41
  227. package/src/library/ResourceListView.tsx +3 -3
  228. package/src/library/useDetectSkillPackage.ts +1 -1
  229. package/src/mcp-server/McpServerPicker.tsx +1 -1
  230. package/src/mcp-server/useMcpServer.ts +17 -42
  231. package/src/mcp-server/useMcpServerCount.ts +1 -1
  232. package/src/mcp-server/useMcpServerList.ts +2 -2
  233. package/src/mcp-server/useOAuthGrantStatus.ts +31 -69
  234. package/src/mcp-server/useOrgOAuthApp.ts +34 -51
  235. package/src/oauth-app/useOAuthAppList.ts +15 -41
  236. package/src/organization/useOrganization.ts +9 -38
  237. package/src/platform-client/usePlatformClient.ts +9 -39
  238. package/src/platform-client/usePlatformClientList.ts +14 -42
  239. package/src/runner/RunnerListPanel.tsx +49 -41
  240. package/src/runner/__tests__/phase.test.ts +35 -0
  241. package/src/runner/__tests__/useRunnerList.test.tsx +96 -0
  242. package/src/runner/index.ts +7 -0
  243. package/src/runner/phase.ts +16 -0
  244. package/src/runner/useRunnerCredential.ts +89 -0
  245. package/src/runner/useRunnerList.ts +36 -44
  246. package/src/search/useResourceCount.ts +20 -48
  247. package/src/search/useResourceList.ts +40 -57
  248. package/src/search/useResourceSearch.ts +22 -43
  249. package/src/session/useNewSessionFlow.ts +35 -1
  250. package/src/session/useSession.ts +10 -39
  251. package/src/session/useSessionExecutions.ts +20 -46
  252. package/src/session/useSessionList.ts +21 -42
  253. package/src/skill/SkillPicker.tsx +1 -1
  254. package/src/skill/useSkill.ts +17 -42
  255. package/src/skill/useSkillCount.ts +1 -1
  256. package/src/skill/useSkillList.ts +2 -2
  257. package/src/usage/useOrgUsageReport.ts +18 -46
  258. package/styles.css +1 -1
  259. package/usage/useOrgUsageReport.d.ts +2 -0
  260. package/usage/useOrgUsageReport.d.ts.map +1 -1
  261. package/usage/useOrgUsageReport.js +5 -35
  262. package/usage/useOrgUsageReport.js.map +1 -1
@@ -1,11 +1,10 @@
1
1
  "use client";
2
2
 
3
- import { useCallback, useEffect, useState } from "react";
4
3
  import { create } from "@bufbuild/protobuf";
5
4
  import type { Invitation } from "@stigmer/protos/ai/stigmer/iam/invitation/v1/api_pb";
6
5
  import { ListInvitationsByOrgInputSchema } from "@stigmer/protos/ai/stigmer/iam/invitation/v1/io_pb";
7
6
  import { useStigmer } from "../hooks";
8
- import { toError } from "../internal/toError";
7
+ import { useFetch } from "../internal/useFetch";
9
8
 
10
9
  /** Return value of {@link useOrgInvitations}. */
11
10
  export interface UseOrgInvitationsReturn {
@@ -13,6 +12,8 @@ export interface UseOrgInvitationsReturn {
13
12
  readonly invitations: readonly Invitation[];
14
13
  /** `true` while the initial fetch or a refetch is in flight. */
15
14
  readonly isLoading: boolean;
15
+ /** `true` while a background refetch is in flight and stale data is shown. */
16
+ readonly isRefetching: boolean;
16
17
  /** Error from the last failed request, or `null` when healthy. */
17
18
  readonly error: Error | null;
18
19
  /** Discard cached data and re-fetch the invitation list from the server. */
@@ -45,44 +46,17 @@ export function useOrgInvitations(
45
46
  org: string | null,
46
47
  ): UseOrgInvitationsReturn {
47
48
  const stigmer = useStigmer();
48
- const [invitations, setInvitations] = useState<Invitation[]>([]);
49
- const [isLoading, setIsLoading] = useState(false);
50
- const [error, setError] = useState<Error | null>(null);
51
- const [fetchKey, setFetchKey] = useState(0);
52
49
 
53
- const refetch = useCallback(() => setFetchKey((k) => k + 1), []);
54
-
55
- useEffect(() => {
56
- if (!org) {
57
- setInvitations([]);
58
- setIsLoading(false);
59
- setError(null);
60
- return;
61
- }
62
-
63
- const cancelled = { current: false };
64
- setIsLoading(true);
65
- setError(null);
66
-
67
- stigmer.invitation
68
- .listByOrg(create(ListInvitationsByOrgInputSchema, { org }))
69
- .then(
70
- (result) => {
71
- if (cancelled.current) return;
72
- setInvitations([...result.entries]);
73
- setIsLoading(false);
74
- },
75
- (err) => {
76
- if (cancelled.current) return;
77
- setError(toError(err));
78
- setIsLoading(false);
79
- },
80
- );
81
-
82
- return () => {
83
- cancelled.current = true;
84
- };
85
- }, [org, stigmer, fetchKey]);
86
-
87
- return { invitations, isLoading, error, refetch };
50
+ const { data: invitations, isLoading, isRefetching, error, refetch } = useFetch(
51
+ org
52
+ ? () =>
53
+ stigmer.invitation
54
+ .listByOrg(create(ListInvitationsByOrgInputSchema, { org }))
55
+ .then((r) => [...r.entries])
56
+ : null,
57
+ [org, stigmer],
58
+ [] as Invitation[],
59
+ );
60
+
61
+ return { invitations, isLoading, isRefetching, error, refetch };
88
62
  }
@@ -22,8 +22,8 @@ export interface ResourceListViewProps {
22
22
  readonly items: readonly SearchResult[];
23
23
  /** Whether data is currently being fetched. */
24
24
  readonly isLoading: boolean;
25
- /** Error message from the data hook. Shown as an alert when present and not loading. */
26
- readonly error?: string | null;
25
+ /** Error from the data hook. Shown as an alert when present and not loading. */
26
+ readonly error?: Error | null;
27
27
  /** Total number of results across all pages. Shown in the pagination bar when provided. */
28
28
  readonly totalCount?: number;
29
29
  /** Total number of pages available. Enables pagination controls when greater than 1. */
@@ -375,7 +375,7 @@ export function ResourceListView({
375
375
 
376
376
  {showSkeletons && (isGrid ? <SkeletonCards /> : <SkeletonRows />)}
377
377
 
378
- {showError && <ErrorState message={error!} onRetry={onRetry} />}
378
+ {showError && <ErrorState message={error!.message} onRetry={onRetry} />}
379
379
 
380
380
  {showEmpty && (
381
381
  <EmptyState
@@ -24,7 +24,7 @@ export interface UseDetectSkillPackageReturn {
24
24
  readonly isLoading: boolean;
25
25
 
26
26
  /** Error message from the SKILL.md fetch, or `null` when healthy. */
27
- readonly error: string | null;
27
+ readonly error: Error | null;
28
28
  }
29
29
 
30
30
  /**
@@ -580,7 +580,7 @@ export function McpServerPicker({
580
580
  autoFocus
581
581
  />
582
582
 
583
- {error && <p className="text-xs text-destructive">{error}</p>}
583
+ {error && <p className="text-xs text-destructive">{error.message}</p>}
584
584
 
585
585
  {/* Scrollable results list */}
586
586
  <div className="relative">
@@ -1,10 +1,9 @@
1
1
  "use client";
2
2
 
3
- import { useCallback, useEffect, useState } from "react";
4
3
  import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
5
4
  import { isNotFound } from "@stigmer/sdk";
6
5
  import { useStigmer } from "../hooks";
7
- import { toError } from "../internal/toError";
6
+ import { useFetch } from "../internal/useFetch";
8
7
 
9
8
  /** Return value of {@link useMcpServer}. */
10
9
  export interface UseMcpServerReturn {
@@ -12,6 +11,8 @@ export interface UseMcpServerReturn {
12
11
  readonly mcpServer: McpServer | null;
13
12
  /** `true` while the initial fetch or a refetch is in flight. */
14
13
  readonly isLoading: boolean;
14
+ /** `true` while a background refetch is in flight. */
15
+ readonly isRefetching: boolean;
15
16
  /** Error from the last failed request, or `null` when healthy. */
16
17
  readonly error: Error | null;
17
18
  /** Discard cached data and re-fetch the MCP server from the server. */
@@ -60,47 +61,21 @@ export function useMcpServer(
60
61
  slug: string | null,
61
62
  ): UseMcpServerReturn {
62
63
  const stigmer = useStigmer();
63
- const [mcpServer, setMcpServer] = useState<McpServer | null>(null);
64
- const [isLoading, setIsLoading] = useState(false);
65
- const [error, setError] = useState<Error | null>(null);
66
- const [fetchKey, setFetchKey] = useState(0);
67
64
 
68
- const refetch = useCallback(() => setFetchKey((k) => k + 1), []);
69
-
70
- useEffect(() => {
71
- if (!org || !slug) {
72
- setMcpServer(null);
73
- setIsLoading(false);
74
- setError(null);
75
- return;
76
- }
77
-
78
- const cancelled = { current: false };
79
- setIsLoading(true);
80
- setError(null);
81
-
82
- stigmer.mcpServer.getByReference({ org, slug }).then(
83
- (result) => {
84
- if (cancelled.current) return;
85
- setMcpServer(result);
86
- setIsLoading(false);
87
- },
88
- (err) => {
89
- if (cancelled.current) return;
90
- if (isNotFound(err)) {
91
- setMcpServer(null);
92
- setIsLoading(false);
93
- return;
65
+ const { data: mcpServer, isLoading, isRefetching, error, refetch } = useFetch(
66
+ org && slug
67
+ ? async () => {
68
+ try {
69
+ return await stigmer.mcpServer.getByReference({ org, slug });
70
+ } catch (err) {
71
+ if (isNotFound(err)) return null;
72
+ throw err;
73
+ }
94
74
  }
95
- setError(toError(err));
96
- setIsLoading(false);
97
- },
98
- );
99
-
100
- return () => {
101
- cancelled.current = true;
102
- };
103
- }, [org, slug, stigmer, fetchKey]);
75
+ : null,
76
+ [org, slug, stigmer],
77
+ null,
78
+ );
104
79
 
105
- return { mcpServer, isLoading, error, refetch };
80
+ return { mcpServer, isLoading, isRefetching, error, refetch };
106
81
  }
@@ -29,7 +29,7 @@ export interface UseMcpServerCountReturn {
29
29
  /** `true` while the count fetch is in flight. */
30
30
  readonly isLoading: boolean;
31
31
  /** Error message from the last failed request, or `null` when healthy. */
32
- readonly error: string | null;
32
+ readonly error: Error | null;
33
33
  /** Discard cached data and re-fetch the count from the server. */
34
34
  readonly refetch: () => void;
35
35
  }
@@ -36,8 +36,8 @@ export interface UseMcpServerListReturn {
36
36
  readonly currentPage: number;
37
37
  /** `true` while the initial fetch or a refetch is in flight. */
38
38
  readonly isLoading: boolean;
39
- /** Error message from the last failed request, or `null` when healthy. */
40
- readonly error: string | null;
39
+ /** Error from the last failed request, or `null` when healthy. */
40
+ readonly error: Error | null;
41
41
  /** Discard cached data and re-fetch the current page from the server. */
42
42
  readonly refetch: () => void;
43
43
  }
@@ -1,13 +1,12 @@
1
1
  "use client";
2
2
 
3
- import { useCallback, useEffect, useState } from "react";
4
3
  import { create } from "@bufbuild/protobuf";
5
4
  import {
6
5
  OAuthConnectionHealth,
7
6
  GetOAuthGrantStatusInputSchema,
8
7
  } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
9
8
  import { useStigmer } from "../hooks";
10
- import { toError } from "../internal/toError";
9
+ import { useFetch } from "../internal/useFetch";
11
10
 
12
11
  /** Return value of {@link useOAuthGrantStatus}. */
13
12
  export interface UseOAuthGrantStatusReturn {
@@ -32,6 +31,8 @@ export interface UseOAuthGrantStatusReturn {
32
31
  readonly connectionHealth: OAuthConnectionHealth;
33
32
  /** `true` while the grant status is being fetched. */
34
33
  readonly isLoading: boolean;
34
+ /** `true` while a background refetch is in flight. */
35
+ readonly isRefetching: boolean;
35
36
  /** Error from the last failed request, or `null` when healthy. */
36
37
  readonly error: Error | null;
37
38
  /** Discard cached data and re-fetch the grant status. */
@@ -40,15 +41,20 @@ export interface UseOAuthGrantStatusReturn {
40
41
 
41
42
  const BIGINT_ZERO = BigInt(0);
42
43
 
43
- const IDLE: UseOAuthGrantStatusReturn = {
44
+ interface OAuthGrantData {
45
+ connected: boolean;
46
+ accessTokenExpiresAt: bigint;
47
+ targetEnvVar: string;
48
+ authMethod: string;
49
+ connectionHealth: OAuthConnectionHealth;
50
+ }
51
+
52
+ const IDLE_DATA: OAuthGrantData = {
44
53
  connected: false,
45
54
  accessTokenExpiresAt: BIGINT_ZERO,
46
55
  targetEnvVar: "",
47
56
  authMethod: "",
48
57
  connectionHealth: OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_UNSPECIFIED,
49
- isLoading: false,
50
- error: null,
51
- refetch: () => {},
52
58
  };
53
59
 
54
60
  /**
@@ -75,69 +81,25 @@ export function useOAuthGrantStatus(
75
81
  org: string | null,
76
82
  ): UseOAuthGrantStatusReturn {
77
83
  const stigmer = useStigmer();
78
- const [connected, setConnected] = useState(false);
79
- const [accessTokenExpiresAt, setAccessTokenExpiresAt] = useState(BIGINT_ZERO);
80
- const [targetEnvVar, setTargetEnvVar] = useState("");
81
- const [authMethod, setAuthMethod] = useState("");
82
- const [connectionHealth, setConnectionHealth] = useState(
83
- OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_UNSPECIFIED,
84
- );
85
- const [isLoading, setIsLoading] = useState(false);
86
- const [error, setError] = useState<Error | null>(null);
87
- const [fetchKey, setFetchKey] = useState(0);
88
-
89
- const refetch = useCallback(() => setFetchKey((k) => k + 1), []);
90
-
91
- useEffect(() => {
92
- if (!resourceId || !org) {
93
- setConnected(false);
94
- setAccessTokenExpiresAt(BIGINT_ZERO);
95
- setTargetEnvVar("");
96
- setAuthMethod("");
97
- setConnectionHealth(OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_UNSPECIFIED);
98
- setIsLoading(false);
99
- setError(null);
100
- return;
101
- }
102
84
 
103
- const cancelled = { current: false };
104
- setIsLoading(true);
105
- setError(null);
106
-
107
- stigmer.mcpServer
108
- .getOAuthGrantStatus(create(GetOAuthGrantStatusInputSchema, { resourceId, org }))
109
- .then(
110
- (result) => {
111
- if (cancelled.current) return;
112
- setConnected(result.connected);
113
- setAccessTokenExpiresAt(result.accessTokenExpiresAt);
114
- setTargetEnvVar(result.targetEnvVar);
115
- setAuthMethod(result.authMethod);
116
- setConnectionHealth(result.connectionHealth);
117
- setIsLoading(false);
118
- },
119
- (err) => {
120
- if (cancelled.current) return;
121
- setError(toError(err));
122
- setIsLoading(false);
123
- },
124
- );
125
-
126
- return () => {
127
- cancelled.current = true;
128
- };
129
- }, [resourceId, org, stigmer, fetchKey]);
130
-
131
- if (!resourceId || !org) return { ...IDLE, refetch };
85
+ const { data, isLoading, isRefetching, error, refetch } = useFetch<OAuthGrantData>(
86
+ resourceId && org
87
+ ? async () => {
88
+ const result = await stigmer.mcpServer.getOAuthGrantStatus(
89
+ create(GetOAuthGrantStatusInputSchema, { resourceId, org }),
90
+ );
91
+ return {
92
+ connected: result.connected,
93
+ accessTokenExpiresAt: result.accessTokenExpiresAt,
94
+ targetEnvVar: result.targetEnvVar,
95
+ authMethod: result.authMethod,
96
+ connectionHealth: result.connectionHealth,
97
+ };
98
+ }
99
+ : null,
100
+ [resourceId, org, stigmer],
101
+ IDLE_DATA,
102
+ );
132
103
 
133
- return {
134
- connected,
135
- accessTokenExpiresAt,
136
- targetEnvVar,
137
- authMethod,
138
- connectionHealth,
139
- isLoading,
140
- error,
141
- refetch,
142
- };
104
+ return { ...data, isLoading, isRefetching, error, refetch };
143
105
  }
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { useCallback, useEffect, useState } from "react";
3
+ import { useCallback, useState } from "react";
4
4
  import { create } from "@bufbuild/protobuf";
5
5
  import {
6
6
  GetOrgOAuthAppInputSchema,
@@ -9,6 +9,7 @@ import {
9
9
  } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
10
10
  import { useStigmer } from "../hooks";
11
11
  import { toError } from "../internal/toError";
12
+ import { useFetch } from "../internal/useFetch";
12
13
 
13
14
  /** Return value of {@link useOrgOAuthApp}. */
14
15
  export interface UseOrgOAuthAppReturn {
@@ -24,6 +25,8 @@ export interface UseOrgOAuthAppReturn {
24
25
  readonly clientId: string | null;
25
26
  /** `true` while the override status is being fetched. */
26
27
  readonly isLoading: boolean;
28
+ /** `true` while a background refetch is in flight. */
29
+ readonly isRefetching: boolean;
27
30
  /** Error from the last failed fetch, or `null` when healthy. */
28
31
  readonly error: Error | null;
29
32
  /** Discard cached data and re-fetch the override status. */
@@ -68,11 +71,22 @@ export interface UseOrgOAuthAppReturn {
68
71
  readonly clearErrors: () => void;
69
72
  }
70
73
 
71
- const IDLE: UseOrgOAuthAppReturn = {
74
+ interface OrgOAuthAppData {
75
+ hasOverride: boolean;
76
+ oauthAppId: string | null;
77
+ clientId: string | null;
78
+ }
79
+
80
+ const IDLE_DATA: OrgOAuthAppData = {
72
81
  hasOverride: false,
73
82
  oauthAppId: null,
74
83
  clientId: null,
84
+ };
85
+
86
+ const IDLE: UseOrgOAuthAppReturn = {
87
+ ...IDLE_DATA,
75
88
  isLoading: false,
89
+ isRefetching: false,
76
90
  error: null,
77
91
  refetch: () => {},
78
92
  setOrgOAuthApp: () => Promise.resolve(""),
@@ -119,63 +133,33 @@ export function useOrgOAuthApp(
119
133
  ): UseOrgOAuthAppReturn {
120
134
  const stigmer = useStigmer();
121
135
 
122
- const [hasOverride, setHasOverride] = useState(false);
123
- const [oauthAppId, setOauthAppId] = useState<string | null>(null);
124
- const [clientId, setClientId] = useState<string | null>(null);
125
- const [isLoading, setIsLoading] = useState(false);
126
- const [error, setError] = useState<Error | null>(null);
127
- const [fetchKey, setFetchKey] = useState(0);
136
+ const { data, isLoading, isRefetching, error, refetch } = useFetch<OrgOAuthAppData>(
137
+ resourceId && org
138
+ ? async () => {
139
+ const result = await stigmer.mcpServer.getOrgOAuthApp(
140
+ create(GetOrgOAuthAppInputSchema, { resourceId, org }),
141
+ );
142
+ return {
143
+ hasOverride: result.hasOverride,
144
+ oauthAppId: result.oauthAppId || null,
145
+ clientId: result.clientId || null,
146
+ };
147
+ }
148
+ : null,
149
+ [resourceId, org, stigmer],
150
+ IDLE_DATA,
151
+ );
128
152
 
129
153
  const [isSetting, setIsSetting] = useState(false);
130
154
  const [setError_, setSetError] = useState<Error | null>(null);
131
155
  const [isDeleting, setIsDeleting] = useState(false);
132
156
  const [deleteError, setDeleteError] = useState<Error | null>(null);
133
157
 
134
- const refetch = useCallback(() => setFetchKey((k) => k + 1), []);
135
-
136
158
  const clearErrors = useCallback(() => {
137
159
  setSetError(null);
138
160
  setDeleteError(null);
139
161
  }, []);
140
162
 
141
- useEffect(() => {
142
- if (!resourceId || !org) {
143
- setHasOverride(false);
144
- setOauthAppId(null);
145
- setClientId(null);
146
- setIsLoading(false);
147
- setError(null);
148
- return;
149
- }
150
-
151
- const cancelled = { current: false };
152
- setIsLoading(true);
153
- setError(null);
154
-
155
- stigmer.mcpServer
156
- .getOrgOAuthApp(
157
- create(GetOrgOAuthAppInputSchema, { resourceId, org }),
158
- )
159
- .then(
160
- (result) => {
161
- if (cancelled.current) return;
162
- setHasOverride(result.hasOverride);
163
- setOauthAppId(result.oauthAppId || null);
164
- setClientId(result.clientId || null);
165
- setIsLoading(false);
166
- },
167
- (err) => {
168
- if (cancelled.current) return;
169
- setError(toError(err));
170
- setIsLoading(false);
171
- },
172
- );
173
-
174
- return () => {
175
- cancelled.current = true;
176
- };
177
- }, [resourceId, org, stigmer, fetchKey]);
178
-
179
163
  const setOrgOAuthApp = useCallback(
180
164
  async (newClientId: string, clientSecret: string): Promise<string> => {
181
165
  if (!resourceId || !org) {
@@ -233,10 +217,9 @@ export function useOrgOAuthApp(
233
217
  if (!resourceId || !org) return { ...IDLE, refetch, clearErrors };
234
218
 
235
219
  return {
236
- hasOverride,
237
- oauthAppId,
238
- clientId,
220
+ ...data,
239
221
  isLoading,
222
+ isRefetching,
240
223
  error,
241
224
  refetch,
242
225
  setOrgOAuthApp,
@@ -1,11 +1,10 @@
1
1
  "use client";
2
2
 
3
- import { useCallback, useEffect, useState } from "react";
4
3
  import { create } from "@bufbuild/protobuf";
5
4
  import { ListOAuthAppsByOrgInputSchema } from "@stigmer/protos/ai/stigmer/iam/oauthapp/v1/io_pb";
6
5
  import type { OAuthApp } from "@stigmer/protos/ai/stigmer/iam/oauthapp/v1/api_pb";
7
6
  import { useStigmer } from "../hooks";
8
- import { toError } from "../internal/toError";
7
+ import { useFetch } from "../internal/useFetch";
9
8
 
10
9
  /** Return value of {@link useOAuthAppList}. */
11
10
  export interface UseOAuthAppListReturn {
@@ -13,6 +12,8 @@ export interface UseOAuthAppListReturn {
13
12
  readonly oauthApps: readonly OAuthApp[];
14
13
  /** `true` while the initial fetch or a refetch is in flight. */
15
14
  readonly isLoading: boolean;
15
+ /** `true` while a background refetch is in flight and stale data is shown. */
16
+ readonly isRefetching: boolean;
16
17
  /** Error from the last failed request, or `null` when healthy. */
17
18
  readonly error: Error | null;
18
19
  /** Discard cached data and re-fetch the list from the server. */
@@ -41,44 +42,17 @@ export function useOAuthAppList(
41
42
  org: string | null,
42
43
  ): UseOAuthAppListReturn {
43
44
  const stigmer = useStigmer();
44
- const [oauthApps, setOauthApps] = useState<OAuthApp[]>([]);
45
- const [isLoading, setIsLoading] = useState(false);
46
- const [error, setError] = useState<Error | null>(null);
47
- const [fetchKey, setFetchKey] = useState(0);
48
45
 
49
- const refetch = useCallback(() => setFetchKey((k) => k + 1), []);
50
-
51
- useEffect(() => {
52
- if (!org) {
53
- setOauthApps([]);
54
- setIsLoading(false);
55
- setError(null);
56
- return;
57
- }
58
-
59
- const cancelled = { current: false };
60
- setIsLoading(true);
61
- setError(null);
62
-
63
- stigmer.oauthapp
64
- .listByOrg(create(ListOAuthAppsByOrgInputSchema, { org }))
65
- .then(
66
- (result) => {
67
- if (cancelled.current) return;
68
- setOauthApps([...result.entries]);
69
- setIsLoading(false);
70
- },
71
- (err) => {
72
- if (cancelled.current) return;
73
- setError(toError(err));
74
- setIsLoading(false);
75
- },
76
- );
77
-
78
- return () => {
79
- cancelled.current = true;
80
- };
81
- }, [org, stigmer, fetchKey]);
82
-
83
- return { oauthApps, isLoading, error, refetch };
46
+ const { data: oauthApps, isLoading, isRefetching, error, refetch } = useFetch(
47
+ org
48
+ ? () =>
49
+ stigmer.oauthapp
50
+ .listByOrg(create(ListOAuthAppsByOrgInputSchema, { org }))
51
+ .then((r) => [...r.entries])
52
+ : null,
53
+ [org, stigmer],
54
+ [] as OAuthApp[],
55
+ );
56
+
57
+ return { oauthApps, isLoading, isRefetching, error, refetch };
84
58
  }
@@ -1,9 +1,8 @@
1
1
  "use client";
2
2
 
3
- import { useCallback, useEffect, useState } from "react";
4
3
  import type { Organization } from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/api_pb";
5
4
  import { useStigmer } from "../hooks";
6
- import { toError } from "../internal/toError";
5
+ import { useFetch } from "../internal/useFetch";
7
6
 
8
7
  /** Return value of {@link useOrganization}. */
9
8
  export interface UseOrganizationReturn {
@@ -11,6 +10,8 @@ export interface UseOrganizationReturn {
11
10
  readonly organization: Organization | null;
12
11
  /** `true` while the initial fetch or a refetch is in flight. */
13
12
  readonly isLoading: boolean;
13
+ /** `true` while a background refetch is in flight and stale data is shown. */
14
+ readonly isRefetching: boolean;
14
15
  /** Error from the last failed request, or `null` when healthy. */
15
16
  readonly error: Error | null;
16
17
  /** Discard cached data and re-fetch the organization from the server. */
@@ -38,42 +39,12 @@ export function useOrganization(
38
39
  id: string | null,
39
40
  ): UseOrganizationReturn {
40
41
  const stigmer = useStigmer();
41
- const [organization, setOrganization] = useState<Organization | null>(null);
42
- const [isLoading, setIsLoading] = useState(false);
43
- const [error, setError] = useState<Error | null>(null);
44
- const [fetchKey, setFetchKey] = useState(0);
45
42
 
46
- const refetch = useCallback(() => setFetchKey((k) => k + 1), []);
43
+ const { data: organization, isLoading, isRefetching, error, refetch } = useFetch(
44
+ id ? () => stigmer.organization.get(id) : null,
45
+ [id, stigmer],
46
+ null as Organization | null,
47
+ );
47
48
 
48
- useEffect(() => {
49
- if (!id) {
50
- setOrganization(null);
51
- setIsLoading(false);
52
- setError(null);
53
- return;
54
- }
55
-
56
- const cancelled = { current: false };
57
- setIsLoading(true);
58
- setError(null);
59
-
60
- stigmer.organization.get(id).then(
61
- (result) => {
62
- if (cancelled.current) return;
63
- setOrganization(result);
64
- setIsLoading(false);
65
- },
66
- (err) => {
67
- if (cancelled.current) return;
68
- setError(toError(err));
69
- setIsLoading(false);
70
- },
71
- );
72
-
73
- return () => {
74
- cancelled.current = true;
75
- };
76
- }, [id, stigmer, fetchKey]);
77
-
78
- return { organization, isLoading, error, refetch };
49
+ return { organization, isLoading, isRefetching, error, refetch };
79
50
  }