1- import { useLazyGetUserKeysQuery } from '@meshery/schemas/cloudApi' ;
21import { Key } from '@meshery/schemas/permissions' ;
32import { useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
43import { getPermissionKeys , isPermissionKeySet , PermissionKeySpec } from './PermissionProvider' ;
@@ -37,11 +36,21 @@ const orgHasPermission = (
3736const hasDefiniteId = < T extends { id ?: string } > ( org : T ) : org is T & { id : string } =>
3837 Boolean ( org . id ) ;
3938
39+ /**
40+ * The shape of the trigger function returned by RTK Query's
41+ * `useLazyGetUserKeysQuery`. Both `cloudApi` and `mesheryApi` export one
42+ * with the same signature — callers pass whichever is appropriate.
43+ */
44+ export type TriggerGetKeys = (
45+ arg : { orgId : string }
46+ ) => { unwrap : ( ) => Promise < { keys ?: Array < { id : string ; function : string } > } > } ;
47+
4048/**
4149 * Configuration for `useAccessibleOrgs`.
4250 *
43- * The hook does NOT read orgs or the current org from any global store — both
44- * are supplied by the host application so the hook stays framework-agnostic.
51+ * The hook does NOT read orgs, the current org, or the keys endpoint from any
52+ * global store — all are supplied by the host application so the hook stays
53+ * framework-agnostic.
4554 *
4655 * Generic over `T` so the element type of `allOrgs` flows through to
4756 * `accessibleOrgs` — callers keep `org.name`, `org.avatar`, etc. typed.
@@ -58,38 +67,57 @@ export interface UseAccessibleOrgsOptions<T extends { id?: string } = { id?: str
5867
5968 /** The permission key (or key set) to check each org against. */
6069 permissionKey ?: PermissionKeySpec ;
70+
71+ /**
72+ * The lazy trigger returned by RTK Query's `useLazyGetUserKeysQuery`.
73+ *
74+ * - meshery-cloud passes the one from `@meshery/schemas/cloudApi`
75+ * - meshery passes the one from `@meshery/schemas/mesheryApi`
76+ *
77+ * This avoids hardcoding a transport layer so the same logic works in both.
78+ */
79+ triggerGetKeys : TriggerGetKeys ;
6180}
6281
6382/**
6483 * Returns only those organizations where the user holds the permission(s)
6584 * described by `permissionKey`. The current org is excluded from the result
6685 * since the user is already on the 403 page for it.
6786 *
68- * Queries `/api/identity/orgs/:orgId/users/keys` for each org in parallel
69- * via `useLazyGetUserKeysQuery`. This is a 403-page-only hook — the N
70- * parallel requests are acceptable because this page is not a hot path.
87+ * Queries `/api/identity/orgs/:orgId/users/keys` for each org in parallel.
88+ * This is a 403-page-only hook — the N parallel requests are acceptable
89+ * because this page is not a hot path.
7190 *
7291 * @example
7392 * ```tsx
7493 * // In meshery-cloud
75- * const { data: allOrgs, isSuccess } = useGetActiveOrgs();
76- * const currentOrg = useSelector(selectCurrentOrg);
94+ * const [triggerGetKeys] = useLazyGetUserKeysQuery(); // from cloudApi
7795 * const { accessibleOrgs, isLoading } = useAccessibleOrgs({
7896 * allOrgs,
7997 * currentOrgId: currentOrg?.id,
8098 * orgsLoaded: isSuccess,
8199 * permissionKey,
100+ * triggerGetKeys,
101+ * });
102+ *
103+ * // In meshery
104+ * const [triggerGetKeys] = useLazyGetUserKeysQuery(); // from mesheryApi
105+ * const { accessibleOrgs, isLoading } = useAccessibleOrgs({
106+ * allOrgs,
107+ * currentOrgId: selectedOrg?.id,
108+ * orgsLoaded: !isLoading,
109+ * permissionKey,
110+ * triggerGetKeys,
82111 * });
83112 * ```
84113 */
85114export const useAccessibleOrgs = < T extends { id ?: string } > ( {
86115 allOrgs,
87116 currentOrgId,
88117 orgsLoaded,
89- permissionKey
118+ permissionKey,
119+ triggerGetKeys
90120} : UseAccessibleOrgsOptions < T > ) => {
91- const [ triggerGetKeys ] = useLazyGetUserKeysQuery ( ) ;
92-
93121 // Track which orgs have been checked and their results.
94122 // Map<orgId, hasPermission>
95123 const [ checkedOrgs , setCheckedOrgs ] = useState < Map < string , boolean > > ( new Map ( ) ) ;
0 commit comments