@jmruthers/pace-core 0.5.111 → 0.5.112
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/{DataTable-5W2HVLLV.js → DataTable-3D3BUZDV.js} +8 -8
- package/dist/{UnifiedAuthProvider-LUM3QLS5.js → UnifiedAuthProvider-KZZUO27W.js} +3 -3
- package/dist/{api-SIZPFBFX.js → api-QPMBZZUZ.js} +3 -3
- package/dist/{audit-5JI5T3SL.js → audit-H4YJJF7R.js} +2 -2
- package/dist/{chunk-IWJYNWXN.js → chunk-3OGQLOJM.js} +11 -3
- package/dist/chunk-3OGQLOJM.js.map +1 -0
- package/dist/{chunk-TDFBX7KJ.js → chunk-7H75SHXZ.js} +2 -2
- package/dist/{chunk-EFVQBYFN.js → chunk-BUN7NMV7.js} +2 -2
- package/dist/{chunk-ACYQNYHB.js → chunk-C5RN4TE5.js} +7 -7
- package/dist/{chunk-2BIDKXQU.js → chunk-EKVVTPIF.js} +82 -23
- package/dist/chunk-EKVVTPIF.js.map +1 -0
- package/dist/{chunk-X7SPKHYZ.js → chunk-F6QB26OS.js} +4 -4
- package/dist/{chunk-UGVU7L7N.js → chunk-I7JC7PTJ.js} +6 -6
- package/dist/chunk-I7JC7PTJ.js.map +1 -0
- package/dist/{chunk-I5YM5BGS.js → chunk-L36JW4KV.js} +2 -2
- package/dist/{chunk-ZL45MG76.js → chunk-MNSGWRPB.js} +15 -15
- package/dist/{chunk-JE2GFA3O.js → chunk-NEONKMTU.js} +3 -3
- package/dist/{chunk-MW73E7SP.js → chunk-OO3V7W4H.js} +2 -2
- package/dist/chunk-OO3V7W4H.js.map +1 -0
- package/dist/{chunk-PXXS26G5.js → chunk-TAJRS6YB.js} +2 -2
- package/dist/{chunk-TD4BXGPE.js → chunk-WMPZY26G.js} +8 -4
- package/dist/{chunk-TD4BXGPE.js.map → chunk-WMPZY26G.js.map} +1 -1
- package/dist/components.js +10 -10
- package/dist/hooks.js +7 -7
- package/dist/index.js +13 -13
- package/dist/providers.js +2 -2
- package/dist/rbac/index.js +9 -9
- package/dist/utils.js +1 -1
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +8 -8
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +12 -12
- package/package.json +1 -1
- package/src/components/DataTable/DataTable.test.tsx +405 -154
- package/src/components/DataTable/components/DataTableCore.tsx +6 -1
- package/src/components/EventSelector/EventSelector.tsx +32 -2
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +56 -8
- package/src/components/NavigationMenu/NavigationMenu.tsx +75 -12
- package/src/rbac/audit-enhanced.ts +14 -2
- package/src/rbac/audit.test.ts +16 -6
- package/src/rbac/audit.ts +11 -1
- package/src/rbac/hooks/usePermissions.ts +18 -2
- package/src/services/EventService.ts +3 -2
- package/dist/chunk-2BIDKXQU.js.map +0 -1
- package/dist/chunk-IWJYNWXN.js.map +0 -1
- package/dist/chunk-MW73E7SP.js.map +0 -1
- package/dist/chunk-UGVU7L7N.js.map +0 -1
- /package/dist/{DataTable-5W2HVLLV.js.map → DataTable-3D3BUZDV.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-LUM3QLS5.js.map → UnifiedAuthProvider-KZZUO27W.js.map} +0 -0
- /package/dist/{api-SIZPFBFX.js.map → api-QPMBZZUZ.js.map} +0 -0
- /package/dist/{audit-5JI5T3SL.js.map → audit-H4YJJF7R.js.map} +0 -0
- /package/dist/{chunk-TDFBX7KJ.js.map → chunk-7H75SHXZ.js.map} +0 -0
- /package/dist/{chunk-EFVQBYFN.js.map → chunk-BUN7NMV7.js.map} +0 -0
- /package/dist/{chunk-ACYQNYHB.js.map → chunk-C5RN4TE5.js.map} +0 -0
- /package/dist/{chunk-X7SPKHYZ.js.map → chunk-F6QB26OS.js.map} +0 -0
- /package/dist/{chunk-I5YM5BGS.js.map → chunk-L36JW4KV.js.map} +0 -0
- /package/dist/{chunk-ZL45MG76.js.map → chunk-MNSGWRPB.js.map} +0 -0
- /package/dist/{chunk-JE2GFA3O.js.map → chunk-NEONKMTU.js.map} +0 -0
- /package/dist/{chunk-PXXS26G5.js.map → chunk-TAJRS6YB.js.map} +0 -0
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
init_useOrganisations,
|
|
3
3
|
useOrganisations
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-L36JW4KV.js";
|
|
5
5
|
import {
|
|
6
6
|
init_UnifiedAuthProvider
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-7H75SHXZ.js";
|
|
8
8
|
import {
|
|
9
9
|
OrganisationServiceContext,
|
|
10
10
|
OrganisationServiceProvider,
|
|
11
11
|
init_OrganisationServiceProvider,
|
|
12
12
|
useOrganisationService,
|
|
13
13
|
useUnifiedAuth
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-OO3V7W4H.js";
|
|
15
15
|
import {
|
|
16
16
|
init_organisationContext,
|
|
17
17
|
setOrganisationContext
|
|
@@ -1572,4 +1572,4 @@ export {
|
|
|
1572
1572
|
clearPublicFileDisplayCache,
|
|
1573
1573
|
getPublicFileDisplayCacheStats
|
|
1574
1574
|
};
|
|
1575
|
-
//# sourceMappingURL=chunk-
|
|
1575
|
+
//# sourceMappingURL=chunk-F6QB26OS.js.map
|
|
@@ -6,16 +6,16 @@ import {
|
|
|
6
6
|
isPermitted,
|
|
7
7
|
isPermittedCached,
|
|
8
8
|
resolveAppContext
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-TAJRS6YB.js";
|
|
10
10
|
import {
|
|
11
11
|
init_useOrganisations,
|
|
12
12
|
useEvents,
|
|
13
13
|
useOrganisations
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-L36JW4KV.js";
|
|
15
15
|
import {
|
|
16
16
|
init_UnifiedAuthProvider,
|
|
17
17
|
useUnifiedAuth
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-OO3V7W4H.js";
|
|
19
19
|
import {
|
|
20
20
|
getCurrentAppName
|
|
21
21
|
} from "./chunk-JCQZ6LA7.js";
|
|
@@ -332,7 +332,6 @@ function usePermissions(userId, scope) {
|
|
|
332
332
|
return;
|
|
333
333
|
}
|
|
334
334
|
if (!scope.organisationId || scope.organisationId === null || typeof scope.organisationId === "string" && scope.organisationId.trim() === "") {
|
|
335
|
-
setPermissions({});
|
|
336
335
|
setIsLoading(true);
|
|
337
336
|
setError(null);
|
|
338
337
|
return;
|
|
@@ -344,6 +343,7 @@ function usePermissions(userId, scope) {
|
|
|
344
343
|
const permissionMap = await getPermissionMap({ userId, scope });
|
|
345
344
|
setPermissions(permissionMap);
|
|
346
345
|
} catch (err) {
|
|
346
|
+
console.error("[usePermissions] Failed to fetch permissions:", err);
|
|
347
347
|
setError(err instanceof Error ? err : new Error("Failed to fetch permissions"));
|
|
348
348
|
} finally {
|
|
349
349
|
setIsLoading(false);
|
|
@@ -380,7 +380,6 @@ function usePermissions(userId, scope) {
|
|
|
380
380
|
return;
|
|
381
381
|
}
|
|
382
382
|
if (!scope.organisationId || scope.organisationId === null || typeof scope.organisationId === "string" && scope.organisationId.trim() === "") {
|
|
383
|
-
setPermissions({});
|
|
384
383
|
setIsLoading(true);
|
|
385
384
|
setError(null);
|
|
386
385
|
return;
|
|
@@ -392,6 +391,7 @@ function usePermissions(userId, scope) {
|
|
|
392
391
|
const permissionMap = await getPermissionMap({ userId, scope });
|
|
393
392
|
setPermissions(permissionMap);
|
|
394
393
|
} catch (err) {
|
|
394
|
+
console.error("[usePermissions] Failed to refetch permissions:", err);
|
|
395
395
|
setError(err instanceof Error ? err : new Error("Failed to fetch permissions"));
|
|
396
396
|
} finally {
|
|
397
397
|
setIsLoading(false);
|
|
@@ -691,4 +691,4 @@ export {
|
|
|
691
691
|
useHasAllPermissions,
|
|
692
692
|
useCachedPermissions
|
|
693
693
|
};
|
|
694
|
-
//# sourceMappingURL=chunk-
|
|
694
|
+
//# sourceMappingURL=chunk-I7JC7PTJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/rbac/hooks/useRBAC.ts","../src/rbac/hooks/useResolvedScope.ts","../src/rbac/utils/eventContext.ts","../src/rbac/hooks/usePermissions.ts"],"sourcesContent":["/**\n * @file RBAC Hook\n * @package @jmruthers/pace-core\n * @module RBAC/Hooks\n * @since 0.3.0\n *\n * A React hook that provides access to the RBAC (Role-Based Access Control) system\n * through the hardened RBAC engine API. The hook defers all permission and role\n * resolution to the shared engine to ensure consistent security behaviour across\n * applications.\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport { useOrganisations } from '../../hooks/useOrganisations';\nimport { useEvents } from '../../hooks/useEvents';\nimport {\n getPermissionMap,\n getAccessLevel,\n resolveAppContext,\n getRoleContext,\n} from '../api';\nimport { getRBACLogger } from '../config';\nimport type {\n UserRBACContext,\n GlobalRole,\n OrganisationRole,\n EventAppRole,\n Permission,\n Scope,\n PermissionMap,\n UUID,\n} from '../types';\n\nfunction mapAccessLevelToEventRole(level: string | null): EventAppRole | null {\n switch (level) {\n case 'viewer':\n return 'viewer';\n case 'participant':\n return 'participant';\n case 'planner':\n return 'planner';\n case 'admin':\n case 'super':\n return 'event_admin';\n default:\n return null;\n }\n}\n\nexport function useRBAC(pageId?: string): UserRBACContext {\n const logger = getRBACLogger();\n const { user, session, appName } = useUnifiedAuth();\n const { selectedOrganisation } = useOrganisations();\n\n let selectedEvent: { event_id: string } | null = null;\n try {\n const eventsContext = useEvents();\n selectedEvent = eventsContext.selectedEvent;\n } catch (error) {\n logger.debug('[useRBAC] Event provider not available, continuing without event context', error);\n }\n\n const [globalRole, setGlobalRole] = useState<GlobalRole | null>(null);\n const [organisationRole, setOrganisationRole] = useState<OrganisationRole | null>(null);\n const [eventAppRole, setEventAppRole] = useState<EventAppRole | null>(null);\n const [permissionMap, setPermissionMap] = useState<PermissionMap>({} as PermissionMap);\n const [currentScope, setCurrentScope] = useState<Scope | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const resetState = useCallback(() => {\n setGlobalRole(null);\n setOrganisationRole(null);\n setEventAppRole(null);\n setPermissionMap({} as PermissionMap);\n setCurrentScope(null);\n }, []);\n\n const loadRBACContext = useCallback(async () => {\n if (!user || !session) {\n resetState();\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n let appId: UUID | undefined;\n if (appName) {\n const resolved = await resolveAppContext({ userId: user.id as UUID, appName });\n if (!resolved || !resolved.hasAccess) {\n throw new Error(`User does not have access to app \"${appName}\"`);\n }\n appId = resolved.appId;\n }\n\n const scope: Scope = {\n organisationId: selectedOrganisation?.id,\n eventId: selectedEvent?.event_id || undefined,\n appId,\n };\n setCurrentScope(scope);\n\n const [map, roleContext, accessLevel] = await Promise.all([\n getPermissionMap({ userId: user.id as UUID, scope }),\n getRoleContext({ userId: user.id as UUID, scope }),\n getAccessLevel({ userId: user.id as UUID, scope }),\n ]);\n\n setPermissionMap(map);\n setGlobalRole(roleContext.globalRole);\n setOrganisationRole(roleContext.organisationRole);\n setEventAppRole(roleContext.eventAppRole || mapAccessLevelToEventRole(accessLevel));\n } catch (err) {\n const handledError = err instanceof Error ? err : new Error('Failed to load RBAC context');\n logger.error('[useRBAC] Error loading RBAC context:', handledError);\n setError(handledError);\n resetState();\n } finally {\n setIsLoading(false);\n }\n }, [appName, logger, resetState, selectedEvent?.event_id, selectedOrganisation?.id, session, user]);\n\n const hasGlobalPermission = useCallback(\n (permission: string): boolean => {\n if (globalRole === 'super_admin' || permissionMap['*']) {\n return true;\n }\n\n if (permission === 'super_admin') {\n return globalRole === 'super_admin';\n }\n\n if (permission === 'org_admin') {\n return organisationRole === 'org_admin';\n }\n\n return permissionMap[permission as Permission] === true;\n },\n [globalRole, organisationRole, permissionMap],\n );\n\n const isSuperAdmin = useMemo(() => globalRole === 'super_admin' || permissionMap['*'] === true, [globalRole, permissionMap]);\n const isOrgAdmin = useMemo(() => organisationRole === 'org_admin' || isSuperAdmin, [organisationRole, isSuperAdmin]);\n const isEventAdmin = useMemo(() => eventAppRole === 'event_admin' || isSuperAdmin, [eventAppRole, isSuperAdmin]);\n const canManageOrganisation = useMemo(() => isSuperAdmin || organisationRole === 'org_admin', [isSuperAdmin, organisationRole]);\n const canManageEvent = useMemo(() => isSuperAdmin || eventAppRole === 'event_admin', [isSuperAdmin, eventAppRole]);\n\n useEffect(() => {\n loadRBACContext();\n }, [loadRBACContext]);\n\n return {\n user,\n globalRole,\n organisationRole,\n eventAppRole,\n hasGlobalPermission,\n isSuperAdmin,\n isOrgAdmin,\n isEventAdmin,\n canManageOrganisation,\n canManageEvent,\n isLoading,\n error,\n };\n}\n","/**\n * @file useResolvedScope Hook\n * @package @jmruthers/pace-core\n * @module RBAC/Hooks\n * @since 1.0.0\n * \n * Shared hook for resolving RBAC scope from various contexts.\n * This hook is used by both DataTable and PagePermissionGuard to ensure\n * consistent scope resolution logic.\n */\n\nimport { useEffect, useState, useRef } from 'react';\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport type { Database } from '../../types/database';\nimport type { Scope } from '../types';\nimport { createScopeFromEvent } from '../utils/eventContext';\nimport { getCurrentAppName } from '../../utils/appNameResolver';\n\nexport interface UseResolvedScopeOptions {\n /** Supabase client instance */\n supabase: SupabaseClient<Database> | null;\n /** Selected organisation ID */\n selectedOrganisationId: string | null;\n /** Selected event ID */\n selectedEventId: string | null;\n}\n\nexport interface UseResolvedScopeReturn {\n /** Resolved scope, or null if not yet resolved */\n resolvedScope: Scope | null;\n /** Whether the scope resolution is in progress */\n isLoading: boolean;\n /** Error if scope resolution failed */\n error: Error | null;\n}\n\n/**\n * Resolves RBAC scope from organisation and event context\n * \n * This hook handles the complex logic of determining the correct RBAC scope\n * based on available context (organisation, event, app). It ensures consistent\n * scope resolution across the application.\n * \n * @param options - Hook options\n * @returns Resolved scope and loading state\n * \n * @example\n * ```tsx\n * const { resolvedScope, isLoading } = useResolvedScope({\n * supabase,\n * selectedOrganisationId,\n * selectedEventId\n * });\n * \n * if (isLoading) return <Loading />;\n * if (!resolvedScope) return <Error />;\n * \n * const permission = useCan(userId, resolvedScope, permission);\n * ```\n */\nexport function useResolvedScope({\n supabase,\n selectedOrganisationId,\n selectedEventId\n}: UseResolvedScopeOptions): UseResolvedScopeReturn {\n const [resolvedScope, setResolvedScope] = useState<Scope | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n \n // Use a ref to track the stable scope and only update it when it actually changes\n const stableScopeRef = useRef<{ organisationId: string; appId: string; eventId: string | undefined }>({ \n organisationId: '', \n appId: '', \n eventId: undefined \n });\n \n // Update stable scope ref in useEffect to avoid updates during render\n useEffect(() => {\n if (resolvedScope && resolvedScope.organisationId) {\n const newScope = {\n organisationId: resolvedScope.organisationId,\n appId: resolvedScope.appId,\n eventId: resolvedScope.eventId\n };\n \n // Only update if the scope has actually changed\n if (stableScopeRef.current.organisationId !== newScope.organisationId ||\n stableScopeRef.current.eventId !== newScope.eventId ||\n stableScopeRef.current.appId !== newScope.appId) {\n stableScopeRef.current = {\n organisationId: newScope.organisationId,\n appId: newScope.appId || '',\n eventId: newScope.eventId\n };\n }\n } else if (!resolvedScope) {\n // Reset to empty scope when no resolved scope\n stableScopeRef.current = { organisationId: '', appId: '', eventId: undefined };\n }\n }, [resolvedScope]);\n \n const stableScope = stableScopeRef.current;\n \n useEffect(() => {\n let cancelled = false;\n \n const resolveScope = async () => {\n setIsLoading(true);\n setError(null);\n \n try {\n // Get app ID from package.json or environment\n let appId: string | undefined = undefined;\n \n // Try to resolve from database\n if (supabase) {\n const appName = getCurrentAppName();\n if (appName) {\n try {\n const { data: app, error } = await supabase\n .from('rbac_apps')\n .select('id, name, is_active')\n .eq('name', appName)\n .eq('is_active', true)\n .single() as { data: { id: string; name: string; is_active: boolean } | null; error: any };\n \n if (error) {\n // Check if app exists but is inactive\n const { data: inactiveApp } = await supabase\n .from('rbac_apps')\n .select('id, name, is_active')\n .eq('name', appName)\n .single() as { data: { id: string; name: string; is_active: boolean } | null };\n \n if (inactiveApp) {\n console.error(`[useResolvedScope] App \"${appName}\" exists but is inactive (is_active: ${inactiveApp.is_active})`);\n } else {\n console.error(`[useResolvedScope] App \"${appName}\" not found in rbac_apps table`);\n }\n } else if (app) {\n appId = app.id;\n }\n } catch (error) {\n console.error('[useResolvedScope] Unexpected error resolving app ID:', error);\n }\n }\n }\n\n // Resolve scope based on available context\n\n // If we have both organisation and event, use them directly\n if (selectedOrganisationId && selectedEventId) {\n if (!cancelled) {\n setResolvedScope({\n organisationId: selectedOrganisationId,\n eventId: selectedEventId,\n appId: appId\n });\n setIsLoading(false);\n }\n return;\n }\n\n // If we only have organisation, use it\n if (selectedOrganisationId) {\n if (!cancelled) {\n setResolvedScope({\n organisationId: selectedOrganisationId,\n eventId: selectedEventId || undefined,\n appId: appId\n });\n setIsLoading(false);\n }\n return;\n }\n\n // If we only have event, resolve organisation from event\n if (selectedEventId && supabase) {\n try {\n const eventScope = await createScopeFromEvent(supabase, selectedEventId, appId);\n if (!eventScope) {\n console.error('[useResolvedScope] Could not resolve organization from event context');\n if (!cancelled) {\n setResolvedScope(null);\n setError(new Error('Could not resolve organisation from event context'));\n setIsLoading(false);\n }\n return;\n }\n // Preserve the resolved app ID\n if (!cancelled) {\n setResolvedScope({\n ...eventScope,\n appId: appId || eventScope.appId\n });\n setIsLoading(false);\n }\n } catch (err) {\n console.error('[useResolvedScope] Error resolving scope from event:', err);\n if (!cancelled) {\n setResolvedScope(null);\n setError(err as Error);\n setIsLoading(false);\n }\n }\n return;\n }\n\n // No context available\n console.error('[useResolvedScope] No organisation or event context available');\n if (!cancelled) {\n setResolvedScope(null);\n setError(new Error('No organisation or event context available'));\n setIsLoading(false);\n }\n } catch (err) {\n if (!cancelled) {\n setError(err as Error);\n setIsLoading(false);\n }\n }\n };\n\n resolveScope();\n \n return () => {\n cancelled = true;\n };\n }, [selectedOrganisationId, selectedEventId, supabase]);\n \n return {\n resolvedScope: stableScope.organisationId ? stableScope as Scope : null,\n isLoading,\n error\n };\n}\n","/**\n * Event Context Utilities for RBAC\n * @package @jmruthers/pace-core\n * @module RBAC/EventContext\n * @since 1.0.0\n * \n * This module provides utilities for event-based RBAC operations where\n * the organization context is derived from the event context.\n */\n\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../../types/database';\nimport { UUID, Scope } from '../types';\n\n/**\n * Get organization ID from event ID\n * \n * @param supabase - Supabase client\n * @param eventId - Event ID\n * @returns Promise resolving to organization ID or null\n */\nexport async function getOrganisationFromEvent(\n supabase: SupabaseClient<Database>,\n eventId: string\n): Promise<UUID | null> {\n const { data, error } = await supabase\n .from('event')\n .select('organisation_id')\n .eq('event_id', eventId)\n .single() as { data: { organisation_id: string } | null; error: any };\n\n if (error || !data) {\n return null;\n }\n\n return data.organisation_id;\n}\n\n/**\n * Create a complete scope from event context\n * \n * @param supabase - Supabase client\n * @param eventId - Event ID\n * @param appId - Optional app ID\n * @returns Promise resolving to complete scope\n */\nexport async function createScopeFromEvent(\n supabase: SupabaseClient<Database>,\n eventId: string,\n appId?: UUID\n): Promise<Scope | null> {\n const organisationId = await getOrganisationFromEvent(supabase, eventId);\n \n if (!organisationId) {\n return null;\n }\n\n return {\n organisationId,\n eventId,\n appId\n };\n}\n\n/**\n * Check if a scope is event-based (has eventId but no explicit organisationId)\n * \n * @param scope - Permission scope\n * @returns True if scope is event-based\n */\nexport function isEventBasedScope(scope: Scope): boolean {\n return !scope.organisationId && !!scope.eventId;\n}\n\n/**\n * Validate that an event-based scope has the required context\n * \n * @param scope - Permission scope\n * @returns True if scope is valid for event-based operations\n */\nexport function isValidEventBasedScope(scope: Scope): boolean {\n return isEventBasedScope(scope) && !!scope.eventId;\n}\n","/**\n * @file RBAC Permission Hooks\n * @package @jmruthers/pace-core\n * @module RBAC/Hooks\n * @since 1.0.0\n * \n * This module provides React hooks for RBAC functionality.\n */\n\nimport { useState, useEffect, useCallback, useMemo, useRef } from 'react';\nimport { \n UUID, \n Scope, \n Permission, \n PermissionMap\n} from '../types';\nimport { AccessLevel as AccessLevelType } from '../types';\nimport { \n getAccessLevel, \n getPermissionMap, \n isPermitted,\n isPermittedCached \n} from '../api';\n\n/**\n * Hook to get user's permissions in a scope\n * \n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @returns Permission state and methods\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { permissions, isLoading, error } = usePermissions(userId, scope);\n * \n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return (\n * <div>\n * {permissions['read:users'] && <UserList />}\n * {permissions['create:users'] && <CreateUserButton />}\n * </div>\n * );\n * }\n * ```\n */\nexport function usePermissions(userId: UUID, scope: Scope) {\n const [permissions, setPermissions] = useState<PermissionMap>({} as PermissionMap);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const isFetchingRef = useRef(false);\n\n // Add timeout for missing organisation context (3 seconds)\n useEffect(() => {\n if (!scope.organisationId || scope.organisationId === null || (typeof scope.organisationId === 'string' && scope.organisationId.trim() === '')) {\n const timeoutId = setTimeout(() => {\n setError(new Error('Organisation context is required for permission checks'));\n setIsLoading(false);\n }, 3000); // 3 seconds - typical permission check is < 1 second\n \n return () => clearTimeout(timeoutId);\n }\n // Clear error if organisation context becomes available\n if (error?.message === 'Organisation context is required for permission checks') {\n setError(null);\n }\n }, [scope.organisationId, error]);\n\n useEffect(() => {\n const fetchPermissions = async () => {\n // Prevent multiple simultaneous fetches\n if (isFetchingRef.current) {\n return;\n }\n\n if (!userId) {\n setPermissions({} as PermissionMap);\n setIsLoading(false);\n return;\n }\n\n // Don't fetch permissions if scope is invalid (e.g., organisationId is null/empty)\n // Wait for organisation context to resolve\n // IMPORTANT: Don't clear existing permissions here - keep them until we have new ones\n if (!scope.organisationId || scope.organisationId === null || (typeof scope.organisationId === 'string' && scope.organisationId.trim() === '')) {\n // Keep existing permissions, just mark as loading\n setIsLoading(true);\n setError(null);\n return;\n }\n\n try {\n isFetchingRef.current = true;\n setIsLoading(true);\n setError(null);\n \n // Fetch new permissions - don't clear old ones until we have new ones\n const permissionMap = await getPermissionMap({ userId, scope });\n \n // Only update permissions if fetch was successful\n setPermissions(permissionMap);\n } catch (err) {\n // On error, keep existing permissions but set error state\n // This prevents the UI from losing all items when there's a transient error\n console.error('[usePermissions] Failed to fetch permissions:', err);\n setError(err instanceof Error ? err : new Error('Failed to fetch permissions'));\n // Don't clear permissions on error - keep what we had\n } finally {\n setIsLoading(false);\n isFetchingRef.current = false;\n }\n };\n\n fetchPermissions();\n }, [userId, scope.organisationId, scope.eventId, scope.appId]);\n\n const hasPermission = useCallback((permission: Permission): boolean => {\n if (permissions['*']) {\n return true;\n }\n return permissions[permission] === true;\n }, [permissions]);\n\n const hasAnyPermission = useCallback((permissionList: Permission[]): boolean => {\n if (permissions['*']) {\n return true;\n }\n return permissionList.some(p => permissions[p] === true);\n }, [permissions]);\n\n const hasAllPermissions = useCallback((permissionList: Permission[]): boolean => {\n if (permissions['*']) {\n return true;\n }\n return permissionList.every(p => permissions[p] === true);\n }, [permissions]);\n\n const refetch = useCallback(async () => {\n // Prevent multiple simultaneous fetches\n if (isFetchingRef.current) {\n return;\n }\n\n if (!userId) {\n setPermissions({} as PermissionMap);\n setIsLoading(false);\n return;\n }\n\n // Don't fetch permissions if scope is invalid (e.g., organisationId is null/empty)\n // IMPORTANT: Don't clear existing permissions - keep them until we have new ones\n if (!scope.organisationId || scope.organisationId === null || (typeof scope.organisationId === 'string' && scope.organisationId.trim() === '')) {\n // Keep existing permissions, just mark as loading\n setIsLoading(true);\n setError(null);\n return;\n }\n\n try {\n isFetchingRef.current = true;\n setIsLoading(true);\n setError(null);\n \n // Fetch new permissions - don't clear old ones until we have new ones\n const permissionMap = await getPermissionMap({ userId, scope });\n \n // Only update permissions if fetch was successful\n setPermissions(permissionMap);\n } catch (err) {\n // On error, keep existing permissions but set error state\n // This prevents the UI from losing all items when there's a transient error\n console.error('[usePermissions] Failed to refetch permissions:', err);\n setError(err instanceof Error ? err : new Error('Failed to fetch permissions'));\n // Don't clear permissions on error - keep what we had\n } finally {\n setIsLoading(false);\n isFetchingRef.current = false;\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n permissions,\n isLoading,\n error,\n hasPermission,\n hasAnyPermission,\n hasAllPermissions,\n refetch\n }), [permissions, isLoading, error, hasPermission, hasAnyPermission, hasAllPermissions, refetch]);\n}\n\n/**\n * Hook to check if user can perform an action\n * \n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @param permission - Permission to check\n * @param pageId - Optional page ID\n * @param useCache - Whether to use cached results\n * @returns Permission check state and methods\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { can, isLoading, error } = useCan(userId, scope, 'read:users');\n * \n * if (isLoading) return <div>Checking permission...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return can ? <UserList /> : <div>Access denied</div>;\n * }\n * ```\n */\nexport function useCan(\n userId: UUID, \n scope: Scope, \n permission: Permission, \n pageId?: UUID,\n useCache: boolean = true\n) {\n const [can, setCan] = useState<boolean>(false);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Add timeout for missing organisation context (3 seconds)\n useEffect(() => {\n if (!scope.organisationId || scope.organisationId === null || (typeof scope.organisationId === 'string' && scope.organisationId.trim() === '')) {\n const timeoutId = setTimeout(() => {\n setError(new Error('Organisation context is required for permission checks'));\n setIsLoading(false);\n setCan(false);\n }, 3000); // 3 seconds - typical permission check is < 1 second\n \n return () => clearTimeout(timeoutId);\n }\n // Clear error if organisation context becomes available\n if (error?.message === 'Organisation context is required for permission checks') {\n setError(null);\n }\n }, [scope.organisationId, error]);\n\n // Use refs to track the last values to prevent unnecessary re-runs\n const lastUserIdRef = useRef<UUID | null>(null);\n const lastScopeRef = useRef<string | null>(null);\n const lastPermissionRef = useRef<Permission | null>(null);\n const lastPageIdRef = useRef<UUID | undefined | null>(null);\n const lastUseCacheRef = useRef<boolean | null>(null);\n\n useEffect(() => {\n // Create a scope key to track changes\n const scopeKey = `${scope.organisationId}-${scope.eventId}-${scope.appId}`;\n \n // Only run if something has actually changed\n if (\n lastUserIdRef.current !== userId ||\n lastScopeRef.current !== scopeKey ||\n lastPermissionRef.current !== permission ||\n lastPageIdRef.current !== pageId ||\n lastUseCacheRef.current !== useCache\n ) {\n lastUserIdRef.current = userId;\n lastScopeRef.current = scopeKey;\n lastPermissionRef.current = permission;\n lastPageIdRef.current = pageId;\n lastUseCacheRef.current = useCache;\n \n // Inline the permission check logic to avoid useCallback dependency issues\n const checkPermission = async () => {\n if (!userId) {\n setCan(false);\n setIsLoading(false);\n return;\n }\n\n // Don't check permissions if scope is invalid (e.g., organisationId is null/empty)\n // Wait for organisation context to resolve\n if (!scope.organisationId || scope.organisationId === null || (typeof scope.organisationId === 'string' && scope.organisationId.trim() === '')) {\n setIsLoading(true);\n setCan(false);\n setError(null);\n // Timeout is handled in separate useEffect (Phase 1.4)\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n const result = useCache \n ? await isPermittedCached({ userId, scope, permission, pageId })\n : await isPermitted({ userId, scope, permission, pageId });\n \n setCan(result);\n } catch (err) {\n console.error('[useCan] Permission check error:', { permission, error: err });\n setError(err instanceof Error ? err : new Error('Failed to check permission'));\n setCan(false);\n } finally {\n setIsLoading(false);\n }\n };\n \n checkPermission();\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId, permission, pageId, useCache]);\n\n const refetch = useCallback(async () => {\n if (!userId) {\n setCan(false);\n setIsLoading(false);\n return;\n }\n\n // Don't check permissions if scope is invalid (e.g., organisationId is null/empty)\n if (!scope.organisationId || scope.organisationId === null || (typeof scope.organisationId === 'string' && scope.organisationId.trim() === '')) {\n setCan(false);\n setIsLoading(true);\n setError(null);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n const result = useCache \n ? await isPermittedCached({ userId, scope, permission, pageId })\n : await isPermitted({ userId, scope, permission, pageId });\n \n setCan(result);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to check permission'));\n setCan(false);\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId, permission, pageId, useCache]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n can,\n isLoading,\n error,\n refetch\n }), [can, isLoading, error, refetch]);\n}\n\n/**\n * Hook to get user's access level in a scope\n * \n * @param userId - User ID\n * @param scope - Scope for access level checking\n * @returns Access level state and methods\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { accessLevel, isLoading, error } = useAccessLevel(userId, scope);\n * \n * if (isLoading) return <div>Loading access level...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return (\n * <div>\n * Access Level: {accessLevel}\n * {accessLevel >= AccessLevel.ADMIN && <AdminPanel />}\n * </div>\n * );\n * }\n * ```\n */\nexport function useAccessLevel(userId: UUID, scope: Scope): {\n accessLevel: AccessLevelType;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n} {\n const [accessLevel, setAccessLevel] = useState<AccessLevelType>('viewer');\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchAccessLevel = useCallback(async () => {\n if (!userId) {\n setAccessLevel('viewer');\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n const level = await getAccessLevel({ userId, scope });\n setAccessLevel(level);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to fetch access level'));\n setAccessLevel('viewer');\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId]);\n\n useEffect(() => {\n fetchAccessLevel();\n }, [fetchAccessLevel]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n accessLevel,\n isLoading,\n error,\n refetch: fetchAccessLevel\n }), [accessLevel, isLoading, error, fetchAccessLevel]);\n}\n\n/**\n * Hook to check multiple permissions at once\n * \n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @param permissions - Array of permissions to check\n * @param useCache - Whether to use cached results\n * @returns Multiple permission check results\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { results, isLoading, error } = useMultiplePermissions(\n * userId, \n * scope, \n * ['read:users', 'create:users', 'update:users']\n * );\n * \n * if (isLoading) return <div>Checking permissions...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return (\n * <div>\n * {results['read:users'] && <UserList />}\n * {results['create:users'] && <CreateUserButton />}\n * {results['update:users'] && <EditUserButton />}\n * </div>\n * );\n * }\n * ```\n */\nexport function useMultiplePermissions(\n userId: UUID, \n scope: Scope, \n permissions: Permission[],\n useCache: boolean = true\n): {\n results: Record<Permission, boolean>;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n} {\n const [results, setResults] = useState<Record<Permission, boolean>>({} as Record<Permission, boolean>);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const checkPermissions = useCallback(async () => {\n if (!userId || permissions.length === 0) {\n setResults({} as Record<Permission, boolean>);\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n const permissionResults: Record<Permission, boolean> = {} as Record<Permission, boolean>;\n \n // Check each permission\n for (const permission of permissions) {\n const result = useCache \n ? await isPermittedCached({ userId, scope, permission })\n : await isPermitted({ userId, scope, permission });\n permissionResults[permission] = result;\n }\n \n setResults(permissionResults);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to check permissions'));\n setResults({} as Record<Permission, boolean>);\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);\n\n useEffect(() => {\n checkPermissions();\n }, [checkPermissions]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n results,\n isLoading,\n error,\n refetch: checkPermissions\n }), [results, isLoading, error, checkPermissions]);\n}\n\n/**\n * Hook to check if user has any of the specified permissions\n * \n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @param permissions - Array of permissions to check\n * @param useCache - Whether to use cached results\n * @returns Whether user has any of the permissions\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { hasAny, isLoading, error } = useHasAnyPermission(\n * userId, \n * scope, \n * ['read:users', 'create:users']\n * );\n * \n * if (isLoading) return <div>Checking permissions...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return hasAny ? <UserManagementPanel /> : <div>No user permissions</div>;\n * }\n * ```\n */\nexport function useHasAnyPermission(\n userId: UUID, \n scope: Scope, \n permissions: Permission[],\n useCache: boolean = true\n): {\n hasAny: boolean;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n} {\n const [hasAny, setHasAny] = useState<boolean>(false);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const checkAnyPermission = useCallback(async () => {\n if (!userId || permissions.length === 0) {\n setHasAny(false);\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n let hasAnyPermission = false;\n \n for (const permission of permissions) {\n const result = useCache \n ? await isPermittedCached({ userId, scope, permission })\n : await isPermitted({ userId, scope, permission });\n \n if (result) {\n hasAnyPermission = true;\n break;\n }\n }\n \n setHasAny(hasAnyPermission);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to check permissions'));\n setHasAny(false);\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);\n\n useEffect(() => {\n checkAnyPermission();\n }, [checkAnyPermission]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n hasAny,\n isLoading,\n error,\n refetch: checkAnyPermission\n }), [hasAny, isLoading, error, checkAnyPermission]);\n}\n\n/**\n * Hook to check if user has all of the specified permissions\n * \n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @param permissions - Array of permissions to check\n * @param useCache - Whether to use cached results\n * @returns Whether user has all of the permissions\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { hasAll, isLoading, error } = useHasAllPermissions(\n * userId, \n * scope, \n * ['read:users', 'create:users', 'update:users']\n * );\n * \n * if (isLoading) return <div>Checking permissions...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return hasAll ? <FullUserManagementPanel /> : <div>Insufficient permissions</div>;\n * }\n * ```\n */\nexport function useHasAllPermissions(\n userId: UUID, \n scope: Scope, \n permissions: Permission[],\n useCache: boolean = true\n): {\n hasAll: boolean;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n} {\n const [hasAll, setHasAll] = useState<boolean>(false);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const checkAllPermissions = useCallback(async () => {\n if (!userId || permissions.length === 0) {\n setHasAll(false);\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n let hasAllPermissions = true;\n \n for (const permission of permissions) {\n const result = useCache \n ? await isPermittedCached({ userId, scope, permission })\n : await isPermitted({ userId, scope, permission });\n \n if (!result) {\n hasAllPermissions = false;\n break;\n }\n }\n \n setHasAll(hasAllPermissions);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to check permissions'));\n setHasAll(false);\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);\n\n useEffect(() => {\n checkAllPermissions();\n }, [checkAllPermissions]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n hasAll,\n isLoading,\n error,\n refetch: checkAllPermissions\n }), [hasAll, isLoading, error, checkAllPermissions]);\n}\n\n/**\n * Hook to get cached permissions with TTL management\n * \n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @returns Cached permission state and methods\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { permissions, isLoading, error, invalidateCache } = useCachedPermissions(userId, scope);\n * \n * if (isLoading) return <div>Loading cached permissions...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return (\n * <div>\n * {permissions['read:users'] && <UserList />}\n * <button onClick={invalidateCache}>Refresh Permissions</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useCachedPermissions(userId: UUID, scope: Scope): {\n permissions: PermissionMap;\n isLoading: boolean;\n error: Error | null;\n invalidateCache: () => void;\n refetch: () => Promise<void>;\n} {\n const [permissions, setPermissions] = useState<PermissionMap>({} as PermissionMap);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchCachedPermissions = useCallback(async () => {\n if (!userId) {\n setPermissions({} as PermissionMap);\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n const permissionMap = await getPermissionMap({ userId, scope });\n setPermissions(permissionMap);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to fetch cached permissions'));\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId]);\n\n const invalidateCache = useCallback(() => {\n // This would typically invalidate the cache in the actual implementation\n // For now, we'll just refetch\n fetchCachedPermissions();\n }, [fetchCachedPermissions]);\n\n useEffect(() => {\n fetchCachedPermissions();\n }, [fetchCachedPermissions]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n permissions,\n isLoading,\n error,\n invalidateCache,\n refetch: fetchCachedPermissions\n }), [permissions, isLoading, error, invalidateCache, fetchCachedPermissions]);\n}\n"],"mappings":"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","names":["error","useEffect","useState","useState","useEffect","error","useState","useEffect","useCallback","useMemo","useRef","useState","useRef","useEffect","useCallback","useMemo"]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
init_useOrganisationService,
|
|
4
4
|
useEventService2 as useEventService,
|
|
5
5
|
useOrganisationService2 as useOrganisationService
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-OO3V7W4H.js";
|
|
7
7
|
import {
|
|
8
8
|
__esm
|
|
9
9
|
} from "./chunk-PLDDJCW6.js";
|
|
@@ -57,4 +57,4 @@ export {
|
|
|
57
57
|
init_useOrganisations,
|
|
58
58
|
useEvents
|
|
59
59
|
};
|
|
60
|
-
//# sourceMappingURL=chunk-
|
|
60
|
+
//# sourceMappingURL=chunk-L36JW4KV.js.map
|
|
@@ -3,22 +3,22 @@ import {
|
|
|
3
3
|
useAccessLevel,
|
|
4
4
|
useCan,
|
|
5
5
|
useMultiplePermissions
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-I7JC7PTJ.js";
|
|
7
7
|
import {
|
|
8
8
|
OrganisationContextRequiredError,
|
|
9
9
|
RBACCache,
|
|
10
10
|
getRBACLogger,
|
|
11
11
|
rbacCache
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-TAJRS6YB.js";
|
|
13
13
|
import {
|
|
14
14
|
useSecureDataAccess
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-NEONKMTU.js";
|
|
16
16
|
import {
|
|
17
17
|
init_UnifiedAuthProvider
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-7H75SHXZ.js";
|
|
19
19
|
import {
|
|
20
20
|
useUnifiedAuth
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-OO3V7W4H.js";
|
|
22
22
|
import {
|
|
23
23
|
getCurrentAppName
|
|
24
24
|
} from "./chunk-JCQZ6LA7.js";
|
|
@@ -1539,7 +1539,7 @@ function withPermissionGuard(config, handler) {
|
|
|
1539
1539
|
if (!userId || !organisationId) {
|
|
1540
1540
|
throw new Error("User context required for permission check");
|
|
1541
1541
|
}
|
|
1542
|
-
const { isPermitted: isPermitted2 } = await import("./api-
|
|
1542
|
+
const { isPermitted: isPermitted2 } = await import("./api-QPMBZZUZ.js");
|
|
1543
1543
|
const hasPermission2 = await isPermitted2({
|
|
1544
1544
|
userId,
|
|
1545
1545
|
scope: { organisationId, eventId, appId },
|
|
@@ -1562,7 +1562,7 @@ function withAccessLevelGuard(minLevel, handler) {
|
|
|
1562
1562
|
if (!userId || !organisationId) {
|
|
1563
1563
|
throw new Error("User context required for access level check");
|
|
1564
1564
|
}
|
|
1565
|
-
const { getAccessLevel: getAccessLevel2 } = await import("./api-
|
|
1565
|
+
const { getAccessLevel: getAccessLevel2 } = await import("./api-QPMBZZUZ.js");
|
|
1566
1566
|
const accessLevel = await getAccessLevel2({
|
|
1567
1567
|
userId,
|
|
1568
1568
|
scope: { organisationId, eventId, appId }
|
|
@@ -1587,11 +1587,11 @@ function withRoleGuard(config, handler) {
|
|
|
1587
1587
|
throw new Error("User context required for role check");
|
|
1588
1588
|
}
|
|
1589
1589
|
if (config.globalRoles && config.globalRoles.length > 0) {
|
|
1590
|
-
const { isSuperAdmin } = await import("./api-
|
|
1590
|
+
const { isSuperAdmin } = await import("./api-QPMBZZUZ.js");
|
|
1591
1591
|
const isSuper = await isSuperAdmin(userId);
|
|
1592
1592
|
if (isSuper) {
|
|
1593
1593
|
if (organisationId) {
|
|
1594
|
-
const { emitAuditEvent: emitAuditEvent2 } = await import("./audit-
|
|
1594
|
+
const { emitAuditEvent: emitAuditEvent2 } = await import("./audit-H4YJJF7R.js");
|
|
1595
1595
|
await emitAuditEvent2({
|
|
1596
1596
|
type: "permission_check",
|
|
1597
1597
|
userId,
|
|
@@ -1613,21 +1613,21 @@ function withRoleGuard(config, handler) {
|
|
|
1613
1613
|
}
|
|
1614
1614
|
}
|
|
1615
1615
|
if (config.organisationRoles && config.organisationRoles.length > 0) {
|
|
1616
|
-
const { isOrganisationAdmin } = await import("./api-
|
|
1616
|
+
const { isOrganisationAdmin } = await import("./api-QPMBZZUZ.js");
|
|
1617
1617
|
const isOrgAdmin = await isOrganisationAdmin(userId, organisationId);
|
|
1618
1618
|
if (!isOrgAdmin && config.requireAll !== false) {
|
|
1619
1619
|
throw new Error(`Organisation admin role required`);
|
|
1620
1620
|
}
|
|
1621
1621
|
}
|
|
1622
1622
|
if (config.eventAppRoles && config.eventAppRoles.length > 0 && eventId && appId) {
|
|
1623
|
-
const { isEventAdmin } = await import("./api-
|
|
1623
|
+
const { isEventAdmin } = await import("./api-QPMBZZUZ.js");
|
|
1624
1624
|
const isEventAdminUser = await isEventAdmin(userId, { organisationId, eventId, appId });
|
|
1625
1625
|
if (!isEventAdminUser && config.requireAll !== false) {
|
|
1626
1626
|
throw new Error(`Event admin role required`);
|
|
1627
1627
|
}
|
|
1628
1628
|
}
|
|
1629
1629
|
if (organisationId) {
|
|
1630
|
-
const { emitAuditEvent: emitAuditEvent2 } = await import("./audit-
|
|
1630
|
+
const { emitAuditEvent: emitAuditEvent2 } = await import("./audit-H4YJJF7R.js");
|
|
1631
1631
|
await emitAuditEvent2({
|
|
1632
1632
|
type: "permission_check",
|
|
1633
1633
|
userId,
|
|
@@ -1660,7 +1660,7 @@ function createRBACMiddleware(config) {
|
|
|
1660
1660
|
);
|
|
1661
1661
|
if (protectedRoute) {
|
|
1662
1662
|
try {
|
|
1663
|
-
const { isPermitted: isPermitted2 } = await import("./api-
|
|
1663
|
+
const { isPermitted: isPermitted2 } = await import("./api-QPMBZZUZ.js");
|
|
1664
1664
|
const hasPermission2 = await isPermitted2({
|
|
1665
1665
|
userId,
|
|
1666
1666
|
scope: { organisationId },
|
|
@@ -1687,7 +1687,7 @@ function createRBACExpressMiddleware(config) {
|
|
|
1687
1687
|
return res.status(401).json({ error: "User context required" });
|
|
1688
1688
|
}
|
|
1689
1689
|
try {
|
|
1690
|
-
const { isPermitted: isPermitted2 } = await import("./api-
|
|
1690
|
+
const { isPermitted: isPermitted2 } = await import("./api-QPMBZZUZ.js");
|
|
1691
1691
|
const hasPermission2 = await isPermitted2({
|
|
1692
1692
|
userId,
|
|
1693
1693
|
scope: { organisationId, eventId, appId },
|
|
@@ -1860,4 +1860,4 @@ export {
|
|
|
1860
1860
|
getPermissionsForRole,
|
|
1861
1861
|
ALL_PERMISSIONS
|
|
1862
1862
|
};
|
|
1863
|
-
//# sourceMappingURL=chunk-
|
|
1863
|
+
//# sourceMappingURL=chunk-MNSGWRPB.js.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
init_useOrganisations,
|
|
3
3
|
useOrganisations
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-L36JW4KV.js";
|
|
5
5
|
import {
|
|
6
6
|
useUnifiedAuth
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OO3V7W4H.js";
|
|
8
8
|
import {
|
|
9
9
|
init_organisationContext,
|
|
10
10
|
setOrganisationContext
|
|
@@ -380,4 +380,4 @@ function useSecureDataAccess() {
|
|
|
380
380
|
export {
|
|
381
381
|
useSecureDataAccess
|
|
382
382
|
};
|
|
383
|
-
//# sourceMappingURL=chunk-
|
|
383
|
+
//# sourceMappingURL=chunk-NEONKMTU.js.map
|
|
@@ -1298,7 +1298,7 @@ var init_EventService = __esm({
|
|
|
1298
1298
|
// Lifecycle methods
|
|
1299
1299
|
async initialize() {
|
|
1300
1300
|
await super.initialize();
|
|
1301
|
-
await this.fetchEvents(
|
|
1301
|
+
await this.fetchEvents(false);
|
|
1302
1302
|
}
|
|
1303
1303
|
cleanup() {
|
|
1304
1304
|
super.cleanup();
|
|
@@ -2430,4 +2430,4 @@ export {
|
|
|
2430
2430
|
UnifiedAuthProvider,
|
|
2431
2431
|
init_UnifiedAuthProvider
|
|
2432
2432
|
};
|
|
2433
|
-
//# sourceMappingURL=chunk-
|
|
2433
|
+
//# sourceMappingURL=chunk-OO3V7W4H.js.map
|