@jmruthers/pace-core 0.5.110 → 0.5.111

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 (230) hide show
  1. package/dist/{AuthService-DrHrvXNZ.d.ts → AuthService-CVgsgtaZ.d.ts} +8 -0
  2. package/dist/{DataTable-D3BK2FCN.js → DataTable-5W2HVLLV.js} +8 -8
  3. package/dist/{UnifiedAuthProvider-A7I23UCN.js → UnifiedAuthProvider-LUM3QLS5.js} +3 -3
  4. package/dist/{api-PIE4JRFS.js → api-SIZPFBFX.js} +5 -3
  5. package/dist/{audit-65VNHEV2.js → audit-5JI5T3SL.js} +2 -2
  6. package/dist/{chunk-3J5N2T2N.js → chunk-2BIDKXQU.js} +113 -116
  7. package/dist/chunk-2BIDKXQU.js.map +1 -0
  8. package/dist/{chunk-AWK2FAUN.js → chunk-ACYQNYHB.js} +7 -7
  9. package/dist/{chunk-D6MEKC27.js → chunk-EFVQBYFN.js} +2 -2
  10. package/dist/{chunk-EZ64QG2I.js → chunk-I5YM5BGS.js} +2 -2
  11. package/dist/{chunk-Q7APDV6H.js → chunk-IWJYNWXN.js} +13 -5
  12. package/dist/chunk-IWJYNWXN.js.map +1 -0
  13. package/dist/{chunk-YFMENCR4.js → chunk-JE2GFA3O.js} +3 -3
  14. package/dist/{chunk-AUXS7XSO.js → chunk-MW73E7SP.js} +35 -11
  15. package/dist/chunk-MW73E7SP.js.map +1 -0
  16. package/dist/{chunk-XRSP3H52.js → chunk-PXXS26G5.js} +57 -23
  17. package/dist/chunk-PXXS26G5.js.map +1 -0
  18. package/dist/{chunk-HGZSO43Y.js → chunk-TD4BXGPE.js} +4 -4
  19. package/dist/{chunk-EYSXQ756.js → chunk-TDFBX7KJ.js} +2 -2
  20. package/dist/{chunk-HADXAZT3.js → chunk-UGVU7L7N.js} +52 -90
  21. package/dist/chunk-UGVU7L7N.js.map +1 -0
  22. package/dist/{chunk-2W4WKJVF.js → chunk-X7SPKHYZ.js} +290 -255
  23. package/dist/chunk-X7SPKHYZ.js.map +1 -0
  24. package/dist/{chunk-7GBEBJLR.js → chunk-ZL45MG76.js} +45 -37
  25. package/dist/chunk-ZL45MG76.js.map +1 -0
  26. package/dist/components.js +10 -10
  27. package/dist/hooks.d.ts +11 -1
  28. package/dist/hooks.js +9 -7
  29. package/dist/hooks.js.map +1 -1
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +13 -13
  32. package/dist/providers.d.ts +2 -2
  33. package/dist/providers.js +2 -2
  34. package/dist/rbac/index.d.ts +13 -8
  35. package/dist/rbac/index.js +9 -9
  36. package/dist/utils.js +1 -1
  37. package/docs/api/classes/ColumnFactory.md +1 -1
  38. package/docs/api/classes/ErrorBoundary.md +1 -1
  39. package/docs/api/classes/InvalidScopeError.md +4 -4
  40. package/docs/api/classes/MissingUserContextError.md +4 -4
  41. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  42. package/docs/api/classes/PermissionDeniedError.md +4 -4
  43. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  44. package/docs/api/classes/RBACAuditManager.md +8 -8
  45. package/docs/api/classes/RBACCache.md +8 -8
  46. package/docs/api/classes/RBACEngine.md +4 -4
  47. package/docs/api/classes/RBACError.md +4 -4
  48. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  49. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  50. package/docs/api/classes/StorageUtils.md +1 -1
  51. package/docs/api/enums/FileCategory.md +1 -1
  52. package/docs/api/interfaces/AggregateConfig.md +1 -1
  53. package/docs/api/interfaces/ButtonProps.md +1 -1
  54. package/docs/api/interfaces/CardProps.md +1 -1
  55. package/docs/api/interfaces/ColorPalette.md +1 -1
  56. package/docs/api/interfaces/ColorShade.md +1 -1
  57. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  58. package/docs/api/interfaces/DataRecord.md +1 -1
  59. package/docs/api/interfaces/DataTableAction.md +1 -1
  60. package/docs/api/interfaces/DataTableColumn.md +1 -1
  61. package/docs/api/interfaces/DataTableProps.md +1 -1
  62. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  63. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  64. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  65. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  66. package/docs/api/interfaces/FileMetadata.md +1 -1
  67. package/docs/api/interfaces/FileReference.md +1 -1
  68. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  69. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  70. package/docs/api/interfaces/FileUploadProps.md +1 -1
  71. package/docs/api/interfaces/FooterProps.md +1 -1
  72. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  73. package/docs/api/interfaces/InputProps.md +1 -1
  74. package/docs/api/interfaces/LabelProps.md +1 -1
  75. package/docs/api/interfaces/LoginFormProps.md +1 -1
  76. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  77. package/docs/api/interfaces/NavigationContextType.md +1 -1
  78. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  79. package/docs/api/interfaces/NavigationItem.md +1 -1
  80. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  81. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  82. package/docs/api/interfaces/Organisation.md +1 -1
  83. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  84. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  85. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  86. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  87. package/docs/api/interfaces/PaceAppLayoutProps.md +27 -27
  88. package/docs/api/interfaces/PaceLoginPageProps.md +4 -4
  89. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  90. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  91. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  92. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  93. package/docs/api/interfaces/PaletteData.md +1 -1
  94. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  95. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  96. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  97. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  98. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  99. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  100. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  101. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  102. package/docs/api/interfaces/RBACConfig.md +1 -1
  103. package/docs/api/interfaces/RBACLogger.md +1 -1
  104. package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
  105. package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
  106. package/docs/api/interfaces/RouteAccessRecord.md +10 -10
  107. package/docs/api/interfaces/RouteConfig.md +19 -6
  108. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  109. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  110. package/docs/api/interfaces/StorageConfig.md +1 -1
  111. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  112. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  113. package/docs/api/interfaces/StorageListOptions.md +1 -1
  114. package/docs/api/interfaces/StorageListResult.md +1 -1
  115. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  116. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  117. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  118. package/docs/api/interfaces/StyleImport.md +1 -1
  119. package/docs/api/interfaces/SwitchProps.md +1 -1
  120. package/docs/api/interfaces/ToastActionElement.md +1 -1
  121. package/docs/api/interfaces/ToastProps.md +1 -1
  122. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  123. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  124. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  125. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  126. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  127. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  128. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  129. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  130. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  131. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  132. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  133. package/docs/api/interfaces/UserEventAccess.md +1 -1
  134. package/docs/api/interfaces/UserMenuProps.md +1 -1
  135. package/docs/api/interfaces/UserProfile.md +1 -1
  136. package/docs/api/modules.md +36 -36
  137. package/docs/api-reference/hooks.md +8 -4
  138. package/docs/architecture/rpc-function-standards.md +3 -1
  139. package/docs/best-practices/common-patterns.md +3 -3
  140. package/docs/best-practices/deployment.md +10 -4
  141. package/docs/best-practices/performance.md +11 -3
  142. package/docs/core-concepts/organisations.md +8 -8
  143. package/docs/core-concepts/permissions.md +133 -72
  144. package/docs/migration/rbac-migration.md +65 -66
  145. package/docs/rbac/advanced-patterns.md +15 -22
  146. package/docs/rbac/examples.md +12 -12
  147. package/docs/rbac/getting-started.md +3 -3
  148. package/docs/rbac/troubleshooting.md +2 -1
  149. package/package.json +1 -1
  150. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +913 -0
  151. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +609 -0
  152. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +434 -0
  153. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +120 -0
  154. package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +519 -0
  155. package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +316 -0
  156. package/src/components/DataTable/examples/__tests__/InitialPageSizeExample.test.tsx +211 -0
  157. package/src/components/FileUpload/FileUpload.tsx +2 -8
  158. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +193 -63
  159. package/src/components/PaceAppLayout/PaceAppLayout.tsx +102 -135
  160. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +41 -2
  161. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +61 -6
  162. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +71 -21
  163. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +113 -41
  164. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +155 -45
  165. package/src/components/PaceLoginPage/PaceLoginPage.tsx +30 -1
  166. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +63 -5
  167. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +156 -72
  168. package/src/hooks/__tests__/useRBAC.unit.test.ts +4 -38
  169. package/src/hooks/index.ts +1 -1
  170. package/src/hooks/useFileDisplay.ts +51 -0
  171. package/src/hooks/usePermissionCache.test.ts +112 -68
  172. package/src/hooks/usePermissionCache.ts +55 -15
  173. package/src/rbac/README.md +81 -39
  174. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +3 -3
  175. package/src/rbac/__tests__/engine.comprehensive.test.ts +15 -6
  176. package/src/rbac/__tests__/rbac-core.test.tsx +1 -1
  177. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +57 -4
  178. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +3 -2
  179. package/src/rbac/adapters.tsx +4 -4
  180. package/src/rbac/api.test.ts +37 -13
  181. package/src/rbac/api.ts +25 -8
  182. package/src/rbac/audit.test.ts +2 -2
  183. package/src/rbac/audit.ts +14 -5
  184. package/src/rbac/cache.test.ts +12 -0
  185. package/src/rbac/cache.ts +29 -9
  186. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +1 -1
  187. package/src/rbac/components/NavigationGuard.tsx +14 -14
  188. package/src/rbac/components/NavigationProvider.test.tsx +1 -1
  189. package/src/rbac/components/PagePermissionGuard.tsx +4 -3
  190. package/src/rbac/components/PagePermissionProvider.test.tsx +1 -1
  191. package/src/rbac/components/PermissionEnforcer.tsx +19 -15
  192. package/src/rbac/components/RoleBasedRouter.tsx +16 -9
  193. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +123 -107
  194. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +1 -1
  195. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +121 -103
  196. package/src/rbac/docs/event-based-apps.md +6 -6
  197. package/src/rbac/engine.ts +12 -2
  198. package/src/rbac/hooks/useCan.test.ts +29 -2
  199. package/src/rbac/hooks/usePermissions.test.ts +25 -25
  200. package/src/rbac/hooks/usePermissions.ts +47 -23
  201. package/src/rbac/hooks/useRBAC.simple.test.ts +1 -8
  202. package/src/rbac/hooks/useRBAC.test.ts +3 -40
  203. package/src/rbac/hooks/useRBAC.ts +0 -55
  204. package/src/rbac/hooks/useResolvedScope.ts +23 -31
  205. package/src/rbac/permissions.test.ts +11 -7
  206. package/src/rbac/security.test.ts +2 -2
  207. package/src/rbac/security.ts +22 -7
  208. package/src/rbac/types.test.ts +2 -2
  209. package/src/rbac/types.ts +1 -2
  210. package/src/services/EventService.ts +41 -13
  211. package/src/services/__tests__/EventService.test.ts +25 -4
  212. package/src/services/interfaces/IEventService.ts +1 -0
  213. package/src/utils/file-reference.ts +9 -0
  214. package/dist/chunk-2W4WKJVF.js.map +0 -1
  215. package/dist/chunk-3J5N2T2N.js.map +0 -1
  216. package/dist/chunk-7GBEBJLR.js.map +0 -1
  217. package/dist/chunk-AUXS7XSO.js.map +0 -1
  218. package/dist/chunk-HADXAZT3.js.map +0 -1
  219. package/dist/chunk-Q7APDV6H.js.map +0 -1
  220. package/dist/chunk-XRSP3H52.js.map +0 -1
  221. /package/dist/{DataTable-D3BK2FCN.js.map → DataTable-5W2HVLLV.js.map} +0 -0
  222. /package/dist/{UnifiedAuthProvider-A7I23UCN.js.map → UnifiedAuthProvider-LUM3QLS5.js.map} +0 -0
  223. /package/dist/{api-PIE4JRFS.js.map → api-SIZPFBFX.js.map} +0 -0
  224. /package/dist/{audit-65VNHEV2.js.map → audit-5JI5T3SL.js.map} +0 -0
  225. /package/dist/{chunk-AWK2FAUN.js.map → chunk-ACYQNYHB.js.map} +0 -0
  226. /package/dist/{chunk-D6MEKC27.js.map → chunk-EFVQBYFN.js.map} +0 -0
  227. /package/dist/{chunk-EZ64QG2I.js.map → chunk-I5YM5BGS.js.map} +0 -0
  228. /package/dist/{chunk-YFMENCR4.js.map → chunk-JE2GFA3O.js.map} +0 -0
  229. /package/dist/{chunk-HGZSO43Y.js.map → chunk-TD4BXGPE.js.map} +0 -0
  230. /package/dist/{chunk-EYSXQ756.js.map → chunk-TDFBX7KJ.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/rbac/types.ts","../src/rbac/cache.ts","../src/rbac/cache-invalidation.ts","../src/rbac/errors.ts","../src/rbac/security.ts","../src/rbac/engine.ts","../src/rbac/config.ts","../src/rbac/api.ts"],"sourcesContent":["/**\n * RBAC (Role-Based Access Control) Types - Build Contract Compliant\n * @package @jmruthers/pace-core\n * @module RBAC/Types\n * @since 1.0.0\n * \n * This module defines the core types for the RBAC system that match the build contract exactly.\n * All types are designed to be framework-agnostic and provide strong typing for permission operations.\n */\n\nimport type React from 'react';\n\n// ============================================================================\n// CORE TYPES\n// ============================================================================\n\nexport type UUID = string;\n\nexport type Operation = 'read' | 'create' | 'update' | 'delete';\n\nexport type Permission = `${Operation}:${string}`; // e.g. \"read:base.events\" or \"create:team.members\"\n\nexport type AccessLevel =\n | 'viewer'\n | 'participant'\n | 'planner'\n | 'admin'\n | 'super';\n\nexport type Scope = {\n organisationId?: UUID;\n eventId?: string; // event_id is text/varchar\n appId?: UUID;\n};\n\nexport type PermissionCheck = {\n userId: UUID;\n scope: Scope;\n permission: Permission;\n pageId?: UUID | string;\n};\n\nexport type PermissionMap = Record<Permission, boolean> & Partial<Record<'*', boolean>>;\n\n// ============================================================================\n// ROLE TYPES\n// ============================================================================\n\nexport type GlobalRole = 'super_admin';\n\nexport type OrganisationRole = 'supporter' | 'member' | 'leader' | 'org_admin';\n\nexport type EventAppRole = 'viewer' | 'participant' | 'planner' | 'event_admin';\n\n// ============================================================================\n// DATABASE TYPES\n// ============================================================================\n\nexport interface RBACGlobalRole {\n id: UUID;\n user_id: UUID;\n role: GlobalRole;\n granted_at: string;\n granted_by: UUID | null;\n valid_from: string;\n valid_to: string | null;\n}\n\nexport interface RBACOrganisationRole {\n id: UUID;\n user_id: UUID;\n organisation_id: UUID;\n role: OrganisationRole;\n status: 'active' | 'inactive' | 'suspended';\n granted_at: string;\n granted_by: UUID | null;\n revoked_at: string | null;\n revoked_by: UUID | null;\n notes: string | null;\n created_at: string;\n updated_at: string;\n valid_from: string;\n valid_to: string | null;\n}\n\nexport interface RBACEventAppRole {\n id: UUID;\n user_id: UUID;\n event_id: string;\n role: EventAppRole;\n status: 'active' | 'inactive' | 'suspended';\n granted_at: string;\n granted_by: UUID | null;\n organisation_id: UUID;\n app_id: UUID;\n valid_from: string;\n valid_to: string | null;\n}\n\nexport interface RBACPagePermission {\n id: UUID;\n app_page_id: UUID;\n operation: Operation;\n role_name: string;\n allowed: boolean;\n created_at: string;\n updated_at: string;\n organisation_id: UUID;\n}\n\nexport interface RBACAppPage {\n id: UUID;\n page_name: string;\n page_description: string | null;\n created_at: string;\n updated_at: string;\n created_by: UUID | null;\n updated_by: UUID | null;\n app_id: UUID;\n}\n\nexport interface RBACApp {\n id: UUID;\n name: string;\n display_name: string;\n description: string | null;\n requires_event: boolean;\n is_active: boolean;\n created_at: string;\n updated_at: string;\n created_by: UUID | null;\n updated_by: UUID | null;\n}\n\n// ============================================================================\n// AUDIT EVENT TYPES\n// ============================================================================\n\nexport type AuditEventType = \n | 'permission_check'\n | 'permission_denied'\n | 'role_granted'\n | 'role_denied'\n | 'rls_denied';\n\nexport type AuditEventSource = 'api' | 'ui' | 'middleware' | 'rls';\n\nexport interface RBACAuditEvent {\n id: UUID;\n event_type: AuditEventType;\n user_id: UUID;\n organisation_id: UUID | null; // Nullable to properly track missing context cases (should be rare since organisationId is required)\n event_id?: string;\n app_id?: UUID;\n page_id?: UUID;\n permission?: string;\n decision?: boolean;\n source?: AuditEventSource;\n bypass?: boolean;\n duration_ms?: number;\n metadata: Record<string, any>;\n created_at: string;\n}\n\nexport interface RBACAppContext {\n appId: UUID;\n hasAccess: boolean;\n}\n\nexport interface RBACRoleContext {\n globalRole: GlobalRole | null;\n organisationRole: OrganisationRole | null;\n eventAppRole: EventAppRole | null;\n}\n\n// ============================================================================\n// CACHE TYPES\n// ============================================================================\n\nexport interface CacheEntry<T> {\n data: T;\n expires: number;\n}\n\nexport interface PermissionCacheKey {\n userId: UUID;\n organisationId?: UUID;\n eventId?: string;\n appId?: UUID;\n permission?: Permission;\n pageId?: UUID | string;\n}\n\n// ============================================================================\n// API TYPES\n// ============================================================================\n\nexport interface GetAccessLevelInput {\n userId: UUID;\n scope: Scope;\n}\n\nexport interface GetPermissionMapInput {\n userId: UUID;\n scope: Scope;\n}\n\nexport interface IsPermittedInput extends PermissionCheck {}\n\n// ============================================================================\n// HOOK TYPES\n// ============================================================================\n\nexport interface UsePermissionsReturn {\n permissions: PermissionMap;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n}\n\nexport interface UseCanReturn {\n can: boolean;\n isLoading: boolean;\n error: Error | null;\n check: () => Promise<void>;\n}\n\n// ============================================================================\n// ADAPTER TYPES\n// ============================================================================\n\nexport interface PermissionGuardConfig {\n permission: Permission;\n pageId?: UUID;\n}\n\nexport interface WithPermissionGuardOptions {\n permission: Permission;\n pageId?: UUID;\n fallback?: React.ReactNode;\n onDenied?: () => void;\n}\n\n// ============================================================================\n// HOOK RETURN TYPES\n// ============================================================================\n\nexport interface UserRBACContext {\n user: any; // User from auth context\n globalRole: GlobalRole | null;\n organisationRole: OrganisationRole | null;\n eventAppRole: EventAppRole | null;\n hasGlobalPermission: (permission: Permission) => boolean;\n isSuperAdmin: boolean;\n isOrgAdmin: boolean;\n isEventAdmin: boolean;\n canManageOrganisation: boolean;\n canManageEvent: boolean;\n isLoading: boolean;\n error: Error | null;\n}\n\nexport interface RBACPermission {\n permission_type: string;\n role_name: string;\n [key: string]: any;\n}\n\n// ============================================================================\n// COMPONENT TYPES\n// ============================================================================\n\nexport interface RBACGuardProps {\n children: React.ReactNode;\n operation: Operation;\n pageId?: UUID;\n fallback?: React.ReactNode;\n}\n\nexport interface RoleBasedContentProps {\n children: React.ReactNode;\n globalRoles?: GlobalRole[];\n organisationRoles?: OrganisationRole[];\n eventAppRoles?: EventAppRole[];\n fallback?: React.ReactNode;\n}\n\n// ============================================================================\n// ERROR TYPES\n// ============================================================================\n\nexport class RBACError extends Error {\n constructor(\n message: string,\n public code: string,\n public context?: Record<string, any>\n ) {\n super(message);\n this.name = 'RBACError';\n }\n}\n\nexport class PermissionDeniedError extends RBACError {\n constructor(permission: Permission, context?: Record<string, any>) {\n super(\n `Permission denied: ${permission}`,\n 'PERMISSION_DENIED',\n { permission, ...context }\n );\n this.name = 'PermissionDeniedError';\n }\n}\n\nexport class OrganisationContextRequiredError extends RBACError {\n constructor() {\n super(\n 'Organisation context is required for this operation',\n 'ORGANISATION_CONTEXT_REQUIRED'\n );\n this.name = 'OrganisationContextRequiredError';\n }\n}\n\nexport class RBACNotInitializedError extends RBACError {\n constructor() {\n super(\n 'RBAC system not initialized. Please call setupRBAC(supabase) before using any RBAC components or hooks. See: https://docs.pace-core.dev/rbac/setup',\n 'RBAC_NOT_INITIALIZED'\n );\n this.name = 'RBACNotInitializedError';\n }\n}\n\nexport class InvalidScopeError extends RBACError {\n constructor(scope: Scope, reason: string) {\n super(\n `Invalid scope provided: ${JSON.stringify(scope)}. ${reason}`,\n 'INVALID_SCOPE',\n { scope, reason }\n );\n this.name = 'InvalidScopeError';\n }\n}\n\nexport class MissingUserContextError extends RBACError {\n constructor() {\n super(\n 'User context is required but not available. Make sure to wrap your app with an auth provider.',\n 'MISSING_USER_CONTEXT'\n );\n this.name = 'MissingUserContextError';\n }\n}\n","/**\n * RBAC Cache Implementation\n * @package @jmruthers/pace-core\n * @module RBAC/Cache\n * @since 1.0.0\n * \n * This module provides caching functionality for RBAC operations with TTL and invalidation.\n */\n\nimport { UUID } from './types';\nimport { CacheEntry, PermissionCacheKey } from './types';\n\n/**\n * In-memory cache for RBAC operations\n * \n * Provides 60-second TTL and pattern-based invalidation for permission checks.\n */\nexport class RBACCache {\n private cache = new Map<string, CacheEntry<any>>();\n private readonly TTL = 60 * 1000; // 60 seconds\n private invalidationCallbacks: Set<(pattern: string) => void> = new Set();\n\n /**\n * Get a value from the cache\n * \n * @param key - Cache key\n * @returns Cached value or null if not found/expired\n */\n get<T>(key: string): T | null {\n const entry = this.cache.get(key);\n \n if (!entry) {\n return null;\n }\n\n if (Date.now() > entry.expires) {\n this.cache.delete(key);\n return null;\n }\n\n return entry.data as T;\n }\n\n /**\n * Set a value in the cache\n * \n * @param key - Cache key\n * @param data - Data to cache\n * @param ttl - Time to live in milliseconds (defaults to 60s)\n */\n set<T>(key: string, data: T, ttl: number = this.TTL): void {\n // For zero or negative TTL, set expires to current time to make it immediately expired\n const expires = ttl <= 0 ? Date.now() - 1 : Date.now() + ttl;\n this.cache.set(key, {\n data,\n expires,\n });\n }\n\n /**\n * Delete a specific key from the cache\n * \n * @param key - Cache key to delete\n */\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n /**\n * Invalidate cache entries matching a pattern\n * \n * @param pattern - Pattern to match against cache keys\n */\n invalidate(pattern: string): void {\n const trimmedPattern = pattern?.trim();\n\n if (!trimmedPattern) {\n return;\n }\n\n const matcher = this.createMatcher(trimmedPattern);\n const keysToDelete: string[] = [];\n\n for (const key of this.cache.keys()) {\n if (matcher(key)) {\n keysToDelete.push(key);\n }\n }\n\n keysToDelete.forEach(key => this.cache.delete(key));\n\n // Notify invalidation callbacks\n this.invalidationCallbacks.forEach(callback => callback(trimmedPattern));\n }\n\n private createMatcher(pattern: string): (key: string) => boolean {\n if (pattern.includes('*')) {\n const escapedSegments = pattern\n .split('*')\n .map(segment => segment.replace(/[|\\\\{}()[\\]^$+?.-]/g, '\\\\$&'));\n const regexPattern = escapedSegments.join('.*');\n const regex = new RegExp(regexPattern);\n return (key: string) => regex.test(key);\n }\n\n return (key: string) => key.includes(pattern);\n }\n\n /**\n * Clear all cache entries\n */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Get cache statistics\n */\n getStats(): {\n size: number;\n ttl: number;\n keys: string[];\n } {\n return {\n size: this.cache.size,\n ttl: this.TTL,\n keys: Array.from(this.cache.keys()),\n };\n }\n\n /**\n * Add an invalidation callback\n * \n * @param callback - Function to call when cache is invalidated\n */\n onInvalidate(callback: (pattern: string) => void): () => void {\n this.invalidationCallbacks.add(callback);\n \n // Return unsubscribe function\n return () => {\n this.invalidationCallbacks.delete(callback);\n };\n }\n\n /**\n * Generate cache key for permission check (simplified signature)\n * \n * @param userId - User ID\n * @param permission - Permission string\n * @param organisationId - Organisation ID (optional)\n * @param eventId - Event ID (optional)\n * @param appId - App ID (optional)\n * @param pageId - Page ID (optional)\n * @returns String cache key\n */\n static generateKey(\n userId: UUID,\n permission: string,\n organisationId?: UUID,\n eventId?: string,\n appId?: UUID,\n pageId?: UUID | string\n ): string {\n const parts = [\n 'perm',\n userId,\n organisationId || 'null',\n eventId || 'null',\n appId || 'null',\n permission || 'null',\n pageId || 'null',\n ];\n \n return parts.join(':');\n }\n\n /**\n * Generate cache key for permission check (object signature)\n * \n * @param key - Permission cache key object\n * @returns String cache key\n */\n static generatePermissionKey(key: PermissionCacheKey): string {\n const parts = [\n 'perm',\n key.userId,\n key.organisationId || 'null',\n key.eventId || 'null',\n key.appId || 'null',\n key.permission || 'null',\n key.pageId || 'null',\n ];\n \n return parts.join(':');\n }\n\n /**\n * Generate cache key for access level\n * \n * @param userId - User ID\n * @param organisationId - Organisation ID\n * @param eventId - Event ID (optional)\n * @param appId - App ID (optional)\n * @returns String cache key\n */\n static generateAccessLevelKey(\n userId: UUID,\n organisationId: UUID,\n eventId?: string,\n appId?: UUID\n ): string {\n const parts = [\n 'access',\n userId,\n organisationId,\n eventId || 'null',\n appId || 'null',\n ];\n \n return parts.join(':');\n }\n\n /**\n * Generate cache key for permission map\n * \n * @param userId - User ID\n * @param organisationId - Organisation ID\n * @param eventId - Event ID (optional)\n * @param appId - App ID (optional)\n * @returns String cache key\n */\n static generatePermissionMapKey(\n userId: UUID,\n organisationId: UUID,\n eventId?: string,\n appId?: UUID\n ): string {\n const parts = [\n 'map',\n userId,\n organisationId,\n eventId || 'null',\n appId || 'null',\n ];\n \n return parts.join(':');\n }\n}\n\n/**\n * Global cache instance\n * \n * This is the default cache instance used by the RBAC system.\n * You can create additional instances if needed for different contexts.\n */\nexport const rbacCache = new RBACCache();\n\n/**\n * Cache key patterns for invalidation\n */\nexport const CACHE_PATTERNS = {\n USER: (userId: UUID) => `:${userId}:`,\n ORGANISATION: (organisationId: UUID) => `:${organisationId}:`,\n EVENT: (eventId: string) => `:${eventId}:`,\n APP: (appId: UUID) => `:${appId}`,\n PERMISSION: (userId: UUID, organisationId: UUID) => `perm:${userId}:${organisationId}:`,\n} as const;\n","/**\n * RBAC Cache Invalidation Service\n * @package @jmruthers/pace-core\n * @module RBAC/CacheInvalidation\n * @since 1.0.0\n * \n * This module provides automatic cache invalidation when RBAC data changes.\n */\n\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../types/database';\nimport { rbacCache, CACHE_PATTERNS } from './cache';\nimport { emitAuditEvent } from './audit';\nimport { UUID } from './types';\n\n/**\n * Cache invalidation patterns for different RBAC changes\n */\nexport const INVALIDATION_PATTERNS = {\n // User-level invalidation\n USER_ROLES_CHANGED: (userId: UUID) => [\n CACHE_PATTERNS.USER(userId),\n `perm:${userId}:*`,\n `access:${userId}:*`,\n `map:${userId}:*`\n ],\n \n // Organisation-level invalidation\n ORGANISATION_PERMISSIONS_CHANGED: (organisationId: UUID) => [\n CACHE_PATTERNS.ORGANISATION(organisationId),\n `perm:*:${organisationId}:*`,\n `access:*:${organisationId}:*`,\n `map:*:${organisationId}:*`\n ],\n \n // Event-level invalidation\n EVENT_PERMISSIONS_CHANGED: (eventId: string) => [\n CACHE_PATTERNS.EVENT(eventId),\n `perm:*:*:${eventId}:*`,\n `access:*:*:${eventId}:*`,\n `map:*:*:${eventId}:*`\n ],\n \n // App-level invalidation\n APP_PERMISSIONS_CHANGED: (appId: UUID) => [\n CACHE_PATTERNS.APP(appId),\n `perm:*:*:*:${appId}:*`,\n `access:*:*:*:${appId}`,\n `map:*:*:*:${appId}`\n ],\n \n // Page-level invalidation\n PAGE_PERMISSIONS_CHANGED: (pageId: UUID) => [\n `perm:*:*:*:*:${pageId}`,\n `map:*:*:*:*`\n ]\n} as const;\n\n/**\n * RBAC Cache Invalidation Manager\n * \n * Handles automatic cache invalidation when RBAC data changes.\n */\nexport class RBACCacheInvalidationManager {\n private supabase: SupabaseClient<Database>;\n private invalidationCallbacks: Set<(pattern: string) => void> = new Set();\n\n constructor(supabase: SupabaseClient<Database>) {\n this.supabase = supabase;\n this.setupRealtimeSubscriptions();\n }\n\n /**\n * Add a callback for cache invalidation events\n * \n * @param callback - Function to call when cache is invalidated\n * @returns Unsubscribe function\n */\n onInvalidation(callback: (pattern: string) => void): () => void {\n this.invalidationCallbacks.add(callback);\n return () => this.invalidationCallbacks.delete(callback);\n }\n\n /**\n * Invalidate cache for a specific user\n * \n * @param userId - User ID\n * @param reason - Reason for invalidation\n */\n invalidateUser(userId: UUID, reason: string): void {\n const patterns = INVALIDATION_PATTERNS.USER_ROLES_CHANGED(userId);\n this.invalidatePatterns(patterns, reason);\n }\n\n /**\n * Invalidate cache for a specific organisation\n * \n * @param organisationId - Organisation ID\n * @param reason - Reason for invalidation\n */\n invalidateOrganisation(organisationId: UUID, reason: string): void {\n const patterns = INVALIDATION_PATTERNS.ORGANISATION_PERMISSIONS_CHANGED(organisationId);\n this.invalidatePatterns(patterns, reason);\n }\n\n /**\n * Invalidate cache for a specific event\n * \n * @param eventId - Event ID\n * @param reason - Reason for invalidation\n */\n invalidateEvent(eventId: string, reason: string): void {\n const patterns = INVALIDATION_PATTERNS.EVENT_PERMISSIONS_CHANGED(eventId);\n this.invalidatePatterns(patterns, reason);\n }\n\n /**\n * Invalidate cache for a specific app\n * \n * @param appId - App ID\n * @param reason - Reason for invalidation\n */\n invalidateApp(appId: UUID, reason: string): void {\n const patterns = INVALIDATION_PATTERNS.APP_PERMISSIONS_CHANGED(appId);\n this.invalidatePatterns(patterns, reason);\n }\n\n /**\n * Invalidate cache for a specific page\n * \n * @param pageId - Page ID\n * @param reason - Reason for invalidation\n */\n invalidatePage(pageId: UUID, reason: string): void {\n const patterns = INVALIDATION_PATTERNS.PAGE_PERMISSIONS_CHANGED(pageId);\n this.invalidatePatterns(patterns, reason);\n }\n\n /**\n * Invalidate cache patterns and notify callbacks\n * \n * @param patterns - Array of cache patterns to invalidate\n * @param reason - Reason for invalidation\n */\n private invalidatePatterns(patterns: string[], reason: string): void {\n console.log(`[RBAC Cache] Invalidating patterns: ${patterns.join(', ')} (${reason})`);\n \n patterns.forEach(pattern => {\n rbacCache.invalidate(pattern);\n });\n\n // Notify callbacks\n this.invalidationCallbacks.forEach(callback => {\n patterns.forEach(pattern => callback(pattern));\n });\n\n // Log audit event for cache invalidation\n emitAuditEvent({\n type: 'permission_check',\n userId: 'system' as UUID,\n organisationId: '00000000-0000-0000-0000-000000000000' as UUID,\n permission: 'cache:invalidate',\n decision: true,\n source: 'api',\n duration_ms: 0,\n metadata: {\n reason,\n patterns,\n timestamp: new Date().toISOString(),\n cache_invalidation: true\n }\n }).catch(error => {\n console.warn('[RBAC Cache] Failed to log cache invalidation audit event:', error);\n });\n }\n\n /**\n * Setup realtime subscriptions for automatic cache invalidation\n */\n private setupRealtimeSubscriptions(): void {\n // Check if realtime is available (skip in test environments)\n if (!this.supabase.channel || typeof this.supabase.channel !== 'function') {\n console.log('[RBAC Cache] Realtime not available, skipping subscriptions');\n return;\n }\n\n // Subscribe to organisation role changes\n this.supabase\n .channel('rbac_organisation_roles_changes')\n .on('postgres_changes', {\n event: '*',\n schema: 'public',\n table: 'rbac_organisation_roles'\n }, (payload: any) => {\n const { organisation_id, user_id } = payload.new || payload.old || {};\n if (organisation_id) {\n this.invalidateOrganisation(organisation_id, `organisation_role_${payload.eventType}`);\n }\n if (user_id) {\n this.invalidateUser(user_id, `organisation_role_${payload.eventType}`);\n }\n })\n .subscribe();\n\n // Subscribe to event app role changes\n this.supabase\n .channel('rbac_event_app_roles_changes')\n .on('postgres_changes', {\n event: '*',\n schema: 'public',\n table: 'rbac_event_app_roles'\n }, (payload: any) => {\n const { organisation_id, user_id, event_id, app_id } = payload.new || payload.old || {};\n if (organisation_id) {\n this.invalidateOrganisation(organisation_id, `event_app_role_${payload.eventType}`);\n }\n if (user_id) {\n this.invalidateUser(user_id, `event_app_role_${payload.eventType}`);\n }\n if (event_id) {\n this.invalidateEvent(event_id, `event_app_role_${payload.eventType}`);\n }\n if (app_id) {\n this.invalidateApp(app_id, `event_app_role_${payload.eventType}`);\n }\n })\n .subscribe();\n\n // Subscribe to global role changes\n this.supabase\n .channel('rbac_global_roles_changes')\n .on('postgres_changes', {\n event: '*',\n schema: 'public',\n table: 'rbac_global_roles'\n }, (payload: any) => {\n const { user_id } = payload.new || payload.old || {};\n if (user_id) {\n this.invalidateUser(user_id, `global_role_${payload.eventType}`);\n }\n })\n .subscribe();\n\n // Subscribe to page permission changes\n this.supabase\n .channel('rbac_page_permissions_changes')\n .on('postgres_changes', {\n event: '*',\n schema: 'public',\n table: 'rbac_page_permissions'\n }, (payload: any) => {\n const { organisation_id, app_page_id, role_id } = payload.new || payload.old || {};\n if (organisation_id) {\n this.invalidateOrganisation(organisation_id, `page_permission_${payload.eventType}`);\n }\n if (app_page_id) {\n this.invalidatePage(app_page_id, `page_permission_${payload.eventType}`);\n }\n // Note: We can't easily get user_id from role_id without additional query\n // This is a limitation of the current schema design\n })\n .subscribe();\n }\n\n /**\n * Manually trigger cache invalidation for all users in an organisation\n * \n * @param organisationId - Organisation ID\n * @param reason - Reason for invalidation\n */\n async invalidateAllUsersInOrganisation(organisationId: UUID, reason: string): Promise<void> {\n // Get all users in the organisation\n const { data: users } = await this.supabase\n .from('rbac_organisation_roles')\n .select('user_id')\n .eq('organisation_id', organisationId)\n .eq('is_active', true);\n\n if (users) {\n users.forEach(({ user_id }) => {\n this.invalidateUser(user_id, reason);\n });\n }\n }\n\n /**\n * Clear all cache entries\n */\n clearAllCache(): void {\n console.log('[RBAC Cache] Clearing all cache entries');\n rbacCache.clear();\n }\n}\n\n/**\n * Global cache invalidation manager instance\n */\nlet globalCacheInvalidationManager: RBACCacheInvalidationManager | null = null;\n\n/**\n * Initialize the global cache invalidation manager\n * \n * @param supabase - Supabase client\n * @returns Cache invalidation manager instance\n */\nexport function initializeCacheInvalidation(supabase: SupabaseClient<Database>): RBACCacheInvalidationManager {\n globalCacheInvalidationManager = new RBACCacheInvalidationManager(supabase);\n return globalCacheInvalidationManager;\n}\n\n/**\n * Get the global cache invalidation manager\n * \n * @returns Global cache invalidation manager or null if not initialized\n */\nexport function getCacheInvalidationManager(): RBACCacheInvalidationManager | null {\n return globalCacheInvalidationManager;\n}\n","import {\n RBACError,\n PermissionDeniedError,\n OrganisationContextRequiredError,\n InvalidScopeError,\n MissingUserContextError,\n} from './types';\n\nexport enum RBACErrorCategory {\n NETWORK = 'network_error',\n DATABASE = 'database_error',\n VALIDATION = 'validation_error',\n RATE_LIMIT = 'rate_limit_error',\n AUTHENTICATION = 'authentication_error',\n AUTHORIZATION = 'authorization_error',\n UNKNOWN = 'unknown_error',\n}\n\nconst RATE_LIMIT_STATUS_CODES = new Set([429]);\nconst AUTH_STATUS_CODES = new Set([401]);\nconst AUTHZ_STATUS_CODES = new Set([403]);\n\nfunction normalize(value: unknown): string {\n if (!value) {\n return '';\n }\n if (typeof value === 'string') {\n return value.toLowerCase();\n }\n if (value instanceof Error && typeof value.message === 'string') {\n return value.message.toLowerCase();\n }\n return String(value).toLowerCase();\n}\n\nexport function categorizeError(error: unknown): RBACErrorCategory {\n if (error instanceof PermissionDeniedError) {\n return RBACErrorCategory.AUTHORIZATION;\n }\n\n if (error instanceof OrganisationContextRequiredError || error instanceof InvalidScopeError) {\n return RBACErrorCategory.VALIDATION;\n }\n\n if (error instanceof MissingUserContextError) {\n return RBACErrorCategory.AUTHENTICATION;\n }\n\n if (error instanceof RBACError) {\n switch (error.code) {\n case 'PERMISSION_DENIED':\n return RBACErrorCategory.AUTHORIZATION;\n case 'ORGANISATION_CONTEXT_REQUIRED':\n case 'INVALID_SCOPE':\n return RBACErrorCategory.VALIDATION;\n case 'MISSING_USER_CONTEXT':\n return RBACErrorCategory.AUTHENTICATION;\n default:\n break;\n }\n }\n\n if (error && typeof error === 'object') {\n const status = (error as { status?: number }).status;\n if (typeof status === 'number') {\n if (RATE_LIMIT_STATUS_CODES.has(status)) {\n return RBACErrorCategory.RATE_LIMIT;\n }\n if (AUTH_STATUS_CODES.has(status)) {\n return RBACErrorCategory.AUTHENTICATION;\n }\n if (AUTHZ_STATUS_CODES.has(status)) {\n return RBACErrorCategory.AUTHORIZATION;\n }\n if (status >= 500) {\n return RBACErrorCategory.DATABASE;\n }\n }\n\n const codeValue = normalize((error as { code?: string }).code);\n if (codeValue) {\n if (codeValue.includes('network')) {\n return RBACErrorCategory.NETWORK;\n }\n if (codeValue.includes('postgres') || codeValue.includes('database') || codeValue.includes('db')) {\n return RBACErrorCategory.DATABASE;\n }\n if (codeValue.includes('rate')) {\n return RBACErrorCategory.RATE_LIMIT;\n }\n if (codeValue.includes('auth')) {\n return RBACErrorCategory.AUTHENTICATION;\n }\n if (codeValue.includes('permission')) {\n return RBACErrorCategory.AUTHORIZATION;\n }\n if (codeValue.includes('scope') || codeValue.includes('invalid')) {\n return RBACErrorCategory.VALIDATION;\n }\n }\n }\n\n const message = normalize(error);\n if (message.includes('timeout') || message.includes('network') || message.includes('fetch')) {\n return RBACErrorCategory.NETWORK;\n }\n if (message.includes('postgres') || message.includes('database') || message.includes('connection')) {\n return RBACErrorCategory.DATABASE;\n }\n if (message.includes('rate limit') || message.includes('too many requests')) {\n return RBACErrorCategory.RATE_LIMIT;\n }\n if (message.includes('permission') || message.includes('forbidden')) {\n return RBACErrorCategory.AUTHORIZATION;\n }\n if (message.includes('auth') || message.includes('token') || message.includes('session')) {\n return RBACErrorCategory.AUTHENTICATION;\n }\n if (message.includes('invalid') || message.includes('scope') || message.includes('validation')) {\n return RBACErrorCategory.VALIDATION;\n }\n\n return RBACErrorCategory.UNKNOWN;\n}\n\nexport type SecurityEventType =\n | 'permission_denied'\n | 'invalid_input'\n | 'rate_limit_exceeded'\n | 'suspicious_activity'\n | 'network_error'\n | 'database_error'\n | 'validation_error'\n | 'rate_limit_error'\n | 'authentication_error'\n | 'unknown_error';\n\nexport function mapErrorCategoryToSecurityEventType(category: RBACErrorCategory): SecurityEventType {\n switch (category) {\n case RBACErrorCategory.AUTHORIZATION:\n return 'permission_denied';\n case RBACErrorCategory.NETWORK:\n return 'network_error';\n case RBACErrorCategory.DATABASE:\n return 'database_error';\n case RBACErrorCategory.VALIDATION:\n return 'validation_error';\n case RBACErrorCategory.RATE_LIMIT:\n return 'rate_limit_error';\n case RBACErrorCategory.AUTHENTICATION:\n return 'authentication_error';\n case RBACErrorCategory.UNKNOWN:\n default:\n return 'unknown_error';\n }\n}\n","/**\n * RBAC Security Enhancements\n * @package @jmruthers/pace-core\n * @module RBAC/Security\n * @since 1.0.0\n * \n * Additional security measures for the RBAC system\n */\n\nimport { UUID, Permission, Scope } from './types';\n\n/**\n * Security validation utilities for RBAC operations\n */\nexport class RBACSecurityValidator {\n /**\n * Validate permission string format\n * @param permission - Permission string to validate\n * @returns True if valid, false otherwise\n */\n static validatePermission(permission: string): boolean {\n if (typeof permission !== 'string' || permission.length === 0) {\n return false;\n }\n\n // Permission format: operation:resource[.subresource]\n // Only CRUD operations are allowed (read, create, update, delete)\n // The 'manage' operation has been removed for RBAC compliance\n const permissionRegex = /^(read|create|update|delete):[a-z0-9._-]+$/;\n return permissionRegex.test(permission);\n }\n\n /**\n * Validate UUID format\n * @param uuid - UUID string to validate\n * @returns True if valid, false otherwise\n */\n static validateUUID(uuid: string): boolean {\n if (typeof uuid !== 'string' || uuid.length === 0) {\n return false;\n }\n\n // More permissive UUID regex that allows all valid UUID versions\n const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n return uuidRegex.test(uuid);\n }\n\n /**\n * Validate scope object\n * @param scope - Scope object to validate\n * @returns True if valid, false otherwise\n */\n static validateScope(scope: Scope): boolean {\n if (!scope || typeof scope !== 'object') {\n return false;\n }\n\n // Organisation ID validation - reject empty strings\n if (scope.organisationId !== undefined) {\n // Reject empty strings - use undefined/null instead\n if (typeof scope.organisationId === 'string' && scope.organisationId.trim() === '') {\n return false;\n }\n if (scope.organisationId && !this.validateUUID(scope.organisationId)) {\n return false;\n }\n }\n\n // Event ID should be a string if provided\n if (scope.eventId && typeof scope.eventId !== 'string') {\n return false;\n }\n\n // App ID should be a valid UUID if provided\n if (scope.appId && !this.validateUUID(scope.appId)) {\n return false;\n }\n\n // At least one valid field must be present\n return !!(scope.organisationId || scope.eventId || scope.appId);\n }\n\n /**\n * Sanitize input string to prevent injection attacks\n * @param input - Input string to sanitize\n * @returns Sanitized string\n */\n static sanitizeInput(input: string): string {\n if (typeof input !== 'string') {\n return '';\n }\n\n // Remove potentially dangerous characters\n return input\n .replace(/<[^>]*>/g, '') // Remove HTML tags\n .replace(/[<>\\\"'&]/g, '') // Remove HTML/XML characters\n .replace(/[;()]/g, '') // Remove SQL injection characters\n .replace(/javascript:/gi, '') // Remove javascript: protocol\n .replace(/data:/gi, '') // Remove data: protocol\n .trim();\n }\n\n /**\n * Validate user ID format\n * @param userId - User ID to validate\n * @returns True if valid, false otherwise\n */\n static validateUserId(userId: UUID): boolean {\n return this.validateUUID(userId);\n }\n\n /**\n * Check if permission is a wildcard permission\n * @param permission - Permission string to check\n * @returns True if wildcard, false otherwise\n */\n static isWildcardPermission(permission: string): boolean {\n return permission.includes('*') || permission.endsWith(':*');\n }\n\n /**\n * Validate permission hierarchy\n * @param permission - Permission to validate\n * @param requiredOperation - Required operation\n * @returns True if permission matches or is higher in hierarchy\n */\n static validatePermissionHierarchy(permission: string, requiredOperation: string): boolean {\n if (!this.validatePermission(permission)) {\n return false;\n }\n\n const [operation] = permission.split(':');\n // Only CRUD operations - 'manage' has been removed\n const hierarchy = ['read', 'create', 'update', 'delete'];\n \n const permissionLevel = hierarchy.indexOf(operation);\n const requiredLevel = hierarchy.indexOf(requiredOperation);\n \n if (permissionLevel === -1 || requiredLevel === -1) {\n return false;\n }\n\n // Higher level permissions include lower level permissions\n return permissionLevel >= requiredLevel;\n }\n\n /**\n * Rate limiting check (placeholder for future implementation)\n * @param userId - User ID\n * @param operation - Operation being performed\n * @returns True if within rate limit, false otherwise\n */\n static async checkRateLimit(userId: UUID, operation: string): Promise<boolean> {\n // TODO: Implement actual rate limiting logic\n // This could use Redis, in-memory cache, or database-based rate limiting\n return true;\n }\n\n /**\n * Validate context requirements for security\n * @param scope - Scope object\n * @param appId - Application ID\n * @returns True if context is valid, false otherwise\n */\n static validateContextRequirements(scope: Scope, appId?: UUID): boolean {\n // Organisation context is always required\n if (!scope.organisationId) {\n return false;\n }\n\n // If app requires event, event context must be provided\n if (appId && scope.appId === appId) {\n // This would need to check app configuration\n // For now, we'll assume event context is required if appId is provided\n if (!scope.eventId) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Log security event for monitoring\n * @param event - Security event details\n */\n static logSecurityEvent(event: {\n type:\n | 'permission_denied'\n | 'invalid_input'\n | 'rate_limit_exceeded'\n | 'suspicious_activity'\n | 'network_error'\n | 'database_error'\n | 'validation_error'\n | 'rate_limit_error'\n | 'authentication_error'\n | 'unknown_error';\n userId: UUID;\n details: Record<string, any>;\n timestamp?: Date;\n }): void {\n const securityEvent = {\n ...event,\n timestamp: event.timestamp || new Date(),\n severity: this.getEventSeverity(event.type),\n };\n\n // Log to console in development, could be sent to security monitoring service in production\n if (import.meta.env.MODE === 'development') {\n console.warn('[RBAC Security]', securityEvent);\n }\n\n // TODO: Send to security monitoring service\n }\n\n /**\n * Get severity level for security event\n * @param eventType - Type of security event\n * @returns Severity level\n */\n private static getEventSeverity(eventType: string): 'low' | 'medium' | 'high' | 'critical' {\n switch (eventType) {\n case 'permission_denied':\n return 'low';\n case 'invalid_input':\n case 'rate_limit_exceeded':\n case 'rate_limit_error':\n case 'network_error':\n return 'medium';\n case 'validation_error':\n return 'high';\n case 'authentication_error':\n case 'database_error':\n return 'critical';\n case 'suspicious_activity':\n case 'unknown_error':\n return 'high';\n default:\n return 'low';\n }\n }\n}\n\n/**\n * Security configuration for RBAC system\n */\nexport interface RBACSecurityConfig {\n enableInputValidation: boolean;\n enableRateLimiting: boolean;\n enableAuditLogging: boolean;\n maxPermissionChecksPerMinute: number;\n suspiciousActivityThreshold: number;\n}\n\n/**\n * Default security configuration\n */\nexport const DEFAULT_SECURITY_CONFIG: RBACSecurityConfig = {\n enableInputValidation: true,\n enableRateLimiting: true,\n enableAuditLogging: true,\n maxPermissionChecksPerMinute: 1000, // Increased from 100 to 1000 for normal app usage\n suspiciousActivityThreshold: 10,\n};\n\n/**\n * Security context for RBAC operations\n * \n * OrganisationId is required - it can always be derived from event context in event-based apps.\n * If organisation context is not available, the operation should fail rather than proceed without context.\n */\nexport interface SecurityContext {\n userId: UUID;\n organisationId: UUID; // Required - can always be derived from event context\n ipAddress?: string;\n userAgent?: string;\n timestamp: Date;\n}\n\n/**\n * Security middleware for RBAC operations\n */\nexport class RBACSecurityMiddleware {\n private config: RBACSecurityConfig;\n\n constructor(config: RBACSecurityConfig = DEFAULT_SECURITY_CONFIG) {\n this.config = config;\n this._startCleanupInterval();\n }\n\n /**\n * Start periodic cleanup of expired entries\n */\n private _startCleanupInterval(): void {\n // Clear expired entries every 5 minutes\n setInterval(() => {\n this.clearExpiredEntries();\n }, 5 * 60 * 1000);\n }\n\n /**\n * Validate input before processing\n * @param input - Input to validate\n * @param context - Security context\n * @returns Validation result\n */\n async validateInput(input: any, context: SecurityContext): Promise<{\n isValid: boolean;\n errors: string[];\n }> {\n const errors: string[] = [];\n\n // Core validations are always enforced regardless of configuration\n if (!RBACSecurityValidator.validateUserId(context.userId)) {\n errors.push('Invalid user ID format');\n }\n\n // OrganisationId is required\n if (!context.organisationId) {\n errors.push('Organisation ID is required');\n } else if (!RBACSecurityValidator.validateUUID(context.organisationId)) {\n errors.push('Invalid organisation ID format');\n }\n\n if (input.permission && !RBACSecurityValidator.validatePermission(input.permission)) {\n errors.push('Invalid permission format');\n }\n\n if (input.scope && !RBACSecurityValidator.validateScope(input.scope)) {\n errors.push('Invalid scope format');\n }\n\n if (this.config.enableInputValidation) {\n if (context.ipAddress && typeof context.ipAddress !== 'string') {\n errors.push('Invalid IP address format');\n }\n\n if (context.userAgent && typeof context.userAgent !== 'string') {\n errors.push('Invalid user agent format');\n }\n }\n\n // Log suspicious activity\n if (errors.length > 0) {\n RBACSecurityValidator.logSecurityEvent({\n type: 'invalid_input',\n userId: context.userId,\n details: { errors, input: this.sanitizeInput(JSON.stringify(input)) },\n });\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n }\n\n /**\n * Check rate limiting\n * @param context - Security context\n * @returns Rate limit check result\n */\n async checkRateLimit(context: SecurityContext): Promise<{\n isAllowed: boolean;\n remaining: number;\n }> {\n if (!this.config.enableRateLimiting) {\n return { isAllowed: true, remaining: this.config.maxPermissionChecksPerMinute };\n }\n\n // Implementation: In-memory rate limiting with sliding window\n // For production, consider using Redis or Supabase Edge Functions\n const isAllowed = await this._checkRateLimitInternal(context.userId);\n \n const remaining = isAllowed ? this.config.maxPermissionChecksPerMinute - this._getRequestCount(context.userId) : 0;\n\n return {\n isAllowed,\n remaining: Math.max(0, remaining),\n };\n }\n\n /**\n * In-memory rate limiting cache (sliding window)\n * Note: For production, this should use Redis or Supabase Edge Functions\n */\n private rateLimitCache = new Map<UUID, Array<{ timestamp: number }>>();\n\n private async _checkRateLimitInternal(userId: UUID): Promise<boolean> {\n const now = Date.now();\n const windowMs = 60 * 1000; // 1 minute window\n\n // Get or create rate limit entries for this user\n const entries = this.rateLimitCache.get(userId) || [];\n \n // Remove entries outside the time window\n const validEntries = entries.filter(entry => now - entry.timestamp < windowMs);\n \n // Check if user exceeded rate limit\n const requestCount = validEntries.length;\n const isAllowed = requestCount < this.config.maxPermissionChecksPerMinute;\n \n // If allowed, add current request\n if (isAllowed) {\n validEntries.push({ timestamp: now });\n }\n \n // Update cache\n this.rateLimitCache.set(userId, validEntries);\n \n return isAllowed;\n }\n\n private _getRequestCount(userId: UUID): number {\n const now = Date.now();\n const windowMs = 60 * 1000; // 1 minute window\n \n const entries = this.rateLimitCache.get(userId) || [];\n const validEntries = entries.filter(entry => now - entry.timestamp < windowMs);\n \n return validEntries.length;\n }\n\n /**\n * Clear old rate limit entries to prevent memory leaks\n * Should be called periodically (e.g., every 5 minutes)\n */\n private clearExpiredEntries(): void {\n const now = Date.now();\n const windowMs = 60 * 1000; // 1 minute window\n \n for (const [userId, entries] of this.rateLimitCache.entries()) {\n const validEntries = entries.filter(entry => now - entry.timestamp < windowMs);\n \n if (validEntries.length === 0) {\n this.rateLimitCache.delete(userId);\n } else {\n this.rateLimitCache.set(userId, validEntries);\n }\n }\n }\n\n /**\n * Sanitize input data\n * @param input - Input to sanitize\n * @returns Sanitized input\n */\n private sanitizeInput(input: string): string {\n return RBACSecurityValidator.sanitizeInput(input);\n }\n}\n","/**\n * RBAC Core Engine - Simplified Version\n * @package @jmruthers/pace-core\n * @module RBAC/Engine\n * @since 2.0.0\n * \n * This is a drastically simplified version that delegates permission checking to a single RPC function.\n * All the complex grant collection logic has been moved to the database for better performance and security.\n * \n * BREAKING CHANGES FROM v1:\n * - No more client-side grant collection\n * - No more complex permission resolution algorithm\n * - Single RPC call for all permission checks\n * - Caching is still supported for performance\n */\n\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../types/database';\nimport {\n UUID,\n Permission,\n Scope,\n PermissionCheck,\n AccessLevel,\n PermissionMap,\n Operation,\n RBACAppContext,\n RBACRoleContext,\n RBACPermission,\n} from './types';\nimport { rbacCache, RBACCache } from './cache';\nimport { emitAuditEvent } from './audit';\nimport { initializeCacheInvalidation } from './cache-invalidation';\nimport { categorizeError, mapErrorCategoryToSecurityEventType } from './errors';\nimport { \n RBACSecurityValidator, \n RBACSecurityMiddleware, \n SecurityContext,\n DEFAULT_SECURITY_CONFIG,\n RBACSecurityConfig\n} from './security';\n\n/**\n * Simplified RBAC Engine\n * \n * Delegates all permission checks to the database via a single RPC function.\n * This reduces complexity, improves performance, and enhances security.\n */\nexport class RBACEngine {\n private supabase: SupabaseClient<Database>;\n private securityMiddleware: RBACSecurityMiddleware;\n\n constructor(supabase: SupabaseClient<Database>, securityConfig?: Partial<RBACSecurityConfig>) {\n this.supabase = supabase;\n // Merge provided security config with defaults\n const mergedSecurityConfig: RBACSecurityConfig = {\n ...DEFAULT_SECURITY_CONFIG,\n ...securityConfig,\n };\n this.securityMiddleware = new RBACSecurityMiddleware(mergedSecurityConfig);\n \n // Initialize cache invalidation for automatic cache clearing\n initializeCacheInvalidation(supabase);\n }\n\n /**\n * Check if a user has a specific permission\n * \n * This method now delegates to the database RPC function for all the heavy lifting.\n * \n * @param input - Permission check input\n * @param securityContext - Security context for validation (required)\n * @returns Promise resolving to permission result\n */\n async isPermitted(input: PermissionCheck, securityContext: SecurityContext): Promise<boolean> {\n const startTime = Date.now();\n const { userId, permission, scope, pageId } = input;\n \n // Track cache usage for audit\n let cacheHit = false;\n let cacheSource: 'memory' | 'rpc' = 'rpc';\n\n try {\n // ========================================================================\n // STEP 1: Security Validation & Rate Limiting (MANDATORY)\n // ========================================================================\n \n // Validate input\n const validation = await this.securityMiddleware.validateInput(input, securityContext);\n if (!validation.isValid) {\n RBACSecurityValidator.logSecurityEvent({\n type: 'invalid_input',\n userId,\n details: { errors: validation.errors, input: JSON.stringify(input) },\n });\n return false;\n }\n\n // Check rate limits\n const rateLimit = await this.securityMiddleware.checkRateLimit(securityContext);\n if (!rateLimit.isAllowed) {\n RBACSecurityValidator.logSecurityEvent({\n type: 'rate_limit_exceeded',\n userId,\n details: { remaining: rateLimit.remaining },\n });\n return false;\n }\n\n // Validate user ID format\n if (!RBACSecurityValidator.validateUserId(userId)) {\n RBACSecurityValidator.logSecurityEvent({\n type: 'invalid_input',\n userId,\n details: { error: 'Invalid user ID format' },\n });\n return false;\n }\n\n // Validate permission format\n if (!RBACSecurityValidator.validatePermission(permission)) {\n RBACSecurityValidator.logSecurityEvent({\n type: 'invalid_input',\n userId,\n details: { error: 'Invalid permission format', permission },\n });\n return false;\n }\n\n // Validate scope format\n if (!RBACSecurityValidator.validateScope(scope)) {\n RBACSecurityValidator.logSecurityEvent({\n type: 'invalid_input',\n userId,\n details: { error: 'Invalid scope format', scope },\n });\n return false;\n }\n\n // ========================================================================\n // STEP 2: Check Cache (OPTIONAL - for performance)\n // ========================================================================\n \n const cacheKey = RBACCache.generateKey(\n userId,\n permission,\n scope.organisationId,\n scope.eventId,\n scope.appId,\n pageId\n );\n \n const cached = rbacCache.get<boolean>(cacheKey);\n if (cached !== null) {\n cacheHit = true;\n cacheSource = 'memory';\n \n const duration = Date.now() - startTime;\n \n // Audit cache hit (if organisation context exists)\n if (scope.organisationId) {\n const resolvedPageId = await this.resolvePageId(pageId, scope.appId);\n await emitAuditEvent({\n type: 'permission_check',\n userId,\n organisationId: scope.organisationId,\n eventId: scope.eventId,\n appId: scope.appId,\n pageId: resolvedPageId,\n permission,\n decision: cached,\n source: 'api',\n duration_ms: duration,\n cache_hit: true,\n cache_source: 'memory',\n });\n }\n \n return cached;\n }\n\n // ========================================================================\n // STEP 3: Call Simplified RPC Function (SINGLE DATABASE CALL)\n // ========================================================================\n \n // This single RPC call replaces hundreds of lines of complex client-side logic:\n // - No more super admin checks here (RPC handles it)\n // - No more grant collection (RPC handles it)\n // - No more permission matching (RPC handles it)\n // - No more deny-override-allow logic (RPC handles it)\n \n const { data, error } = await (this.supabase as any).rpc('rbac_check_permission_simplified', {\n p_user_id: userId,\n p_permission: permission,\n p_organisation_id: scope.organisationId || undefined,\n p_event_id: scope.eventId || undefined,\n p_app_id: scope.appId || undefined,\n p_page_id: pageId || undefined,\n });\n\n if (error) {\n console.error('[RBACEngine] RPC error:', error);\n\n const category = categorizeError(error);\n const eventType = mapErrorCategoryToSecurityEventType(category);\n const errorDetails = error as { message?: string; code?: string; hint?: string; details?: string };\n\n RBACSecurityValidator.logSecurityEvent({\n type: eventType,\n userId,\n details: {\n error: errorDetails?.message || 'RPC call failed',\n code: errorDetails?.code,\n hint: errorDetails?.hint,\n details: errorDetails?.details,\n permission,\n scope: JSON.stringify(scope),\n category,\n },\n });\n\n // Fail securely - deny on error\n return false;\n }\n\n const hasPermission = data === true;\n \n // ========================================================================\n // STEP 4: Cache Result & Audit (COMPLETION)\n // ========================================================================\n \n // Cache the result for 60 seconds\n rbacCache.set(cacheKey, hasPermission, 60000);\n \n const duration = Date.now() - startTime;\n \n // Emit audit event (if organisation context exists)\n if (scope.organisationId) {\n const resolvedPageId = await this.resolvePageId(pageId, scope.appId);\n await emitAuditEvent({\n type: hasPermission ? 'permission_check' : 'permission_denied',\n userId,\n organisationId: scope.organisationId,\n eventId: scope.eventId,\n appId: scope.appId,\n pageId: resolvedPageId,\n permission,\n decision: hasPermission,\n source: 'api',\n duration_ms: duration,\n cache_hit: cacheHit,\n cache_source: cacheSource,\n });\n }\n\n return hasPermission;\n \n } catch (error) {\n const category = categorizeError(error);\n const eventType = mapErrorCategoryToSecurityEventType(category);\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n\n RBACSecurityValidator.logSecurityEvent({\n type: eventType,\n userId,\n details: {\n error: errorMessage,\n permission,\n scope: JSON.stringify(scope),\n category,\n },\n });\n\n // Fail securely - deny access on error\n console.error('[RBACEngine] Permission check failed:', error);\n return false;\n }\n }\n\n /**\n * Get user's access level in a scope\n * \n * This is derived from roles, not permissions.\n * \n * @param input - Access level input\n * @returns Promise resolving to access level\n */\n async getAccessLevel(input: { userId: UUID; scope: Scope }): Promise<AccessLevel> {\n const { userId, scope } = input;\n\n // Check cache first\n const cacheKey = RBACCache.generateAccessLevelKey(\n userId,\n scope.organisationId || '',\n scope.eventId,\n scope.appId\n );\n \n const cached = rbacCache.get<AccessLevel>(cacheKey);\n if (cached) {\n return cached;\n }\n\n const now = new Date().toISOString();\n\n // Check super admin\n const isSuperAdmin = await this.checkSuperAdmin(userId);\n if (isSuperAdmin) {\n rbacCache.set(cacheKey, 'super', 60000);\n return 'super';\n }\n\n // Check organisation role\n if (scope.organisationId) {\n const { data: orgRole } = await this.supabase\n .from('rbac_organisation_roles')\n .select('role')\n .eq('user_id', userId)\n .eq('organisation_id', scope.organisationId)\n .eq('status', 'active')\n .is('revoked_at', null)\n .lte('valid_from', now)\n .or(`valid_to.is.null,valid_to.gte.${now}`)\n .single() as { data: { role: string } | null; error: any };\n\n if (orgRole?.role === 'org_admin') {\n rbacCache.set(cacheKey, 'admin', 60000);\n return 'admin';\n }\n }\n\n // Check event-app role\n if (scope.eventId && scope.appId) {\n const { data: eventRole } = await this.supabase\n .from('rbac_event_app_roles')\n .select('role')\n .eq('user_id', userId)\n .eq('event_id', scope.eventId)\n .eq('app_id', scope.appId)\n .eq('status', 'active')\n .lte('valid_from', now)\n .or(`valid_to.is.null,valid_to.gte.${now}`)\n .single() as { data: { role: string } | null; error: any };\n\n if (eventRole?.role === 'event_admin') {\n rbacCache.set(cacheKey, 'admin', 60000);\n return 'admin';\n }\n if (eventRole?.role === 'planner') {\n rbacCache.set(cacheKey, 'planner', 60000);\n return 'planner';\n }\n if (eventRole?.role === 'participant') {\n rbacCache.set(cacheKey, 'participant', 60000);\n return 'participant';\n }\n }\n\n // Default to viewer\n rbacCache.set(cacheKey, 'viewer', 60000);\n return 'viewer';\n }\n\n /**\n * Get user's permission map for a scope\n * \n * This builds a map of page IDs to allowed operations.\n * Uses the simplified RPC for each permission check.\n * \n * @param input - Permission map input\n * @returns Promise resolving to permission map\n */\n async getPermissionMap(input: { userId: UUID; scope: Scope }): Promise<PermissionMap> {\n const { userId, scope } = input;\n\n // Generate cache key early so it's available for super admin caching\n const cacheKey = RBACCache.generatePermissionMapKey(\n userId,\n scope.organisationId || '',\n scope.eventId,\n scope.appId\n );\n\n // Check super admin first - super admins have all permissions\n const isSuperAdmin = await this.checkSuperAdmin(userId);\n if (isSuperAdmin) {\n const wildcardMap: PermissionMap = { '*': true };\n rbacCache.set(cacheKey, wildcardMap, 60000);\n return wildcardMap;\n }\n\n // Validate scope\n if (!scope.organisationId) {\n return {}; // No permissions without valid context\n }\n\n // Check cache first\n \n const cached = rbacCache.get<PermissionMap>(cacheKey);\n if (cached) {\n return cached;\n }\n\n const permissionMap: PermissionMap = {};\n\n // Get all pages for the app\n if (scope.appId) {\n const { data: pages } = await this.supabase\n .from('rbac_app_pages')\n .select('id, page_name')\n .eq('app_id', scope.appId) as { data: Array<{ id: string; page_name: string }> | null };\n\n if (pages) {\n // OrganisationId is required for permission checks\n if (!scope.organisationId) {\n // Return empty permission map if no organisation context\n rbacCache.set(cacheKey, permissionMap, 60000);\n return permissionMap;\n }\n\n // Create a security context for permission checks\n const securityContext: SecurityContext = {\n userId,\n organisationId: scope.organisationId, // Required\n timestamp: new Date(),\n };\n\n for (const page of pages) {\n // Check each CRUD operation\n for (const operation of ['read', 'create', 'update', 'delete'] as Operation[]) {\n const hasPermission = await this.isPermitted(\n {\n userId,\n scope,\n permission: `${operation}:${page.page_name}`,\n pageId: page.id,\n },\n securityContext\n );\n\n const permissionKey = `${operation}:${page.page_name}` as Permission;\n permissionMap[permissionKey] = hasPermission;\n }\n }\n }\n }\n\n rbacCache.set(cacheKey, permissionMap, 60000);\n return permissionMap;\n }\n\n async resolveAppContext(input: { userId: UUID; appName: string }): Promise<RBACAppContext | null> {\n try {\n const { userId, appName } = input;\n const { data, error } = await (this.supabase as any).rpc('util_app_resolve', {\n p_user_id: userId,\n p_app_name: appName,\n });\n\n if (error) {\n console.error('[RBACEngine] Failed to resolve app context:', error);\n return null;\n }\n\n if (!data || data.length === 0) {\n return null;\n }\n\n const appData = data[0] as { app_id: UUID; has_access: boolean };\n if (!appData?.app_id) {\n return null;\n }\n\n return {\n appId: appData.app_id,\n hasAccess: appData.has_access !== false,\n };\n } catch (error) {\n console.error('[RBACEngine] Unexpected error resolving app context:', error);\n return null;\n }\n }\n\n async getRoleContext(input: { userId: UUID; scope: Scope }): Promise<RBACRoleContext> {\n const result: RBACRoleContext = {\n globalRole: null,\n organisationRole: null,\n eventAppRole: null,\n };\n\n try {\n const { userId, scope } = input;\n // Call unified function (tech debt removed: consolidated from 2 overloaded versions)\n const { data, error } = await (this.supabase as any).rpc('rbac_permissions_get', {\n p_user_id: userId,\n p_organisation_id: scope.organisationId || null,\n p_event_id: scope.eventId || null,\n p_app_id: scope.appId || null,\n p_page_id: null, // Optional: can filter to specific page if needed\n });\n\n if (error) {\n console.error('[RBACEngine] Failed to load role context:', error);\n return result;\n }\n\n if (!Array.isArray(data)) {\n return result;\n }\n\n for (const permission of data as RBACPermission[]) {\n if (permission.permission_type === 'all_permissions') {\n result.globalRole = 'super_admin';\n }\n\n if (permission.permission_type === 'organisation_access') {\n result.organisationRole = permission.role_name as any;\n }\n\n if (permission.permission_type === 'event_app_access') {\n result.eventAppRole = permission.role_name as any;\n }\n }\n\n return result;\n } catch (error) {\n console.error('[RBACEngine] Unexpected error loading role context:', error);\n return result;\n }\n }\n\n /**\n * Check if user is super admin\n * \n * @param userId - User ID\n * @returns Promise resolving to super admin status\n */\n private async checkSuperAdmin(userId: UUID): Promise<boolean> {\n // Check cache first\n const cacheKey = `super_admin:${userId}`;\n const cached = rbacCache.get<boolean>(cacheKey);\n if (cached !== null) {\n return cached;\n }\n\n const now = new Date().toISOString();\n const { data, error } = await this.supabase\n .from('rbac_global_roles')\n .select('role')\n .eq('user_id', userId)\n .eq('role', 'super_admin')\n .lte('valid_from', now)\n .or(`valid_to.is.null,valid_to.gte.${now}`)\n .limit(1) as { data: Array<{ role: string }> | null; error: any };\n\n const isSuperAdmin = !error && data && data.length > 0;\n \n // Cache for 60 seconds\n rbacCache.set(cacheKey, isSuperAdmin, 60000);\n \n return Boolean(isSuperAdmin);\n }\n\n /**\n * Resolve a page ID to UUID if it's a page name\n * \n * @param pageId - Page ID (UUID) or page name (string)\n * @param appId - App ID to look up the page\n * @returns Resolved page ID (UUID) or original pageId\n */\n private async resolvePageId(pageId?: UUID | string, appId?: UUID): Promise<UUID | string | undefined> {\n if (!pageId) {\n return undefined;\n }\n\n // Check if it's already a UUID\n const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n if (uuidRegex.test(pageId)) {\n return pageId as UUID;\n }\n\n // It's a page name, but we need appId to resolve it\n if (!appId) {\n return pageId;\n }\n\n // Resolve page name to UUID\n try {\n const { data: page } = await this.supabase\n .from('rbac_app_pages')\n .select('id')\n .eq('app_id', appId)\n .eq('page_name', pageId)\n .single() as { data: { id: UUID } | null };\n \n return page?.id || pageId;\n } catch (error) {\n console.warn('[RBAC Engine] Failed to resolve page name to UUID:', { pageId, appId, error });\n return pageId;\n }\n }\n}\n\n/**\n * Create an RBAC engine instance\n * \n * @param supabase - Supabase client\n * @param securityConfig - Optional security configuration\n * @returns RBACEngine instance\n */\nexport function createRBACEngine(\n supabase: SupabaseClient<Database>,\n securityConfig?: Partial<RBACSecurityConfig>\n): RBACEngine {\n return new RBACEngine(supabase, securityConfig);\n}\n\n","/**\n * RBAC Configuration\n * @package @jmruthers/pace-core\n * @module RBAC/Config\n * @since 1.0.0\n * \n * This module provides configuration options for the RBAC system.\n */\n\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../types/database';\nimport { RBACSecurityConfig } from './security';\n\nexport type LogLevel = 'error' | 'warn' | 'info' | 'debug';\n\nexport interface RBACConfig {\n supabase: SupabaseClient<Database>;\n debug?: boolean;\n logLevel?: LogLevel;\n developmentMode?: boolean;\n mockPermissions?: Record<string, boolean>;\n cache?: {\n ttl?: number;\n enabled?: boolean;\n };\n audit?: {\n enabled?: boolean;\n logLevel?: LogLevel;\n };\n security?: Partial<RBACSecurityConfig>;\n}\n\nexport interface RBACLogger {\n error: (message: string, ...args: unknown[]) => void;\n warn: (message: string, ...args: unknown[]) => void;\n info: (message: string, ...args: unknown[]) => void;\n debug: (message: string, ...args: unknown[]) => void;\n}\n\nclass RBACConfigManager {\n private config: RBACConfig | null = null;\n private logger: RBACLogger | null = null;\n\n setConfig(config: RBACConfig): void {\n this.config = config;\n this.setupLogger();\n }\n\n getConfig(): RBACConfig | null {\n return this.config;\n }\n\n getLogger(): RBACLogger {\n if (!this.logger) {\n this.logger = this.createDefaultLogger();\n }\n return this.logger;\n }\n\n private setupLogger(): void {\n if (!this.config) return;\n\n const { debug = false, logLevel = 'warn' } = this.config;\n \n this.logger = {\n error: (message: string, ...args: unknown[]) => {\n console.error(`[RBAC ERROR] ${message}`, ...args);\n },\n warn: (message: string, ...args: unknown[]) => {\n if (logLevel === 'warn' || logLevel === 'info' || logLevel === 'debug') {\n console.warn(`[RBAC WARN] ${message}`, ...args);\n }\n },\n info: (message: string, ...args: unknown[]) => {\n if (logLevel === 'info' || logLevel === 'debug') {\n console.info(`[RBAC INFO] ${message}`, ...args);\n }\n },\n debug: (message: string, ...args: unknown[]) => {\n if (debug && logLevel === 'debug') {\n console.debug(`[RBAC DEBUG] ${message}`, ...args);\n }\n },\n };\n }\n\n private createDefaultLogger(): RBACLogger {\n return {\n error: (message: string, ...args: unknown[]) => console.error(`[RBAC ERROR] ${message}`, ...args),\n warn: (message: string, ...args: unknown[]) => console.warn(`[RBAC WARN] ${message}`, ...args),\n info: (message: string, ...args: unknown[]) => console.info(`[RBAC INFO] ${message}`, ...args),\n debug: (message: string, ...args: unknown[]) => console.debug(`[RBAC DEBUG] ${message}`, ...args),\n };\n }\n\n isDebugMode(): boolean {\n return this.config?.debug ?? false;\n }\n\n isDevelopmentMode(): boolean {\n return this.config?.developmentMode ?? false;\n }\n\n getMockPermissions(): Record<string, boolean> | null {\n return this.config?.mockPermissions ?? null;\n }\n}\n\n// Global config manager instance\nconst configManager = new RBACConfigManager();\n\nexport function createRBACConfig(config: RBACConfig): RBACConfig {\n configManager.setConfig(config);\n return config;\n}\n\nexport function getRBACConfig(): RBACConfig | null {\n return configManager.getConfig();\n}\n\nexport function getRBACLogger(): RBACLogger {\n return configManager.getLogger();\n}\n\nexport function isDebugMode(): boolean {\n return configManager.isDebugMode();\n}\n\nexport function isDevelopmentMode(): boolean {\n return configManager.isDevelopmentMode();\n}\n\nexport function getMockPermissions(): Record<string, boolean> | null {\n return configManager.getMockPermissions();\n}\n","/**\n * RBAC Main API Functions\n * @package @jmruthers/pace-core\n * @module RBAC/API\n * @since 1.0.0\n * \n * This module provides the main API functions for the RBAC system.\n */\n\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../types/database';\nimport {\n UUID,\n Scope,\n Permission,\n AccessLevel,\n PermissionMap,\n PermissionCheck,\n RBACNotInitializedError,\n OrganisationContextRequiredError,\n RBACAppContext,\n RBACRoleContext,\n} from './types';\nimport { createRBACEngine, RBACEngine } from './engine';\nimport { createAuditManager, setGlobalAuditManager } from './audit';\nimport { rbacCache, RBACCache, CACHE_PATTERNS } from './cache';\nimport { createRBACConfig, RBACConfig, getRBACLogger } from './config';\nimport { SecurityContext } from './security';\n\n// Global engine instance\nlet globalEngine: RBACEngine | null = null;\n\n/**\n * Setup RBAC system\n * \n * @param supabase - Supabase client\n * @param config - Optional configuration\n */\nexport function setupRBAC(supabase: SupabaseClient<Database>, config?: Partial<RBACConfig>): void {\n const logger = getRBACLogger();\n \n // Create full config\n const fullConfig: RBACConfig = {\n supabase,\n debug: import.meta.env.MODE === 'development',\n logLevel: 'warn',\n developmentMode: import.meta.env.MODE === 'development',\n ...config,\n };\n \n createRBACConfig(fullConfig);\n \n // Pass security config to engine if provided\n globalEngine = createRBACEngine(supabase, config?.security);\n \n // Setup audit manager\n const auditManager = createAuditManager(supabase);\n setGlobalAuditManager(auditManager);\n \n logger.info('RBAC system initialized successfully');\n}\n\n/**\n * Get the global RBAC engine\n * \n * @returns Global RBAC engine\n * @throws Error if RBAC not initialized\n */\nfunction getEngine(): RBACEngine {\n if (!globalEngine) {\n throw new RBACNotInitializedError();\n }\n return globalEngine;\n}\n\n/**\n * Get user's access level in a scope\n * \n * @param input - Access level input\n * @returns Promise resolving to access level\n * \n * @example\n * ```typescript\n * const accessLevel = await getAccessLevel({\n * userId: 'user-123',\n * scope: { organisationId: 'org-456' }\n * });\n * ```\n */\nexport async function getAccessLevel(input: {\n userId: UUID;\n scope: Scope;\n}): Promise<AccessLevel> {\n const engine = getEngine();\n return engine.getAccessLevel(input);\n}\n\n/**\n * Get user's permission map for a scope\n * \n * @param input - Permission map input\n * @returns Promise resolving to permission map\n * \n * @example\n * ```typescript\n * const permissions = await getPermissionMap({\n * userId: 'user-123',\n * scope: { \n * organisationId: 'org-456',\n * eventId: 'event-789',\n * appId: 'app-101'\n * }\n * });\n * ```\n */\nexport async function getPermissionMap(input: {\n userId: UUID;\n scope: Scope;\n}): Promise<PermissionMap> {\n const engine = getEngine();\n return engine.getPermissionMap(input);\n}\n\nexport async function resolveAppContext(input: {\n userId: UUID;\n appName: string;\n}): Promise<RBACAppContext | null> {\n const engine = getEngine();\n return engine.resolveAppContext(input);\n}\n\nexport async function getRoleContext(input: {\n userId: UUID;\n scope: Scope;\n}): Promise<RBACRoleContext> {\n const engine = getEngine();\n return engine.getRoleContext(input);\n}\n\n/**\n * Check if user has a specific permission\n * \n * @param input - Permission check input\n * @returns Promise resolving to permission result\n * \n * @example\n * ```typescript\n * const canManage = await isPermitted({\n * userId: 'user-123',\n * scope: { organisationId: 'org-456' },\n * permission: 'update:events',\n * pageId: 'page-789'\n * });\n * ```\n */\nexport async function isPermitted(input: PermissionCheck): Promise<boolean> {\n const engine = getEngine();\n \n // Validate organisation context is required\n if (!input.scope.organisationId) {\n throw new OrganisationContextRequiredError();\n }\n \n // Create security context from input\n // OrganisationId is required - it can always be derived from event context in event-based apps\n const securityContext: SecurityContext = {\n userId: input.userId,\n organisationId: input.scope.organisationId, // Required - no fallback\n timestamp: new Date(),\n // Optional fields can be omitted\n };\n \n return engine.isPermitted(input, securityContext);\n}\n\n/**\n * Check if user has a specific permission (cached version)\n * \n * @param input - Permission check input\n * @returns Promise resolving to permission result\n */\nexport async function isPermittedCached(input: PermissionCheck): Promise<boolean> {\n const { userId, scope, permission, pageId } = input;\n \n // Check cache first\n const cacheKey = RBACCache.generatePermissionKey({\n userId,\n organisationId: scope.organisationId!,\n eventId: scope.eventId,\n appId: scope.appId,\n permission,\n pageId,\n });\n \n const cached = rbacCache.get<boolean>(cacheKey);\n if (cached !== null) {\n return cached;\n }\n\n // Check permission\n const result = await isPermitted(input);\n \n // Cache result\n rbacCache.set(cacheKey, result);\n \n return result;\n}\n\n/**\n * Check if a user has a specific permission (alias for isPermitted)\n * \n * @param input - Permission check parameters\n * @returns Promise<boolean> - True if user has permission\n */\nexport async function hasPermission(input: PermissionCheck): Promise<boolean> {\n return isPermitted(input);\n}\n\n/**\n * Check if user has any of the specified permissions\n * \n * @param input - Permission check input with array of permissions\n * @returns Promise resolving to true if user has any permission\n */\nexport async function hasAnyPermission(input: {\n userId: UUID;\n scope: Scope;\n permissions: Permission[];\n pageId?: UUID;\n}): Promise<boolean> {\n const { permissions, ...baseInput } = input;\n \n for (const permission of permissions) {\n const hasPermission = await isPermitted({\n ...baseInput,\n permission,\n });\n \n if (hasPermission) {\n return true;\n }\n }\n \n return false;\n}\n\n/**\n * Check if user has all of the specified permissions\n * \n * @param input - Permission check input with array of permissions\n * @returns Promise resolving to true if user has all permissions\n */\nexport async function hasAllPermissions(input: {\n userId: UUID;\n scope: Scope;\n permissions: Permission[];\n pageId?: UUID;\n}): Promise<boolean> {\n const { permissions, ...baseInput } = input;\n \n for (const permission of permissions) {\n const hasPermission = await isPermitted({\n ...baseInput,\n permission,\n });\n \n if (!hasPermission) {\n return false;\n }\n }\n \n return true;\n}\n\n/**\n * Check if user is super admin\n * \n * @param userId - User ID\n * @returns Promise resolving to super admin status\n */\nexport async function isSuperAdmin(userId: UUID): Promise<boolean> {\n const engine = getEngine();\n return engine['checkSuperAdmin'](userId);\n}\n\n/**\n * Get app configuration including requires_event setting\n * \n * @param appId - App ID\n * @returns Promise resolving to app configuration\n */\nexport async function getAppConfig(appId: UUID): Promise<{ requires_event: boolean } | null> {\n // This function requires a Supabase client to be provided\n // Callers should pass the client as a parameter\n console.warn('[RBAC] getAppConfig called without Supabase client - returning null');\n return null;\n}\n\nexport async function getAppConfigWithClient(client: SupabaseClient, appId: UUID): Promise<{ requires_event: boolean } | null> {\n try {\n const { data, error } = await client\n .from('rbac_apps')\n .select('requires_event')\n .eq('id', appId)\n .eq('is_active', true)\n .single() as { data: { requires_event: boolean } | null; error: any };\n\n if (error || !data) {\n return null;\n }\n\n return { requires_event: data.requires_event };\n } catch (err) {\n console.error('[RBAC] Error fetching app config:', err);\n return null;\n }\n}\n\n/**\n * Check if user is organisation admin\n * \n * @param userId - User ID\n * @param organisationId - Organisation ID\n * @returns Promise resolving to organisation admin status\n */\nexport async function isOrganisationAdmin(userId: UUID, organisationId: UUID): Promise<boolean> {\n const accessLevel = await getAccessLevel({\n userId,\n scope: { organisationId },\n });\n \n return accessLevel === 'admin' || accessLevel === 'super';\n}\n\n/**\n * Check if user is event admin\n * \n * @param userId - User ID\n * @param scope - Permission scope with eventId and appId\n * @returns Promise resolving to event admin status\n */\nexport async function isEventAdmin(userId: UUID, scope: Scope): Promise<boolean> {\n if (!scope.eventId || !scope.appId) {\n return false;\n }\n \n const accessLevel = await getAccessLevel({ userId, scope });\n return accessLevel === 'admin' || accessLevel === 'super';\n}\n\n/**\n * Invalidate user's permission cache\n * \n * @param userId - User ID\n * @param organisationId - Organisation ID (optional)\n */\nexport function invalidateUserCache(userId: UUID, organisationId?: UUID): void {\n const patterns = organisationId\n ? [\n CACHE_PATTERNS.PERMISSION(userId, organisationId),\n `access:${userId}:${organisationId}:`,\n `map:${userId}:${organisationId}:`,\n ]\n : [\n `perm:${userId}:`,\n `access:${userId}:`,\n `map:${userId}:`,\n ];\n\n patterns.forEach(pattern => rbacCache.invalidate(pattern));\n}\n\n/**\n * Invalidate organisation's permission cache\n * \n * @param organisationId - Organisation ID\n */\nexport function invalidateOrganisationCache(organisationId: UUID): void {\n rbacCache.invalidate(CACHE_PATTERNS.ORGANISATION(organisationId));\n}\n\n/**\n * Invalidate event's permission cache\n * \n * @param eventId - Event ID\n */\nexport function invalidateEventCache(eventId: string): void {\n rbacCache.invalidate(CACHE_PATTERNS.EVENT(eventId));\n}\n\n/**\n * Invalidate app's permission cache\n * \n * @param appId - App ID\n */\nexport function invalidateAppCache(appId: UUID): void {\n rbacCache.invalidate(CACHE_PATTERNS.APP(appId));\n}\n\n/**\n * Clear all permission cache\n */\nexport function clearCache(): void {\n rbacCache.clear();\n}\n\n// Re-export OrganisationContextRequiredError for convenience\nexport { OrganisationContextRequiredError } from './types';\n"],"mappings":"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","names":["duration","hasPermission","isSuperAdmin","hasPermission"]}
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  useCan,
3
3
  useResolvedScope
4
- } from "./chunk-HADXAZT3.js";
4
+ } from "./chunk-UGVU7L7N.js";
5
5
  import {
6
6
  toast,
7
7
  useDataTablePerformance
8
8
  } from "./chunk-4OX5PXHX.js";
9
9
  import {
10
10
  init_UnifiedAuthProvider
11
- } from "./chunk-EYSXQ756.js";
11
+ } from "./chunk-TDFBX7KJ.js";
12
12
  import {
13
13
  useUnifiedAuth
14
- } from "./chunk-AUXS7XSO.js";
14
+ } from "./chunk-MW73E7SP.js";
15
15
  import {
16
16
  cn
17
17
  } from "./chunk-PYUXFQJ3.js";
@@ -12703,4 +12703,4 @@ lodash/lodash.js:
12703
12703
  * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
12704
12704
  *)
12705
12705
  */
12706
- //# sourceMappingURL=chunk-HGZSO43Y.js.map
12706
+ //# sourceMappingURL=chunk-TD4BXGPE.js.map
@@ -2,7 +2,7 @@ import {
2
2
  UnifiedAuthProvider,
3
3
  init_UnifiedAuthProvider,
4
4
  useUnifiedAuth
5
- } from "./chunk-AUXS7XSO.js";
5
+ } from "./chunk-MW73E7SP.js";
6
6
  import {
7
7
  __esm,
8
8
  __export
@@ -24,4 +24,4 @@ export {
24
24
  UnifiedAuthProvider_exports,
25
25
  init_UnifiedAuthProvider2 as init_UnifiedAuthProvider
26
26
  };
27
- //# sourceMappingURL=chunk-EYSXQ756.js.map
27
+ //# sourceMappingURL=chunk-TDFBX7KJ.js.map
@@ -6,16 +6,16 @@ import {
6
6
  isPermitted,
7
7
  isPermittedCached,
8
8
  resolveAppContext
9
- } from "./chunk-XRSP3H52.js";
9
+ } from "./chunk-PXXS26G5.js";
10
10
  import {
11
11
  init_useOrganisations,
12
12
  useEvents,
13
13
  useOrganisations
14
- } from "./chunk-EZ64QG2I.js";
14
+ } from "./chunk-I5YM5BGS.js";
15
15
  import {
16
16
  init_UnifiedAuthProvider,
17
17
  useUnifiedAuth
18
- } from "./chunk-AUXS7XSO.js";
18
+ } from "./chunk-MW73E7SP.js";
19
19
  import {
20
20
  getCurrentAppName
21
21
  } from "./chunk-JCQZ6LA7.js";
@@ -104,52 +104,6 @@ function useRBAC(pageId) {
104
104
  setIsLoading(false);
105
105
  }
106
106
  }, [appName, logger, resetState, selectedEvent?.event_id, selectedOrganisation?.id, session, user]);
107
- const hasPermission = useCallback(
108
- async (operationOrPermission, targetPageId) => {
109
- if (!user) {
110
- logger.warn("[useRBAC] Permission check attempted without authenticated user context");
111
- return false;
112
- }
113
- if (!currentScope || !currentScope.organisationId) {
114
- logger.error("[useRBAC] Permission check denied due to missing organisation context", {
115
- hasScope: !!currentScope,
116
- scope: currentScope,
117
- userId: user.id,
118
- permission: operationOrPermission
119
- });
120
- return false;
121
- }
122
- if (globalRole === "super_admin" || permissionMap["*"]) {
123
- logger.info("[useRBAC] Super admin bypass granted", {
124
- userId: user.id,
125
- permission: operationOrPermission
126
- });
127
- return true;
128
- }
129
- let permission;
130
- if (operationOrPermission.includes(":")) {
131
- permission = operationOrPermission;
132
- } else if (targetPageId || pageId) {
133
- permission = `${operationOrPermission}:${targetPageId || pageId}`;
134
- } else {
135
- permission = operationOrPermission;
136
- }
137
- const cachedValue = permissionMap[permission];
138
- if (cachedValue === true) {
139
- return true;
140
- }
141
- if (cachedValue === false) {
142
- return false;
143
- }
144
- return isPermittedCached({
145
- userId: user.id,
146
- scope: currentScope,
147
- permission,
148
- pageId: targetPageId ?? pageId
149
- });
150
- },
151
- [currentScope, globalRole, logger, pageId, permissionMap, user]
152
- );
153
107
  const hasGlobalPermission = useCallback(
154
108
  (permission) => {
155
109
  if (globalRole === "super_admin" || permissionMap["*"]) {
@@ -178,7 +132,6 @@ function useRBAC(pageId) {
178
132
  globalRole,
179
133
  organisationRole,
180
134
  eventAppRole,
181
- hasPermission,
182
135
  hasGlobalPermission,
183
136
  isSuperAdmin,
184
137
  isOrgAdmin,
@@ -227,22 +180,24 @@ function useResolvedScope({
227
180
  appId: "",
228
181
  eventId: void 0
229
182
  });
230
- if (resolvedScope && resolvedScope.organisationId) {
231
- const newScope = {
232
- organisationId: resolvedScope.organisationId,
233
- appId: resolvedScope.appId,
234
- eventId: resolvedScope.eventId
235
- };
236
- if (stableScopeRef.current.organisationId !== newScope.organisationId || stableScopeRef.current.eventId !== newScope.eventId || stableScopeRef.current.appId !== newScope.appId) {
237
- stableScopeRef.current = {
238
- organisationId: newScope.organisationId,
239
- appId: newScope.appId || "",
240
- eventId: newScope.eventId
183
+ useEffect2(() => {
184
+ if (resolvedScope && resolvedScope.organisationId) {
185
+ const newScope = {
186
+ organisationId: resolvedScope.organisationId,
187
+ appId: resolvedScope.appId,
188
+ eventId: resolvedScope.eventId
241
189
  };
190
+ if (stableScopeRef.current.organisationId !== newScope.organisationId || stableScopeRef.current.eventId !== newScope.eventId || stableScopeRef.current.appId !== newScope.appId) {
191
+ stableScopeRef.current = {
192
+ organisationId: newScope.organisationId,
193
+ appId: newScope.appId || "",
194
+ eventId: newScope.eventId
195
+ };
196
+ }
197
+ } else if (!resolvedScope) {
198
+ stableScopeRef.current = { organisationId: "", appId: "", eventId: void 0 };
242
199
  }
243
- } else if (!resolvedScope) {
244
- stableScopeRef.current = { organisationId: "", appId: "", eventId: void 0 };
245
- }
200
+ }, [resolvedScope]);
246
201
  const stableScope = stableScopeRef.current;
247
202
  useEffect2(() => {
248
203
  let cancelled = false;
@@ -271,14 +226,7 @@ function useResolvedScope({
271
226
  }
272
227
  }
273
228
  }
274
- console.log("[useResolvedScope] Attempting to resolve scope:", {
275
- selectedOrganisationId,
276
- selectedEventId,
277
- appId: appId || "NOT RESOLVED YET",
278
- resolveStep: "initial"
279
- });
280
229
  if (selectedOrganisationId && selectedEventId) {
281
- console.log("[useResolvedScope] Resolving with both org and event");
282
230
  if (!cancelled) {
283
231
  setResolvedScope({
284
232
  organisationId: selectedOrganisationId,
@@ -290,7 +238,6 @@ function useResolvedScope({
290
238
  return;
291
239
  }
292
240
  if (selectedOrganisationId) {
293
- console.log("[useResolvedScope] Resolving with organisation only");
294
241
  if (!cancelled) {
295
242
  setResolvedScope({
296
243
  organisationId: selectedOrganisationId,
@@ -303,7 +250,6 @@ function useResolvedScope({
303
250
  }
304
251
  if (selectedEventId && supabase) {
305
252
  try {
306
- console.log("[useResolvedScope] Resolving from event:", { selectedEventId, appId });
307
253
  const eventScope = await createScopeFromEvent(supabase, selectedEventId, appId);
308
254
  if (!eventScope) {
309
255
  console.error("[useResolvedScope] Could not resolve organization from event context");
@@ -314,7 +260,6 @@ function useResolvedScope({
314
260
  }
315
261
  return;
316
262
  }
317
- console.log("[useResolvedScope] Resolved from event:", eventScope);
318
263
  if (!cancelled) {
319
264
  setResolvedScope({
320
265
  ...eventScope,
@@ -364,6 +309,18 @@ function usePermissions(userId, scope) {
364
309
  const [isLoading, setIsLoading] = useState3(true);
365
310
  const [error, setError] = useState3(null);
366
311
  const isFetchingRef = useRef2(false);
312
+ useEffect3(() => {
313
+ if (!scope.organisationId || scope.organisationId === null || typeof scope.organisationId === "string" && scope.organisationId.trim() === "") {
314
+ const timeoutId = setTimeout(() => {
315
+ setError(new Error("Organisation context is required for permission checks"));
316
+ setIsLoading(false);
317
+ }, 3e3);
318
+ return () => clearTimeout(timeoutId);
319
+ }
320
+ if (error?.message === "Organisation context is required for permission checks") {
321
+ setError(null);
322
+ }
323
+ }, [scope.organisationId, error]);
367
324
  useEffect3(() => {
368
325
  const fetchPermissions = async () => {
369
326
  if (isFetchingRef.current) {
@@ -374,7 +331,7 @@ function usePermissions(userId, scope) {
374
331
  setIsLoading(false);
375
332
  return;
376
333
  }
377
- if (!scope.organisationId || scope.organisationId.trim() === "") {
334
+ if (!scope.organisationId || scope.organisationId === null || typeof scope.organisationId === "string" && scope.organisationId.trim() === "") {
378
335
  setPermissions({});
379
336
  setIsLoading(true);
380
337
  setError(null);
@@ -422,7 +379,7 @@ function usePermissions(userId, scope) {
422
379
  setIsLoading(false);
423
380
  return;
424
381
  }
425
- if (!scope.organisationId || scope.organisationId.trim() === "") {
382
+ if (!scope.organisationId || scope.organisationId === null || typeof scope.organisationId === "string" && scope.organisationId.trim() === "") {
426
383
  setPermissions({});
427
384
  setIsLoading(true);
428
385
  setError(null);
@@ -455,6 +412,19 @@ function useCan(userId, scope, permission, pageId, useCache = true) {
455
412
  const [can, setCan] = useState3(false);
456
413
  const [isLoading, setIsLoading] = useState3(true);
457
414
  const [error, setError] = useState3(null);
415
+ useEffect3(() => {
416
+ if (!scope.organisationId || scope.organisationId === null || typeof scope.organisationId === "string" && scope.organisationId.trim() === "") {
417
+ const timeoutId = setTimeout(() => {
418
+ setError(new Error("Organisation context is required for permission checks"));
419
+ setIsLoading(false);
420
+ setCan(false);
421
+ }, 3e3);
422
+ return () => clearTimeout(timeoutId);
423
+ }
424
+ if (error?.message === "Organisation context is required for permission checks") {
425
+ setError(null);
426
+ }
427
+ }, [scope.organisationId, error]);
458
428
  const lastUserIdRef = useRef2(null);
459
429
  const lastScopeRef = useRef2(null);
460
430
  const lastPermissionRef = useRef2(null);
@@ -474,25 +444,16 @@ function useCan(userId, scope, permission, pageId, useCache = true) {
474
444
  setIsLoading(false);
475
445
  return;
476
446
  }
477
- if (!scope.organisationId || scope.organisationId.trim() === "") {
478
- console.log("[useCan] Invalid scope - organisationId is empty:", { scope, permission, pageId });
479
- setCan(false);
447
+ if (!scope.organisationId || scope.organisationId === null || typeof scope.organisationId === "string" && scope.organisationId.trim() === "") {
480
448
  setIsLoading(true);
449
+ setCan(false);
450
+ setError(null);
481
451
  return;
482
452
  }
483
453
  try {
484
454
  setIsLoading(true);
485
455
  setError(null);
486
- console.log("[useCan] Checking permission:", {
487
- userId,
488
- organisationId: scope.organisationId,
489
- eventId: scope.eventId,
490
- appId: scope.appId,
491
- permission,
492
- pageId
493
- });
494
456
  const result = useCache ? await isPermittedCached({ userId, scope, permission, pageId }) : await isPermitted({ userId, scope, permission, pageId });
495
- console.log("[useCan] Permission check result:", { permission, result, pageId });
496
457
  setCan(result);
497
458
  } catch (err) {
498
459
  console.error("[useCan] Permission check error:", { permission, error: err });
@@ -511,9 +472,10 @@ function useCan(userId, scope, permission, pageId, useCache = true) {
511
472
  setIsLoading(false);
512
473
  return;
513
474
  }
514
- if (!scope.organisationId || scope.organisationId.trim() === "") {
475
+ if (!scope.organisationId || scope.organisationId === null || typeof scope.organisationId === "string" && scope.organisationId.trim() === "") {
515
476
  setCan(false);
516
477
  setIsLoading(true);
478
+ setError(null);
517
479
  return;
518
480
  }
519
481
  try {
@@ -729,4 +691,4 @@ export {
729
691
  useHasAllPermissions,
730
692
  useCachedPermissions
731
693
  };
732
- //# sourceMappingURL=chunk-HADXAZT3.js.map
694
+ //# sourceMappingURL=chunk-UGVU7L7N.js.map