@jmruthers/pace-core 0.5.190 → 0.5.191

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 (249) hide show
  1. package/dist/{DataTable-IVYljGJ6.d.ts → DataTable-Be6dH_dR.d.ts} +1 -1
  2. package/dist/{DataTable-ON3IXISJ.js → DataTable-WKRZD47S.js} +6 -6
  3. package/dist/{PublicPageProvider-C4uxosp6.d.ts → PublicPageProvider-ULXC_u6U.d.ts} +1 -1
  4. package/dist/{UnifiedAuthProvider-X5NXANVI.js → UnifiedAuthProvider-FTSG5XH7.js} +3 -3
  5. package/dist/{api-I6UCQ5S6.js → api-IHKALJZD.js} +2 -2
  6. package/dist/{chunk-J2XXC7R5.js → chunk-6LTQQAT6.js} +77 -111
  7. package/dist/chunk-6LTQQAT6.js.map +1 -0
  8. package/dist/{chunk-STYK4OH2.js → chunk-6TQDD426.js} +10 -10
  9. package/dist/chunk-6TQDD426.js.map +1 -0
  10. package/dist/{chunk-DZWK57KZ.js → chunk-G37KK66H.js} +1 -1
  11. package/dist/{chunk-DZWK57KZ.js.map → chunk-G37KK66H.js.map} +1 -1
  12. package/dist/{chunk-73HSNNOQ.js → chunk-LOMZXPSN.js} +13 -13
  13. package/dist/{chunk-Y4BUBBHD.js → chunk-OETXORNB.js} +3 -3
  14. package/dist/{chunk-RUYZKXOD.js → chunk-ROXMHMY2.js} +5 -3
  15. package/dist/chunk-ROXMHMY2.js.map +1 -0
  16. package/dist/{chunk-SDMHPX3X.js → chunk-ULHIJK66.js} +56 -21
  17. package/dist/{chunk-SDMHPX3X.js.map → chunk-ULHIJK66.js.map} +1 -1
  18. package/dist/{chunk-VVBAW5A5.js → chunk-VKB2CO4Z.js} +46 -35
  19. package/dist/chunk-VKB2CO4Z.js.map +1 -0
  20. package/dist/{chunk-HQVPB5MZ.js → chunk-VRGWKHDB.js} +6 -6
  21. package/dist/{chunk-NIU6J6OX.js → chunk-XNYQOL3Z.js} +16 -16
  22. package/dist/chunk-XNYQOL3Z.js.map +1 -0
  23. package/dist/{chunk-4QYC5L4K.js → chunk-XYXSXPUK.js} +22 -27
  24. package/dist/chunk-XYXSXPUK.js.map +1 -0
  25. package/dist/components.d.ts +3 -3
  26. package/dist/components.js +8 -8
  27. package/dist/{database.generated-DI89OQeI.d.ts → database.generated-CzIvgcPu.d.ts} +165 -201
  28. package/dist/hooks.d.ts +12 -12
  29. package/dist/hooks.js +7 -7
  30. package/dist/index.d.ts +7 -7
  31. package/dist/index.js +18 -23
  32. package/dist/index.js.map +1 -1
  33. package/dist/providers.js +2 -2
  34. package/dist/rbac/index.d.ts +1 -1
  35. package/dist/rbac/index.js +6 -6
  36. package/dist/{types-Bwgl--Xo.d.ts → types-CEpcvwwF.d.ts} +1 -1
  37. package/dist/types.d.ts +2 -2
  38. package/dist/{usePublicRouteParams-DxIDS4bC.d.ts → usePublicRouteParams-TZe0gy-4.d.ts} +1 -1
  39. package/dist/utils.d.ts +8 -8
  40. package/dist/utils.js +2 -2
  41. package/docs/api/classes/ColumnFactory.md +1 -1
  42. package/docs/api/classes/ErrorBoundary.md +1 -1
  43. package/docs/api/classes/InvalidScopeError.md +1 -1
  44. package/docs/api/classes/Logger.md +1 -1
  45. package/docs/api/classes/MissingUserContextError.md +1 -1
  46. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  47. package/docs/api/classes/PermissionDeniedError.md +1 -1
  48. package/docs/api/classes/RBACAuditManager.md +2 -2
  49. package/docs/api/classes/RBACCache.md +1 -1
  50. package/docs/api/classes/RBACEngine.md +2 -2
  51. package/docs/api/classes/RBACError.md +1 -1
  52. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  53. package/docs/api/classes/SecureSupabaseClient.md +5 -5
  54. package/docs/api/classes/StorageUtils.md +1 -1
  55. package/docs/api/enums/FileCategory.md +1 -1
  56. package/docs/api/enums/LogLevel.md +1 -1
  57. package/docs/api/enums/RBACErrorCode.md +1 -1
  58. package/docs/api/enums/RPCFunction.md +1 -1
  59. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  60. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  61. package/docs/api/interfaces/AggregateConfig.md +1 -1
  62. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  63. package/docs/api/interfaces/AvatarProps.md +1 -1
  64. package/docs/api/interfaces/BadgeProps.md +1 -1
  65. package/docs/api/interfaces/ButtonProps.md +1 -1
  66. package/docs/api/interfaces/CalendarProps.md +1 -1
  67. package/docs/api/interfaces/CardProps.md +1 -1
  68. package/docs/api/interfaces/ColorPalette.md +1 -1
  69. package/docs/api/interfaces/ColorShade.md +1 -1
  70. package/docs/api/interfaces/ComplianceResult.md +1 -1
  71. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  72. package/docs/api/interfaces/DataRecord.md +1 -1
  73. package/docs/api/interfaces/DataTableAction.md +1 -1
  74. package/docs/api/interfaces/DataTableColumn.md +1 -1
  75. package/docs/api/interfaces/DataTableProps.md +1 -1
  76. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  77. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  78. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  79. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  80. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  81. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  82. package/docs/api/interfaces/ExportColumn.md +1 -1
  83. package/docs/api/interfaces/ExportOptions.md +1 -1
  84. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  85. package/docs/api/interfaces/FileMetadata.md +1 -1
  86. package/docs/api/interfaces/FileReference.md +1 -1
  87. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  88. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  89. package/docs/api/interfaces/FileUploadProps.md +1 -1
  90. package/docs/api/interfaces/FooterProps.md +1 -1
  91. package/docs/api/interfaces/FormFieldProps.md +1 -1
  92. package/docs/api/interfaces/FormProps.md +1 -1
  93. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  94. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  95. package/docs/api/interfaces/InputProps.md +1 -1
  96. package/docs/api/interfaces/LabelProps.md +1 -1
  97. package/docs/api/interfaces/LoggerConfig.md +1 -1
  98. package/docs/api/interfaces/LoginFormProps.md +1 -1
  99. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  100. package/docs/api/interfaces/NavigationContextType.md +1 -1
  101. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  102. package/docs/api/interfaces/NavigationItem.md +1 -1
  103. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  104. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  105. package/docs/api/interfaces/Organisation.md +1 -1
  106. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  107. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  108. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  109. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  110. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  111. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  112. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  113. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  114. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  115. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  116. package/docs/api/interfaces/PaletteData.md +1 -1
  117. package/docs/api/interfaces/ParsedAddress.md +2 -2
  118. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  119. package/docs/api/interfaces/ProgressProps.md +1 -1
  120. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  121. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  122. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  123. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  124. package/docs/api/interfaces/QuickFix.md +1 -1
  125. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  126. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  127. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  128. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  129. package/docs/api/interfaces/RBACConfig.md +2 -2
  130. package/docs/api/interfaces/RBACContext.md +1 -1
  131. package/docs/api/interfaces/RBACLogger.md +1 -1
  132. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  133. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  134. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  135. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  136. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  137. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  138. package/docs/api/interfaces/RBACResult.md +1 -1
  139. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  140. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  141. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  142. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  143. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  144. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  145. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  146. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  147. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  148. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  149. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  150. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  151. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  152. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  153. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  154. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  155. package/docs/api/interfaces/RouteConfig.md +1 -1
  156. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  157. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  158. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  159. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  160. package/docs/api/interfaces/SetupIssue.md +1 -1
  161. package/docs/api/interfaces/StorageConfig.md +1 -1
  162. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  163. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  164. package/docs/api/interfaces/StorageListOptions.md +1 -1
  165. package/docs/api/interfaces/StorageListResult.md +1 -1
  166. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  167. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  168. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  169. package/docs/api/interfaces/StyleImport.md +1 -1
  170. package/docs/api/interfaces/SwitchProps.md +1 -1
  171. package/docs/api/interfaces/TabsContentProps.md +1 -1
  172. package/docs/api/interfaces/TabsListProps.md +1 -1
  173. package/docs/api/interfaces/TabsProps.md +1 -1
  174. package/docs/api/interfaces/TabsTriggerProps.md +1 -1
  175. package/docs/api/interfaces/TextareaProps.md +1 -1
  176. package/docs/api/interfaces/ToastActionElement.md +1 -1
  177. package/docs/api/interfaces/ToastProps.md +1 -1
  178. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  179. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  180. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  181. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  182. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  183. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  184. package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
  185. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  186. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  187. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  188. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
  189. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  190. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  191. package/docs/api/interfaces/UseResolvedScopeOptions.md +2 -2
  192. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  193. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  194. package/docs/api/interfaces/UserEventAccess.md +1 -1
  195. package/docs/api/interfaces/UserMenuProps.md +1 -1
  196. package/docs/api/interfaces/UserProfile.md +1 -1
  197. package/docs/api/modules.md +16 -16
  198. package/docs/migration/README.md +18 -0
  199. package/docs/migration/database-changes-december-2025.md +767 -0
  200. package/docs/migration/person-scoped-profiles-migration-guide.md +472 -0
  201. package/package.json +1 -1
  202. package/src/__tests__/public-recipe-view.test.ts +10 -10
  203. package/src/__tests__/rls-policies.test.ts +13 -13
  204. package/src/components/AddressField/README.md +6 -6
  205. package/src/components/OrganisationSelector/OrganisationSelector.tsx +35 -15
  206. package/src/components/Select/Select.test.tsx +4 -1
  207. package/src/components/Select/Select.tsx +60 -15
  208. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +192 -0
  209. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +741 -0
  210. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +703 -0
  211. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +581 -0
  212. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +9 -8
  213. package/src/hooks/public/usePublicEvent.ts +8 -8
  214. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  215. package/src/hooks/useFileDisplay.ts +8 -9
  216. package/src/hooks/useQueryCache.ts +6 -6
  217. package/src/hooks/useSecureDataAccess.test.ts +8 -8
  218. package/src/hooks/useSecureDataAccess.ts +15 -11
  219. package/src/providers/__tests__/OrganisationProvider.test.tsx +27 -21
  220. package/src/rbac/hooks/useRBAC.simple.test.ts +95 -0
  221. package/src/rbac/utils/__tests__/eventContext.test.ts +2 -2
  222. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +490 -0
  223. package/src/rbac/utils/eventContext.ts +5 -2
  224. package/src/services/AuthService.ts +37 -8
  225. package/src/services/OrganisationService.ts +92 -139
  226. package/src/services/__tests__/OrganisationService.pagination.test.ts +34 -8
  227. package/src/services/__tests__/OrganisationService.test.ts +218 -86
  228. package/src/types/database.generated.ts +166 -201
  229. package/src/types/supabase.ts +2 -2
  230. package/src/utils/__tests__/secureDataAccess.unit.test.ts +3 -2
  231. package/src/utils/file-reference/index.ts +4 -4
  232. package/src/utils/google-places/googlePlacesUtils.ts +1 -1
  233. package/src/utils/google-places/types.ts +1 -1
  234. package/src/utils/request-deduplication.ts +4 -4
  235. package/src/utils/security/secureDataAccess.test.ts +1 -1
  236. package/src/utils/security/secureDataAccess.ts +7 -4
  237. package/src/utils/storage/README.md +1 -1
  238. package/dist/chunk-4QYC5L4K.js.map +0 -1
  239. package/dist/chunk-J2XXC7R5.js.map +0 -1
  240. package/dist/chunk-NIU6J6OX.js.map +0 -1
  241. package/dist/chunk-RUYZKXOD.js.map +0 -1
  242. package/dist/chunk-STYK4OH2.js.map +0 -1
  243. package/dist/chunk-VVBAW5A5.js.map +0 -1
  244. /package/dist/{DataTable-ON3IXISJ.js.map → DataTable-WKRZD47S.js.map} +0 -0
  245. /package/dist/{UnifiedAuthProvider-X5NXANVI.js.map → UnifiedAuthProvider-FTSG5XH7.js.map} +0 -0
  246. /package/dist/{api-I6UCQ5S6.js.map → api-IHKALJZD.js.map} +0 -0
  247. /package/dist/{chunk-73HSNNOQ.js.map → chunk-LOMZXPSN.js.map} +0 -0
  248. /package/dist/{chunk-Y4BUBBHD.js.map → chunk-OETXORNB.js.map} +0 -0
  249. /package/dist/{chunk-HQVPB5MZ.js.map → chunk-VRGWKHDB.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/rbac/types.ts","../src/rbac/cache.ts","../src/rbac/cache-invalidation.ts","../src/rbac/errors.ts","../src/rbac/utils/eventContext.ts","../src/rbac/utils/contextValidator.ts","../src/rbac/security.ts","../src/rbac/config.ts","../src/rbac/engine.ts","../src/rbac/performance.ts","../src/rbac/request-deduplication.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';\nimport type { AppId, PageId } from '../types/core';\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?: AppId | UUID;\n};\n\nexport type PermissionCheck = {\n userId: UUID;\n scope: Scope;\n permission: Permission;\n pageId?: PageId | UUID;\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 EventContextRequiredError extends RBACError {\n constructor() {\n super(\n 'Event context is required for this operation',\n 'EVENT_CONTEXT_REQUIRED'\n );\n this.name = 'EventContextRequiredError';\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 two-tier caching:\n * - Short-term cache: 120 seconds for frequently changing permissions\n * - Session cache: 15 minutes for stable permissions (page-level checks)\n */\nexport class RBACCache {\n private cache = new Map<string, CacheEntry<any>>();\n private sessionCache = new Map<string, CacheEntry<any>>();\n private readonly TTL = 120 * 1000; // 120 seconds (short-term) - increased from 60s\n private readonly SESSION_TTL = 15 * 60 * 1000; // 15 minutes (session-level) - increased from 5min\n private invalidationCallbacks: Set<(pattern: string) => void> = new Set();\n\n /**\n * Get a value from the cache\n * \n * Checks both short-term cache and session cache.\n * \n * @param key - Cache key\n * @param useSessionCache - Whether to check session cache (default: true)\n * @returns Cached value or null if not found/expired\n */\n get<T>(key: string, useSessionCache: boolean = true): T | null {\n const now = Date.now();\n \n // Check short-term cache first\n const entry = this.cache.get(key);\n if (entry && now <= entry.expires) {\n return entry.data as T;\n }\n if (entry && now > entry.expires) {\n this.cache.delete(key);\n }\n \n // Check session cache if enabled\n if (useSessionCache) {\n const sessionEntry = this.sessionCache.get(key);\n if (sessionEntry && now <= sessionEntry.expires) {\n return sessionEntry.data as T;\n }\n if (sessionEntry && now > sessionEntry.expires) {\n this.sessionCache.delete(key);\n }\n }\n \n return null;\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 * @param useSessionCache - Whether to also store in session cache (default: false for page-level checks)\n */\n set<T>(key: string, data: T, ttl: number = this.TTL, useSessionCache: boolean = false): void {\n const now = Date.now();\n // For zero or negative TTL, set expires to current time to make it immediately expired\n const expires = ttl <= 0 ? now - 1 : now + ttl;\n \n // Always store in short-term cache\n this.cache.set(key, {\n data,\n expires,\n });\n \n // Optionally store in session cache for page-level permissions\n if (useSessionCache) {\n const sessionExpires = ttl <= 0 ? now - 1 : now + this.SESSION_TTL;\n this.sessionCache.set(key, {\n data,\n expires: sessionExpires,\n });\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 this.sessionCache.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 // Invalidate from both caches\n for (const key of this.cache.keys()) {\n if (matcher(key)) {\n keysToDelete.push(key);\n }\n }\n \n for (const key of this.sessionCache.keys()) {\n if (matcher(key) && !keysToDelete.includes(key)) {\n keysToDelete.push(key);\n }\n }\n\n keysToDelete.forEach(key => {\n this.cache.delete(key);\n this.sessionCache.delete(key);\n });\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 this.sessionCache.clear();\n }\n\n /**\n * Get cache statistics\n */\n getStats(): {\n size: number;\n sessionSize: number;\n ttl: number;\n sessionTtl: number;\n keys: string[];\n } {\n return {\n size: this.cache.size,\n sessionSize: this.sessionCache.size,\n ttl: this.TTL,\n sessionTtl: this.SESSION_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';\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('RBACCache');\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 private channels: Array<{ unsubscribe: () => void }> = [];\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 log.debug(`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 log.warn('Failed to log cache invalidation audit event:', error);\n });\n }\n\n /**\n * Cleanup subscriptions only (not all callbacks)\n * Used internally to cleanup before setting up new subscriptions\n */\n private cleanupSubscriptions(): void {\n this.channels.forEach(channel => {\n try {\n if (channel && typeof channel.unsubscribe === 'function') {\n channel.unsubscribe();\n }\n } catch (error) {\n log.warn('Failed to unsubscribe from channel:', error);\n }\n });\n this.channels = [];\n }\n\n /**\n * Setup realtime subscriptions for automatic cache invalidation\n * Always cleans up existing subscriptions before setting up new ones to prevent duplicates\n */\n private setupRealtimeSubscriptions(): void {\n // Always cleanup existing subscriptions first to prevent duplicates\n this.cleanupSubscriptions();\n \n // Check if realtime is available (skip in test environments)\n if (!this.supabase.channel || typeof this.supabase.channel !== 'function') {\n log.debug('Realtime not available, skipping subscriptions');\n return;\n }\n\n // Subscribe to organisation role changes\n const orgRolesChannel = 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 const orgRolesSubscription = orgRolesChannel.subscribe();\n this.channels.push(orgRolesSubscription);\n\n // Subscribe to event app role changes\n const eventAppRolesChannel = 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 const eventAppRolesSubscription = eventAppRolesChannel.subscribe();\n this.channels.push(eventAppRolesSubscription);\n\n // Subscribe to global role changes\n const globalRolesChannel = 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 const globalRolesSubscription = globalRolesChannel.subscribe();\n this.channels.push(globalRolesSubscription);\n\n // Subscribe to page permission changes\n const pagePermissionsChannel = 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 const pagePermissionsSubscription = pagePermissionsChannel.subscribe();\n this.channels.push(pagePermissionsSubscription);\n }\n\n /**\n * Cleanup all realtime subscriptions\n * Call this when the manager is no longer needed to prevent memory leaks\n */\n cleanup(): void {\n // Unsubscribe from all channels\n this.channels.forEach(channel => {\n try {\n if (channel && typeof channel.unsubscribe === 'function') {\n channel.unsubscribe();\n }\n } catch (error) {\n log.warn('Failed to unsubscribe from channel:', error);\n }\n });\n this.channels = [];\n \n // Clear all callbacks\n this.invalidationCallbacks.clear();\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 log.debug('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 * Ensures only one instance exists per application lifecycle\n * \n * @param supabase - Supabase client\n * @returns Cache invalidation manager instance\n */\nexport function initializeCacheInvalidation(supabase: SupabaseClient<Database>): RBACCacheInvalidationManager {\n // Clean up existing manager if it exists (e.g., when switching Supabase clients)\n if (globalCacheInvalidationManager) {\n log.debug('Cleaning up existing cache invalidation manager before creating new one');\n globalCacheInvalidationManager.cleanup();\n }\n \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\n/**\n * Cleanup the global cache invalidation manager\n * Call this when the application is shutting down or when switching Supabase clients\n */\nexport function cleanupCacheInvalidation(): void {\n if (globalCacheInvalidationManager) {\n globalCacheInvalidationManager.cleanup();\n globalCacheInvalidationManager = null;\n }\n}\n","import {\n RBACError,\n PermissionDeniedError,\n OrganisationContextRequiredError,\n InvalidScopeError,\n MissingUserContextError,\n RBACNotInitializedError,\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// Re-export error classes for convenience\nexport {\n RBACError,\n PermissionDeniedError,\n OrganisationContextRequiredError,\n InvalidScopeError,\n MissingUserContextError,\n RBACNotInitializedError,\n};\n","/**\n * Event Context Utilities for RBAC\n * @package @jmruthers/pace-core\n * @module RBAC/EventContext\n * @since 1.0.0\n * \n * This module provides utilities for event-based RBAC operations where\n * the organization context is derived from the event context.\n */\n\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../../types/database';\nimport { UUID, Scope } from '../types';\n\n/**\n * Cache for organisation derivation from event\n * Key: eventId, Value: organisationId | null\n * Maximum cache size to prevent memory leaks\n */\nconst orgDerivationCache = new Map<string, UUID | null>();\nconst MAX_CACHE_SIZE = 100; // Limit cache to 100 entries\n\n/**\n * Clear cache entry for a specific event (useful if event's org changes)\n * @param eventId - Event ID to clear from cache\n */\nexport function clearOrgDerivationCache(eventId: string): void {\n orgDerivationCache.delete(eventId);\n}\n\n/**\n * Clear all cached organisation derivations\n */\nexport function clearAllOrgDerivationCache(): void {\n orgDerivationCache.clear();\n}\n\n/**\n * Get organization ID from event ID\n * \n * Uses caching to avoid repeated database queries for the same event.\n * Cache is limited to prevent memory leaks.\n * \n * @param supabase - Supabase client\n * @param eventId - Event ID\n * @returns Promise resolving to organization ID or null\n */\nexport async function getOrganisationFromEvent(\n supabase: SupabaseClient<Database>,\n eventId: string\n): Promise<UUID | null> {\n // Check cache first\n if (orgDerivationCache.has(eventId)) {\n return orgDerivationCache.get(eventId) ?? null;\n }\n\n // Query database\n const { data, error } = await supabase\n .from('event')\n .select('organisation_id')\n .eq('event_id', eventId)\n .single() as { data: { organisation_id: string } | null; error: any };\n\n let organisationId: UUID | null = null;\n\n if (error || !data) {\n organisationId = null;\n } else {\n organisationId = data.organisation_id;\n }\n\n // Cache the result (with size limit to prevent memory leaks)\n if (orgDerivationCache.size >= MAX_CACHE_SIZE) {\n // Remove oldest entry (first key in Map)\n const firstKey = orgDerivationCache.keys().next().value;\n if (firstKey) {\n orgDerivationCache.delete(firstKey);\n }\n }\n orgDerivationCache.set(eventId, organisationId);\n\n return organisationId;\n}\n\n/**\n * Create a complete scope from event context\n * \n * @param supabase - Supabase client\n * @param eventId - Event ID\n * @param appId - Optional app ID\n * @returns Promise resolving to complete scope\n */\nexport async function createScopeFromEvent(\n supabase: SupabaseClient<Database>,\n eventId: string,\n appId?: UUID\n): Promise<Scope | null> {\n const organisationId = await getOrganisationFromEvent(supabase, eventId);\n \n if (!organisationId) {\n return null;\n }\n\n return {\n organisationId,\n eventId,\n appId\n };\n}\n\n/**\n * Check if a scope is event-based (has eventId but no explicit organisationId)\n * \n * @param scope - Permission scope\n * @returns True if scope is event-based\n */\nexport function isEventBasedScope(scope: Scope): boolean {\n return !scope.organisationId && !!scope.eventId;\n}\n\n/**\n * Validate that an event-based scope has the required context\n * \n * @param scope - Permission scope\n * @returns True if scope is valid for event-based operations\n */\nexport function isValidEventBasedScope(scope: Scope): boolean {\n return isEventBasedScope(scope) && !!scope.eventId;\n}\n","/**\n * Context Validator for RBAC\n * @package @jmruthers/pace-core\n * @module RBAC/ContextValidator\n * @since 1.0.0\n * \n * Centralized validation for RBAC context requirements based on app configuration.\n * Enforces app-specific context rules with single primary context:\n * - requires_event = TRUE: Event is PRIMARY context, org derived from event (org not required in input)\n * - requires_event = FALSE: Organisation is PRIMARY context, event optional\n * - PORTAL/ADMIN apps: Both contexts optional (allows users to view/edit own profiles, super admin access)\n * \n * Key principle: Only one primary context is required based on app config. The other is derived or optional.\n */\n\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../../types/database';\nimport { UUID, Scope } from '../types';\nimport { EventContextRequiredError, OrganisationContextRequiredError } from '../types';\nimport { getOrganisationFromEvent } from './eventContext';\nimport { createLogger } from '../../utils/core/logger';\n\nconst log = createLogger('ContextValidator');\n\nexport interface AppConfig {\n requires_event: boolean;\n}\n\n/**\n * Check if an app allows optional contexts (both organisation and event optional)\n * @param appName - App name to check\n * @returns True if app allows optional contexts\n */\nfunction allowsOptionalContexts(appName?: string): boolean {\n return appName === 'PORTAL' || appName === 'ADMIN';\n}\n\nexport interface ContextValidationResult {\n isValid: boolean;\n resolvedScope: Scope | null;\n error: Error | null;\n}\n\n/**\n * Context Validator class\n * \n * Validates and resolves RBAC scope based on app configuration requirements.\n */\nexport class ContextValidator {\n /**\n * Validate scope against app requirements\n * \n * @param scope - Current scope\n * @param appConfig - App configuration (requires_event flag)\n * @param appName - App name (for PORTAL/ADMIN special case)\n * @returns Validation result with resolved scope\n */\n static async validateScope(\n scope: Scope,\n appConfig: AppConfig | null,\n appName?: string\n ): Promise<ContextValidationResult> {\n // PORTAL/ADMIN special case: both contexts optional\n if (allowsOptionalContexts(appName)) {\n return {\n isValid: true,\n resolvedScope: {\n organisationId: scope.organisationId,\n eventId: scope.eventId,\n appId: scope.appId\n },\n error: null\n };\n }\n\n // If no app config, default to requiring org context\n if (!appConfig) {\n if (!scope.organisationId) {\n return {\n isValid: false,\n resolvedScope: null,\n error: new OrganisationContextRequiredError()\n };\n }\n return {\n isValid: true,\n resolvedScope: scope,\n error: null\n };\n }\n\n // Event-required apps: must have eventId, derive org from event\n if (appConfig.requires_event) {\n if (!scope.eventId) {\n return {\n isValid: false,\n resolvedScope: null,\n error: new EventContextRequiredError()\n };\n }\n\n // If org is not provided, we'll need to derive it from event\n // But for validation, we just check that eventId exists\n // The actual derivation happens in resolveRequiredContext\n return {\n isValid: true,\n resolvedScope: scope,\n error: null\n };\n }\n\n // Org-required apps: must have organisationId, eventId optional\n if (!scope.organisationId) {\n return {\n isValid: false,\n resolvedScope: null,\n error: new OrganisationContextRequiredError()\n };\n }\n\n return {\n isValid: true,\n resolvedScope: scope,\n error: null\n };\n }\n\n /**\n * Resolve required context and derive missing values\n * \n * @param scope - Current scope\n * @param appConfig - App configuration\n * @param appName - App name (for PORTAL/ADMIN special case)\n * @param supabase - Supabase client (for deriving org from event)\n * @returns Resolved scope with all required context\n */\n static async resolveRequiredContext(\n scope: Scope,\n appConfig: AppConfig | null,\n appName?: string,\n supabase?: SupabaseClient<Database> | null\n ): Promise<ContextValidationResult> {\n // PORTAL/ADMIN special case: both contexts optional\n if (allowsOptionalContexts(appName)) {\n return {\n isValid: true,\n resolvedScope: {\n organisationId: scope.organisationId,\n eventId: scope.eventId,\n appId: scope.appId\n },\n error: null\n };\n }\n\n // If no app config, default to requiring org context\n if (!appConfig) {\n if (!scope.organisationId) {\n return {\n isValid: false,\n resolvedScope: null,\n error: new OrganisationContextRequiredError()\n };\n }\n return {\n isValid: true,\n resolvedScope: scope,\n error: null\n };\n }\n\n // Event-required apps: must have eventId, derive org from event\n if (appConfig.requires_event) {\n if (!scope.eventId) {\n return {\n isValid: false,\n resolvedScope: null,\n error: new EventContextRequiredError()\n };\n }\n\n // Derive organisationId from event if not provided\n let organisationId: UUID | undefined = scope.organisationId;\n if (!organisationId && supabase && scope.eventId) {\n try {\n const derivedOrgId = await this.deriveOrgFromEvent(supabase, scope.eventId);\n organisationId = derivedOrgId || undefined;\n if (!organisationId) {\n return {\n isValid: false,\n resolvedScope: null,\n error: new Error('Could not resolve organisation from event context')\n };\n }\n } catch (error) {\n log.error('Failed to derive org from event:', error);\n return {\n isValid: false,\n resolvedScope: null,\n error: error instanceof Error ? error : new Error('Failed to derive organisation from event')\n };\n }\n } else if (!organisationId) {\n return {\n isValid: false,\n resolvedScope: null,\n error: new Error('Event context requires organisationId but it could not be derived (supabase client not available)')\n };\n }\n\n return {\n isValid: true,\n resolvedScope: {\n organisationId,\n eventId: scope.eventId,\n appId: scope.appId\n },\n error: null\n };\n }\n\n // Org-required apps: must have organisationId, eventId optional\n if (!scope.organisationId) {\n return {\n isValid: false,\n resolvedScope: null,\n error: new OrganisationContextRequiredError()\n };\n }\n\n return {\n isValid: true,\n resolvedScope: scope,\n error: null\n };\n }\n\n /**\n * Derive organisation ID from event ID\n * \n * @param supabase - Supabase client\n * @param eventId - Event ID\n * @returns Organisation ID or null\n */\n static async deriveOrgFromEvent(\n supabase: SupabaseClient<Database>,\n eventId: string\n ): Promise<UUID | null> {\n return getOrganisationFromEvent(supabase, eventId);\n }\n\n /**\n * Check if context is ready for permission checks\n * \n * @param scope - Current scope\n * @param appConfig - App configuration\n * @param appName - App name\n * @param hasSelectedEvent - Whether event is selected\n * @param hasSelectedOrganisation - Whether organisation is selected\n * @returns True if context is ready\n */\n static isContextReady(\n scope: Scope,\n appConfig: AppConfig | null,\n appName?: string,\n hasSelectedEvent?: boolean,\n hasSelectedOrganisation?: boolean\n ): boolean {\n // PORTAL/ADMIN special case: context is always ready\n if (allowsOptionalContexts(appName)) {\n return true;\n }\n\n // If no app config, default to requiring org context\n if (!appConfig) {\n return !!hasSelectedOrganisation || !!scope.organisationId;\n }\n\n // Event-required apps: need event context\n if (appConfig.requires_event) {\n return !!hasSelectedEvent || !!scope.eventId;\n }\n\n // Org-required apps: need org context\n return !!hasSelectedOrganisation || !!scope.organisationId;\n }\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';\nimport { createLogger } from '../utils/core/logger';\nimport { ContextValidator } from './utils/contextValidator';\nimport type { AppConfig } from './utils/contextValidator';\n\nconst log = createLogger('RBACSecurity');\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 appConfig - App configuration\n * @param appName - App name (for PORTAL special case)\n * @returns True if context is valid, false otherwise\n */\n static async validateContextRequirements(\n scope: Scope,\n appConfig?: AppConfig | null,\n appName?: string\n ): Promise<boolean> {\n const validation = await ContextValidator.validateScope(scope, appConfig || null, appName);\n return validation.isValid;\n }\n\n /**\n * Log security event for monitoring\n * @param event - Security event details\n */\n private static rateLimitWarningCount = new Map<UUID, { count: number; lastWarning: number }>();\n private static readonly RATE_LIMIT_WARNING_THROTTLE_MS = 5000; // Only warn once per 5 seconds per user\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 // Throttle rate limit warnings to prevent console flooding\n if (event.type === 'rate_limit_exceeded') {\n const now = Date.now();\n const userWarning = this.rateLimitWarningCount.get(event.userId);\n \n if (userWarning) {\n const timeSinceLastWarning = now - userWarning.lastWarning;\n if (timeSinceLastWarning < this.RATE_LIMIT_WARNING_THROTTLE_MS) {\n // Still within throttle window - increment count but don't log\n userWarning.count++;\n this.rateLimitWarningCount.set(event.userId, userWarning);\n return; // Skip logging to prevent console flooding\n } else {\n // Throttle window expired - log with count and reset\n log.warn('Security event (throttled):', {\n ...securityEvent,\n details: {\n ...securityEvent.details,\n suppressedWarnings: userWarning.count,\n message: `Rate limit exceeded (${userWarning.count + 1} times in last ${Math.round(timeSinceLastWarning / 1000)}s)`\n }\n });\n this.rateLimitWarningCount.set(event.userId, { count: 0, lastWarning: now });\n return;\n }\n } else {\n // First warning for this user - log it\n this.rateLimitWarningCount.set(event.userId, { count: 0, lastWarning: now });\n log.warn('Security event:', securityEvent);\n return;\n }\n }\n\n // Log other security events normally\n log.warn('Security event:', securityEvent);\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 | null; // Required for resource-level permissions, null for page-level permissions (database handles NULL)\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 // For page-level permissions, organisationId can be null (database handles it)\n // For resource-level permissions, organisationId is required\n const isPagePermission = input.permission?.includes(':page.') || !!input.pageId;\n const requiresOrgId = !isPagePermission;\n\n // OrganisationId validation - only required for resource-level permissions\n if (requiresOrgId) {\n if (!context.organisationId) {\n errors.push('Organisation ID is required for resource-level permissions');\n } else if (!RBACSecurityValidator.validateUUID(context.organisationId)) {\n errors.push('Invalid organisation ID format');\n }\n } else {\n // For page-level permissions, organisationId can be null, but if provided, it must be valid\n if (context.organisationId && !RBACSecurityValidator.validateUUID(context.organisationId)) {\n errors.push('Invalid organisation ID format');\n }\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 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 sessionTtl?: number; // Session cache TTL in milliseconds (default: 5 minutes)\n };\n audit?: {\n enabled?: boolean;\n logLevel?: LogLevel;\n batched?: boolean; // Enable batched audit logging (default: true)\n batchWindow?: number; // Time window in milliseconds (default: 100ms)\n batchSize?: number; // Maximum batch size (default: 10)\n };\n security?: Partial<RBACSecurityConfig>;\n performance?: {\n enableRequestDeduplication?: boolean; // Enable request deduplication (default: true)\n enableBatchedAuditLogging?: boolean; // Enable batched audit logging (default: true)\n enablePerformanceTracking?: boolean; // Enable performance tracking (default: false in production)\n };\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 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';\nimport { getRBACLogger } from './config';\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 // Skip audit logging for cached checks (only log on cache miss)\n // This significantly reduces network requests\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 const logger = getRBACLogger();\n logger.error('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 const logger = getRBACLogger();\n logger.error('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: orgRoles } = 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 .limit(1) as { data: Array<{ role: string }> | null; error: any };\n\n const orgRole = orgRoles?.[0];\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 // Permission format: {operation}:page.{pageName} (e.g., read:page.meals)\n for (const operation of ['read', 'create', 'update', 'delete'] as Operation[]) {\n const permissionString = `${operation}:page.${page.page_name}`;\n const hasPermission = await this.isPermitted(\n {\n userId,\n scope,\n permission: permissionString as Permission,\n pageId: page.id,\n },\n securityContext\n );\n\n const permissionKey = permissionString 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 const logger = getRBACLogger();\n logger.error('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 const logger = getRBACLogger();\n logger.error('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 const logger = getRBACLogger();\n logger.error('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 const logger = getRBACLogger();\n logger.error('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 const logger = getRBACLogger();\n logger.warn('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 * Performance Monitoring for RBAC\n * @package @jmruthers/pace-core\n * @module RBAC/Performance\n * @since 2.0.0\n * \n * This module provides performance monitoring and metrics tracking for RBAC operations.\n */\n\nexport interface RBACPerformanceMetrics {\n /** Total number of permission checks */\n totalChecks: number;\n /** Number of cache hits */\n cacheHits: number;\n /** Number of cache misses */\n cacheMisses: number;\n /** Cache hit rate (0-1) */\n cacheHitRate: number;\n /** Number of deduplicated requests */\n deduplicatedRequests: number;\n /** Total number of network requests made */\n networkRequests: number;\n /** Average response time in milliseconds */\n averageResponseTime: number;\n /** Total response time in milliseconds */\n totalResponseTime: number;\n /** Number of batched audit events */\n batchedAuditEvents: number;\n /** Number of individual audit events */\n individualAuditEvents: number;\n}\n\nclass RBACPerformanceMonitor {\n private metrics: RBACPerformanceMetrics = {\n totalChecks: 0,\n cacheHits: 0,\n cacheMisses: 0,\n cacheHitRate: 0,\n deduplicatedRequests: 0,\n networkRequests: 0,\n averageResponseTime: 0,\n totalResponseTime: 0,\n batchedAuditEvents: 0,\n individualAuditEvents: 0,\n };\n\n private enabled: boolean = false;\n\n /**\n * Enable or disable performance monitoring\n */\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n }\n\n /**\n * Check if performance monitoring is enabled\n */\n isEnabled(): boolean {\n return this.enabled;\n }\n\n /**\n * Record a permission check\n */\n recordCheck(cacheHit: boolean, responseTime: number, wasDeduplicated: boolean = false): void {\n if (!this.enabled) {\n return;\n }\n\n this.metrics.totalChecks++;\n \n if (cacheHit) {\n this.metrics.cacheHits++;\n } else {\n this.metrics.cacheMisses++;\n this.metrics.networkRequests++;\n }\n\n if (wasDeduplicated) {\n this.metrics.deduplicatedRequests++;\n }\n\n this.metrics.totalResponseTime += responseTime;\n this.metrics.averageResponseTime = this.metrics.totalResponseTime / this.metrics.totalChecks;\n this.metrics.cacheHitRate = this.metrics.cacheHits / this.metrics.totalChecks;\n }\n\n /**\n * Record an audit event\n */\n recordAuditEvent(batched: boolean): void {\n if (!this.enabled) {\n return;\n }\n\n if (batched) {\n this.metrics.batchedAuditEvents++;\n } else {\n this.metrics.individualAuditEvents++;\n }\n }\n\n /**\n * Get current metrics\n */\n getMetrics(): RBACPerformanceMetrics {\n return { ...this.metrics };\n }\n\n /**\n * Reset all metrics\n */\n reset(): void {\n this.metrics = {\n totalChecks: 0,\n cacheHits: 0,\n cacheMisses: 0,\n cacheHitRate: 0,\n deduplicatedRequests: 0,\n networkRequests: 0,\n averageResponseTime: 0,\n totalResponseTime: 0,\n batchedAuditEvents: 0,\n individualAuditEvents: 0,\n };\n }\n\n /**\n * Get metrics summary as a formatted string\n */\n getSummary(): string {\n const m = this.metrics;\n return `\nRBAC Performance Metrics:\n Total Checks: ${m.totalChecks}\n Cache Hits: ${m.cacheHits} (${(m.cacheHitRate * 100).toFixed(1)}%)\n Cache Misses: ${m.cacheMisses}\n Deduplicated Requests: ${m.deduplicatedRequests}\n Network Requests: ${m.networkRequests}\n Average Response Time: ${m.averageResponseTime.toFixed(2)}ms\n Batched Audit Events: ${m.batchedAuditEvents}\n Individual Audit Events: ${m.individualAuditEvents}\n`;\n }\n}\n\n// Global performance monitor instance\nconst performanceMonitor = new RBACPerformanceMonitor();\n\n/**\n * Enable performance monitoring\n */\nexport function enablePerformanceMonitoring(): void {\n performanceMonitor.setEnabled(true);\n}\n\n/**\n * Disable performance monitoring\n */\nexport function disablePerformanceMonitoring(): void {\n performanceMonitor.setEnabled(false);\n}\n\n/**\n * Check if performance monitoring is enabled\n */\nexport function isPerformanceMonitoringEnabled(): boolean {\n return performanceMonitor.isEnabled();\n}\n\n/**\n * Record a permission check\n */\nexport function recordPermissionCheck(\n cacheHit: boolean,\n responseTime: number,\n wasDeduplicated: boolean = false\n): void {\n performanceMonitor.recordCheck(cacheHit, responseTime, wasDeduplicated);\n}\n\n/**\n * Record an audit event\n */\nexport function recordAuditEvent(batched: boolean): void {\n performanceMonitor.recordAuditEvent(batched);\n}\n\n/**\n * Get current performance metrics\n */\nexport function getPerformanceMetrics(): RBACPerformanceMetrics {\n return performanceMonitor.getMetrics();\n}\n\n/**\n * Reset performance metrics\n */\nexport function resetPerformanceMetrics(): void {\n performanceMonitor.reset();\n}\n\n/**\n * Get performance metrics summary\n */\nexport function getPerformanceSummary(): string {\n return performanceMonitor.getSummary();\n}\n\n","/**\n * Request Deduplication for RBAC Permission Checks\n * @package @jmruthers/pace-core\n * @module RBAC/RequestDeduplication\n * @since 2.0.0\n * \n * This module provides request deduplication to prevent multiple identical\n * permission checks from being made simultaneously. When multiple components\n * request the same permission at the same time, they share the same promise.\n */\n\nimport { PermissionCheck } from './types';\nimport { RBACCache } from './cache';\n\n/**\n * Map of in-flight permission check requests\n * Key: cache key string, Value: Promise<boolean>\n */\nconst inFlightRequests = new Map<string, Promise<boolean>>();\n\n/**\n * Generate a deduplication key from permission check input\n * \n * @param input - Permission check input\n * @returns Deduplication key string\n */\nfunction generateDeduplicationKey(input: PermissionCheck): string {\n return RBACCache.generatePermissionKey({\n userId: input.userId,\n organisationId: input.scope.organisationId, // Can be undefined for page-level permissions\n eventId: input.scope.eventId,\n appId: input.scope.appId,\n permission: input.permission,\n pageId: input.pageId,\n });\n}\n\n/**\n * Get or create a deduplicated permission check request\n * \n * If a request for the same permission is already in-flight, returns the existing promise.\n * Otherwise, creates a new request and tracks it.\n * \n * @param input - Permission check input\n * @param checkFn - Function to perform the actual permission check\n * @returns Promise resolving to permission result\n */\nexport async function getOrCreateRequest(\n input: PermissionCheck,\n checkFn: (input: PermissionCheck) => Promise<boolean>\n): Promise<boolean> {\n const key = generateDeduplicationKey(input);\n \n // Check if request is already in-flight\n const existingRequest = inFlightRequests.get(key);\n if (existingRequest) {\n return existingRequest;\n }\n \n // Create new request\n const requestPromise = checkFn(input).finally(() => {\n // Clean up when request completes (success or failure)\n inFlightRequests.delete(key);\n });\n \n // Track the request\n inFlightRequests.set(key, requestPromise);\n \n return requestPromise;\n}\n\n/**\n * Clear all in-flight requests (useful for testing or cleanup)\n */\nexport function clearInFlightRequests(): void {\n inFlightRequests.clear();\n}\n\n/**\n * Get count of in-flight requests (useful for monitoring)\n * \n * @returns Number of in-flight requests\n */\nexport function getInFlightRequestCount(): number {\n return inFlightRequests.size;\n}\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';\nimport { createLogger } from '../utils/core/logger';\nimport { enablePerformanceMonitoring } from './performance';\nimport { getOrCreateRequest } from './request-deduplication';\nimport { ContextValidator } from './utils/contextValidator';\nimport type { AppConfig } from './utils/contextValidator';\n\nconst log = createLogger('RBACAPI');\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 isDevelopment = import.meta.env.MODE === 'development';\n const fullConfig: RBACConfig = {\n supabase,\n debug: isDevelopment,\n logLevel: 'warn',\n developmentMode: isDevelopment,\n ...config,\n };\n \n createRBACConfig(fullConfig);\n \n // Automatically disable rate limiting in development mode unless explicitly overridden\n // Apply default first, then let explicit config override it\n // Pass undefined if no config provided and not in development, otherwise create security config\n const securityConfig = \n config === undefined && !isDevelopment\n ? undefined\n : {\n // Default: disable rate limiting in development\n ...(isDevelopment && config?.security?.enableRateLimiting === undefined\n ? { enableRateLimiting: false }\n : {}),\n // Explicit config overrides defaults\n ...config?.security,\n };\n \n // Pass security config to engine\n globalEngine = createRBACEngine(supabase, securityConfig);\n \n // Setup audit manager with batching configuration\n const useBatchedAudit = config?.audit?.batched !== false && (config?.performance?.enableBatchedAuditLogging !== false);\n const batchConfig = useBatchedAudit ? {\n batchWindow: config?.audit?.batchWindow,\n batchSize: config?.audit?.batchSize,\n } : undefined;\n const auditManager = createAuditManager(supabase, useBatchedAudit, batchConfig);\n setGlobalAuditManager(auditManager);\n \n // Setup performance monitoring if enabled\n if (config?.performance?.enablePerformanceTracking) {\n enablePerformanceMonitoring();\n }\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 * @param appConfig - Optional app configuration\n * @param appName - Optional app name\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(\n input: {\n userId: UUID;\n scope: Scope;\n },\n appConfig?: AppConfig | null,\n appName?: string\n): Promise<AccessLevel> {\n const engine = getEngine();\n \n // Check super admin status first - super admins bypass context requirements\n const isSuperAdminUser = await engine['checkSuperAdmin'](input.userId);\n if (isSuperAdminUser) {\n return 'super';\n }\n \n // Fetch app config if not provided\n let resolvedAppConfig: AppConfig | null = appConfig ?? null;\n let resolvedAppName = appName;\n \n if (!resolvedAppConfig && input.scope.appId) {\n resolvedAppConfig = await getAppConfig(input.scope.appId);\n }\n \n // Validate context using ContextValidator\n const validation = await ContextValidator.resolveRequiredContext(\n input.scope,\n resolvedAppConfig,\n resolvedAppName,\n engine['supabase']\n );\n \n if (!validation.isValid || !validation.resolvedScope) {\n throw validation.error || new OrganisationContextRequiredError();\n }\n \n // Use resolved scope\n return engine.getAccessLevel({\n ...input,\n scope: validation.resolvedScope\n });\n}\n\n/**\n * Get user's permission map for a scope\n * \n * @param input - Permission map input\n * @param appConfig - Optional app configuration\n * @param appName - Optional app name\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(\n input: {\n userId: UUID;\n scope: Scope;\n },\n appConfig?: AppConfig | null,\n appName?: string\n): Promise<PermissionMap> {\n const engine = getEngine();\n \n // Fetch app config if not provided\n let resolvedAppConfig: AppConfig | null = appConfig ?? null;\n let resolvedAppName = appName;\n \n if (!resolvedAppConfig && input.scope.appId) {\n resolvedAppConfig = await getAppConfig(input.scope.appId);\n }\n \n // Validate context using ContextValidator\n const validation = await ContextValidator.resolveRequiredContext(\n input.scope,\n resolvedAppConfig,\n resolvedAppName,\n engine['supabase']\n );\n \n if (!validation.isValid || !validation.resolvedScope) {\n throw validation.error || new OrganisationContextRequiredError();\n }\n \n // Use resolved scope\n return engine.getPermissionMap({\n ...input,\n scope: validation.resolvedScope\n });\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(\n input: {\n userId: UUID;\n scope: Scope;\n },\n appConfig?: AppConfig | null,\n appName?: string\n): Promise<RBACRoleContext> {\n const engine = getEngine();\n \n // Fetch app config if not provided\n let resolvedAppConfig: AppConfig | null = appConfig ?? null;\n let resolvedAppName = appName;\n \n if (!resolvedAppConfig && input.scope.appId) {\n resolvedAppConfig = await getAppConfig(input.scope.appId);\n }\n \n // Validate context using ContextValidator\n const validation = await ContextValidator.resolveRequiredContext(\n input.scope,\n resolvedAppConfig,\n resolvedAppName,\n engine['supabase']\n );\n \n if (!validation.isValid || !validation.resolvedScope) {\n throw validation.error || new OrganisationContextRequiredError();\n }\n \n // Use resolved scope\n return engine.getRoleContext({\n ...input,\n scope: validation.resolvedScope\n });\n}\n\n/**\n * Check if user has a specific permission\n * \n * @param input - Permission check input\n * @param appConfig - Optional app configuration (if not provided, will be fetched)\n * @param appName - Optional app name (for PORTAL/ADMIN special case and config lookup)\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(\n input: PermissionCheck,\n appConfig?: AppConfig | null,\n appName?: string\n): Promise<boolean> {\n const engine = getEngine();\n \n // Fetch app config if not provided and we have appId\n let resolvedAppConfig: AppConfig | null = appConfig ?? null;\n let resolvedAppName = appName;\n \n if (!resolvedAppConfig && input.scope.appId) {\n resolvedAppConfig = await getAppConfig(input.scope.appId);\n }\n \n // If we have appId but no appName, try to get it from the database\n if (!resolvedAppName && input.scope.appId) {\n try {\n const { data } = await engine['supabase']\n .from('rbac_apps')\n .select('name')\n .eq('id', input.scope.appId)\n .eq('is_active', true)\n .single() as { data: { name: string } | null };\n if (data) {\n resolvedAppName = data.name;\n }\n } catch (err) {\n // Ignore errors - appName is optional\n }\n }\n \n // Validate context using ContextValidator\n const validation = await ContextValidator.resolveRequiredContext(\n input.scope,\n resolvedAppConfig,\n resolvedAppName,\n engine['supabase']\n );\n \n if (!validation.isValid || !validation.resolvedScope) {\n throw validation.error || new OrganisationContextRequiredError();\n }\n \n // Use resolved scope for permission check\n const validatedScope = validation.resolvedScope;\n \n // Create security context from validated scope\n const securityContext: SecurityContext = {\n userId: input.userId,\n organisationId: validatedScope.organisationId || null,\n timestamp: new Date(),\n // Optional fields can be omitted\n };\n \n // Create new input with validated scope\n const validatedInput: PermissionCheck = {\n ...input,\n scope: validatedScope\n };\n \n return engine.isPermitted(validatedInput, securityContext);\n}\n\n/**\n * Check if user has a specific permission (cached version)\n * \n * Uses request deduplication to share in-flight requests across components\n * and checks cache before making new requests. Uses session cache for page-level checks.\n * \n * @param input - Permission check input\n * @param appConfig - Optional app configuration\n * @param appName - Optional app name\n * @returns Promise resolving to permission result\n */\nexport async function isPermittedCached(\n input: PermissionCheck,\n appConfig?: AppConfig | null,\n appName?: string\n): Promise<boolean> {\n const { userId, scope, permission, pageId } = input;\n \n // Check cache first (checks both short-term and session cache)\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, true);\n if (cached !== null) {\n return cached;\n }\n\n // Use request deduplication - if same request is in-flight, share the promise\n return getOrCreateRequest(input, async (checkInput) => {\n // Check permission with context validation\n const result = await isPermitted(checkInput, appConfig, appName);\n \n // Determine if this is a page-level check (has pageId or permission contains 'page.')\n const isPageLevelCheck = !!pageId || permission.includes('page.');\n \n // Cache result - use session cache for page-level checks\n rbacCache.set(cacheKey, result, undefined, isPageLevelCheck);\n \n return result;\n });\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<AppConfig | null> {\n try {\n const engine = getEngine();\n return getAppConfigWithClient(engine['supabase'], appId);\n } catch (err) {\n // RBAC not initialized - return null gracefully\n if (err instanceof RBACNotInitializedError) {\n return null;\n }\n throw err;\n }\n}\n\nexport async function getAppConfigWithClient(client: SupabaseClient | null | undefined, appId: UUID): Promise<AppConfig | null> {\n // Return null if client is not available\n if (!client) {\n return null;\n }\n \n // Cache key for app config - cache for 5 minutes (app config rarely changes)\n const cacheKey = `app_config:${appId}`;\n \n // Check cache first\n const cached = rbacCache.get<AppConfig>(cacheKey, true);\n if (cached !== null) {\n return cached;\n }\n \n try {\n const { data, error } = await client\n .from('rbac_apps')\n .select('requires_event, name')\n .eq('id', appId)\n .eq('is_active', true)\n .single() as { data: { requires_event: boolean; name: string } | null; error: any };\n\n if (error || !data) {\n return null;\n }\n\n const appConfig: AppConfig = { requires_event: data.requires_event ?? false };\n \n // Cache the result for 5 minutes (300000ms) with session cache enabled\n // App config rarely changes, so we can cache it longer\n rbacCache.set(cacheKey, appConfig, 5 * 60 * 1000, true);\n \n return appConfig;\n } catch (err) {\n log.error('Error fetching app config:', err);\n return null;\n }\n}\n\n/**\n * Get app configuration by app name\n * \n * @param appName - App name\n * @returns Promise resolving to app configuration\n */\nexport async function getAppConfigByName(appName: string): Promise<AppConfig | null> {\n const engine = getEngine();\n try {\n const { data, error } = await engine['supabase']\n .from('rbac_apps')\n .select('requires_event, name')\n .eq('name', appName)\n .eq('is_active', true)\n .single() as { data: { requires_event: boolean; name: string } | null; error: any };\n\n if (error || !data) {\n return null;\n }\n\n return { requires_event: data.requires_event ?? false };\n } catch (err) {\n log.error('Error fetching app config by name:', 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":["log","log","hasPermission","isSuperAdmin","log","hasPermission"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/useZodForm.ts","../src/hooks/useFormDialog.ts","../src/hooks/useOrganisationSecurity.ts","../src/hooks/useOrganisationPermissions.ts","../src/utils/storage/index.ts","../src/hooks/public/usePublicEvent.ts","../src/hooks/public/usePublicEventLogo.ts","../src/hooks/public/usePublicRouteParams.ts"],"sourcesContent":["\n/**\n * Zod Form Hook\n * \n * Enhanced form hook with Zod validation\n */\n\nimport { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { z } from 'zod';\n\ninterface UseZodFormProps<T extends z.ZodTypeAny> {\n schema: T;\n defaultValues?: Partial<z.infer<T>>;\n mode?: 'onSubmit' | 'onBlur' | 'onChange' | 'onTouched' | 'all';\n}\n\nexport function useZodForm<T extends z.ZodTypeAny>({\n schema,\n defaultValues,\n mode = 'onSubmit'\n}: UseZodFormProps<T>) {\n return useForm<z.infer<T>>({\n resolver: zodResolver(schema),\n defaultValues: defaultValues as any,\n mode\n });\n}\n","/**\n * @file useFormDialog Hook\n * @package @jmruthers/pace-core\n * @module Hooks\n * @since 0.1.0\n * \n * Generic React hook for managing form dialog state (open/close, form data, reset behavior).\n * \n * @example\n * ```ts\n * interface ContactFormData {\n * name: string;\n * email: string;\n * }\n * \n * function ContactDialog() {\n * const { isOpen, formData, openDialog, closeDialog, handleOpenChange } = \n * useFormDialog<ContactFormData>();\n * \n * // Use in Dialog component\n * // <Dialog open={isOpen} onOpenChange={handleOpenChange}>...</Dialog>\n * }\n * ```\n */\n\nimport { useState, useCallback } from 'react';\n\n/**\n * Options for configuring the useFormDialog hook behavior\n */\nexport interface UseFormDialogOptions<T = unknown> {\n /**\n * Callback invoked when the dialog open state changes\n * @param open - The new open state\n */\n onOpenChange?: (open: boolean) => void;\n \n /**\n * Whether to reset form data when the dialog closes\n * @default true\n */\n resetOnClose?: boolean;\n}\n\n/**\n * Return type for the useFormDialog hook\n */\nexport interface UseFormDialogReturn<T = unknown> {\n /**\n * Current open state of the dialog\n */\n isOpen: boolean;\n \n /**\n * Current form data (null when dialog is closed or no data provided)\n */\n formData: T | null;\n \n /**\n * Open the dialog with optional form data\n * @param data - Optional form data to populate the dialog\n */\n openDialog: (data?: T | null) => void;\n \n /**\n * Close the dialog\n */\n closeDialog: () => void;\n \n /**\n * Handler for controlled dialog components (e.g., Radix UI Dialog)\n * @param open - The new open state\n */\n handleOpenChange: (open: boolean) => void;\n}\n\n/**\n * Generic React hook for managing form dialog state.\n * \n * Provides state management for form dialogs including:\n * - Open/close state\n * - Form data management\n * - Automatic reset on close (configurable)\n * - Controlled and uncontrolled usage patterns\n * \n * @param options - Configuration options for the hook\n * @returns Object containing dialog state and control functions\n * \n * @example\n * ```ts\n * // Basic usage\n * const { isOpen, openDialog, closeDialog } = useFormDialog();\n * \n * // With form data\n * interface UserData {\n * id: string;\n * name: string;\n * }\n * const { isOpen, formData, openDialog } = useFormDialog<UserData>();\n * \n * // Open with data\n * openDialog({ id: '1', name: 'John' });\n * \n * // Controlled usage with callback\n * const { handleOpenChange, isOpen } = useFormDialog({\n * onOpenChange: (open) => console.log('Dialog state:', open),\n * resetOnClose: false\n * });\n * ```\n */\nexport function useFormDialog<T = unknown>({\n onOpenChange,\n resetOnClose = true,\n}: UseFormDialogOptions<T> = {}): UseFormDialogReturn<T> {\n const [isOpen, setIsOpen] = useState(false);\n const [formData, setFormData] = useState<T | null>(null);\n\n const openDialog = useCallback((data: T | null = null) => {\n setFormData(data);\n setIsOpen(true);\n onOpenChange?.(true);\n }, [onOpenChange]);\n\n const closeDialog = useCallback(() => {\n setIsOpen(false);\n if (resetOnClose) {\n setFormData(null);\n }\n onOpenChange?.(false);\n }, [resetOnClose, onOpenChange]);\n\n const handleOpenChange = useCallback((open: boolean) => {\n setIsOpen(open);\n if (!open && resetOnClose) {\n setFormData(null);\n }\n onOpenChange?.(open);\n }, [resetOnClose, onOpenChange]);\n\n return {\n isOpen,\n formData,\n openDialog,\n closeDialog,\n handleOpenChange,\n };\n}\n","/**\n * @file Organisation Security Hook\n * @package @jmruthers/pace-core\n * @module Hooks/OrganisationSecurity\n * @since 0.4.0\n *\n * Security-focused hook for organisation access validation and super admin functionality.\n * Provides utilities for validating user access to organisations and checking permissions.\n */\n\nimport { useCallback, useMemo, useEffect, useState } from 'react';\nimport { useUnifiedAuth } from '../providers';\nimport { useOrganisations } from './useOrganisations';\n// Legacy useRBAC hook removed - use new RBAC system instead\nimport type { OrganisationSecurityError, SuperAdminContext } from '../types/organisation';\nimport type { Permission } from '../rbac/types';\nimport { logger } from '../utils/core/logger';\n\nexport interface OrganisationSecurityHook {\n // Super admin context\n superAdminContext: SuperAdminContext;\n \n // Access validation\n validateOrganisationAccess: (orgId: string) => Promise<boolean>;\n hasMinimumRole: (minRole: string, orgId?: string) => boolean;\n canAccessChildOrganisations: (orgId?: string) => boolean;\n \n // Permission checks\n hasPermission: (permission: string, orgId?: string) => Promise<boolean>;\n getUserPermissions: (orgId?: string) => Promise<string[]>;\n \n // Audit logging\n logOrganisationAccess: (action: string, details?: Record<string, unknown>) => Promise<void>;\n \n // Security utilities\n ensureOrganisationAccess: (orgId: string) => Promise<void>;\n validateUserAccess: (userId: string, orgId: string) => Promise<boolean>;\n}\n\nexport const useOrganisationSecurity = (): OrganisationSecurityHook => {\n const { user, session, supabase } = useUnifiedAuth();\n const { selectedOrganisation, getUserRole, validateOrganisationAccess: validateAccess } = useOrganisations();\n \n // Super admin status - query database for security (user_metadata can be spoofed)\n const [isSuperAdmin, setIsSuperAdmin] = useState<boolean>(false);\n const [isCheckingSuperAdmin, setIsCheckingSuperAdmin] = useState(false);\n\n // Check super admin status from database\n useEffect(() => {\n if (!user || !session || !supabase) {\n setIsSuperAdmin(false);\n return;\n }\n\n const checkSuperAdmin = async () => {\n setIsCheckingSuperAdmin(true);\n try {\n const now = new Date().toISOString();\n const { data, error } = await supabase\n .from('rbac_global_roles')\n .select('role')\n .eq('user_id', user.id)\n .eq('role', 'super_admin')\n .lte('valid_from', now)\n .or(`valid_to.is.null,valid_to.gte.${now}`)\n .limit(1);\n\n setIsSuperAdmin(!error && data && data.length > 0);\n } catch (error) {\n logger.error('useOrganisationSecurity', 'Error checking super admin status:', error);\n setIsSuperAdmin(false);\n } finally {\n setIsCheckingSuperAdmin(false);\n }\n };\n\n checkSuperAdmin();\n }, [user, session, supabase]);\n\n // Super admin context\n const superAdminContext = useMemo((): SuperAdminContext => {\n return {\n isSuperAdmin,\n hasGlobalAccess: isSuperAdmin,\n canManageAllOrganisations: isSuperAdmin\n };\n }, [isSuperAdmin]);\n\n // Validate organisation access with database check\n const validateOrganisationAccess = useCallback(async (orgId: string): Promise<boolean> => {\n if (!user || !session || !supabase) return false;\n \n try {\n // Super admin has access to all organisations\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n // Check organisation membership using consolidated rbac_organisation_roles table\n const { data, error } = await supabase\n .from('rbac_organisation_roles')\n .select('id')\n .eq('user_id', user.id)\n .eq('organisation_id', orgId)\n .eq('status', 'active')\n .is('revoked_at', null)\n .in('role', ['org_admin', 'leader', 'member']) // Only actual members, not supporters\n .single();\n\n if (error) {\n logger.error('useOrganisationSecurity', 'Error validating organisation access:', error);\n return false;\n }\n\n return !!data;\n } catch (error) {\n logger.error('useOrganisationSecurity', 'Exception validating organisation access:', error);\n return false;\n }\n }, [user, session, supabase, superAdminContext.isSuperAdmin]);\n\n // Check if user has minimum role\n const hasMinimumRole = useCallback((minRole: string, orgId?: string): boolean => {\n // Super admin has all roles\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId) return false;\n\n const userRole = getUserRole(targetOrgId);\n const roleHierarchy = ['supporter', 'member', 'leader', 'org_admin'];\n \n const userRoleIndex = roleHierarchy.indexOf(userRole);\n const minRoleIndex = roleHierarchy.indexOf(minRole);\n \n return userRoleIndex >= minRoleIndex;\n }, [selectedOrganisation, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Check if user can access child organisations\n const canAccessChildOrganisations = useCallback((orgId?: string): boolean => {\n // Super admin can access all organisations\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId) return false;\n\n const userRole = getUserRole(targetOrgId);\n return userRole === 'org_admin';\n }, [selectedOrganisation, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Check specific permission using the new RBAC system\n const hasPermission = useCallback(async (permission: string, orgId?: string): Promise<boolean> => {\n // Super admin has all permissions\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId || !user) return false;\n\n try {\n // Use the new RBAC system with caching\n const { isPermittedCached } = await import('../rbac/api');\n \n const scope = {\n organisationId: targetOrgId,\n eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,\n appId: user.user_metadata?.appId || user.app_metadata?.appId,\n };\n\n return await isPermittedCached({\n userId: user.id,\n scope,\n permission: permission as Permission\n });\n } catch (error) {\n logger.error('useOrganisationSecurity', 'Exception checking permission:', error);\n return false;\n }\n }, [selectedOrganisation, user, superAdminContext.isSuperAdmin]);\n\n // Get user's permissions for organisation using the new RBAC system\n const getUserPermissions = useCallback(async (orgId?: string): Promise<string[]> => {\n // Super admin has all permissions\n if (superAdminContext.isSuperAdmin) {\n return ['*']; // All permissions\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId || !user) return [];\n\n try {\n // Use the new RBAC system\n const { getPermissionMap } = await import('../rbac/api');\n \n const scope = {\n organisationId: targetOrgId,\n eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,\n appId: user.user_metadata?.appId || user.app_metadata?.appId,\n };\n\n const permissionMap = await getPermissionMap({\n userId: user.id,\n scope\n });\n \n // Flatten all permissions from all pages\n const allPermissions = Object.entries(permissionMap)\n .filter(([, allowed]) => allowed)\n .map(([permission]) => permission);\n return [...new Set(allPermissions)]; // Remove duplicates\n } catch (error) {\n logger.error('useOrganisationSecurity', 'Exception getting user permissions:', error);\n return [];\n }\n }, [selectedOrganisation, user, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Log organisation access for audit using the new RBAC audit system\n const logOrganisationAccess = useCallback(async (action: string, details?: Record<string, unknown>): Promise<void> => {\n if (!user || !selectedOrganisation) return;\n\n try {\n // Use the new RBAC audit system - only if we have a valid organisation ID\n if (selectedOrganisation.id) {\n const { emitAuditEvent } = await import('../rbac/audit');\n \n await emitAuditEvent({\n type: 'permission_check',\n userId: user.id,\n organisationId: selectedOrganisation.id,\n permission: action,\n decision: true, // Assume access was granted if we're logging it\n source: 'api',\n duration_ms: 0, // No actual permission check performed here\n metadata: details || {}\n });\n }\n } catch (error) {\n logger.error('useOrganisationSecurity', 'Error logging organisation access:', error);\n }\n }, [user, selectedOrganisation]);\n\n // Ensure organisation access (throws if no access)\n const ensureOrganisationAccess = useCallback(async (orgId: string): Promise<void> => {\n const hasAccess = await validateOrganisationAccess(orgId);\n \n if (!hasAccess) {\n const error = new Error(`User does not have access to organisation ${orgId}`) as OrganisationSecurityError;\n error.name = 'OrganisationSecurityError';\n error.code = 'ACCESS_DENIED';\n error.organisationId = orgId;\n error.userId = user?.id;\n throw error;\n }\n }, [validateOrganisationAccess, user]);\n\n // Validate user access (for admin functions)\n const validateUserAccess = useCallback(async (userId: string, orgId: string): Promise<boolean> => {\n if (!supabase) return false;\n\n try {\n // Super admin can validate any user\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n // Regular users can only validate their own access\n if (userId !== user?.id) {\n return false;\n }\n\n return await validateOrganisationAccess(orgId);\n } catch (error) {\n logger.error('useOrganisationSecurity', 'Exception validating user access:', error);\n return false;\n }\n }, [supabase, superAdminContext.isSuperAdmin, user, validateOrganisationAccess]);\n\n return {\n superAdminContext,\n validateOrganisationAccess,\n hasMinimumRole,\n canAccessChildOrganisations,\n hasPermission,\n getUserPermissions,\n logOrganisationAccess,\n ensureOrganisationAccess,\n validateUserAccess\n };\n}; ","/**\n * @file useOrganisationPermissions Hook\n * @package @jmruthers/pace-core\n * @module Hooks/useOrganisationPermissions\n * @since 0.4.0\n *\n * Hook for managing organisation-specific permissions and role validation.\n * Provides secure access to user's role and permissions within organisations.\n *\n * @example\n * ```tsx\n * function OrganisationComponent() {\n * const { \n * isOrgAdmin, \n * canManageMembers,\n * userRole,\n * hasOrganisationAccess\n * } = useOrganisationPermissions();\n * \n * return (\n * <div>\n * {isOrgAdmin && <AdminPanel />}\n * {canManageMembers && <MemberManagement />}\n * <p>Your role: {userRole}</p>\n * </div>\n * );\n * }\n * \n * // For specific organisation\n * function MultiOrgComponent() {\n * const permissions = useOrganisationPermissions('org-123');\n * \n * if (!permissions.hasOrganisationAccess) {\n * return <div>No access to this organisation</div>;\n * }\n * \n * return <div>Role in org-123: {permissions.userRole}</div>;\n * }\n * ```\n *\n * @security\n * - Validates user membership in organisation\n * - Provides role-based permission checks\n * - Ensures secure access to organisation data\n * - Real-time permission validation\n */\n\nimport { useMemo } from 'react';\nimport { useOrganisations } from './useOrganisations';\nimport { useOrganisationSecurity } from './useOrganisationSecurity';\nimport type { OrganisationRole, OrganisationPermission } from '../types/organisation';\n\nexport interface UseOrganisationPermissionsReturn {\n /** User's role in the organisation */\n userRole: OrganisationRole | 'no_access';\n \n /** Whether user has organisation admin role */\n isOrgAdmin: boolean;\n \n /** Whether user is a super admin */\n isSuperAdmin: boolean;\n \n /** Whether user can moderate content */\n canModerate: boolean;\n \n /** Whether user can manage members */\n canManageMembers: boolean;\n \n /** Whether user can manage organisation settings */\n canManageSettings: boolean;\n \n /** Whether user can manage events */\n canManageEvents: boolean;\n \n /** Whether user has any admin privileges */\n hasAdminPrivileges: boolean;\n \n /** Whether user has access to the organisation */\n hasOrganisationAccess: boolean;\n \n /** Check if user has specific permission */\n hasPermission: (permission: OrganisationPermission) => boolean;\n \n /** Get all permissions for the user */\n getAllPermissions: () => OrganisationPermission[];\n \n /** Organisation ID being checked */\n organisationId: string;\n}\n\n/**\n * Hook to access organisation-specific permissions and roles\n * \n * @param orgId - Optional organisation ID. Defaults to currently selected organisation\n * @returns Organisation permissions and role information\n */\nexport function useOrganisationPermissions(orgId?: string): UseOrganisationPermissionsReturn {\n const { \n selectedOrganisation, \n getUserRole, \n validateOrganisationAccess,\n ensureOrganisationContext\n } = useOrganisations();\n \n // Get super admin context if available (may not be available in all contexts)\n let superAdminContext: { isSuperAdmin: boolean } = { isSuperAdmin: false };\n try {\n superAdminContext = useOrganisationSecurity().superAdminContext;\n } catch {\n // Not available in this context, default to false\n }\n\n const organisationId = useMemo(() => {\n if (orgId) {\n return orgId;\n }\n try {\n const currentOrg = ensureOrganisationContext();\n return currentOrg.id;\n } catch {\n return '';\n }\n }, [orgId, ensureOrganisationContext]);\n\n const userRole = useMemo(() => {\n if (!organisationId) return 'no_access';\n const role = getUserRole(organisationId);\n // Map to valid OrganisationRole or 'no_access'\n if (role === 'org_admin' || role === 'leader' || role === 'member' || role === 'supporter') {\n return role as OrganisationRole;\n }\n return 'no_access';\n }, [organisationId, getUserRole]);\n\n const hasOrganisationAccess = useMemo(() => {\n if (!organisationId) return false;\n return validateOrganisationAccess(organisationId);\n }, [organisationId, validateOrganisationAccess]);\n\n const permissions = useMemo(() => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return {\n isOrgAdmin: false,\n isSuperAdmin: false,\n canModerate: false,\n canManageMembers: false,\n canManageSettings: false,\n canManageEvents: false,\n hasAdminPrivileges: false\n };\n }\n\n const isOrgAdmin = userRole === 'org_admin';\n const isLeader = userRole === 'leader';\n const isMember = userRole === 'member';\n const isSupporter = userRole === 'supporter';\n\n // Super admin status - database backed (user_metadata can be spoofed)\n // Get super admin status from the security hook\n const isSuperAdmin = superAdminContext.isSuperAdmin;\n\n return {\n isOrgAdmin,\n isSuperAdmin,\n canModerate: isSuperAdmin || isOrgAdmin || isLeader,\n canManageMembers: isSuperAdmin || isOrgAdmin || isLeader, // Leaders can manage members\n canManageSettings: isSuperAdmin || isOrgAdmin,\n canManageEvents: isSuperAdmin || isOrgAdmin || isLeader,\n hasAdminPrivileges: isSuperAdmin || isOrgAdmin || isLeader // Leaders have admin privileges\n };\n }, [hasOrganisationAccess, userRole]);\n\n const hasPermission = useMemo(() => {\n return (permission: OrganisationPermission): boolean => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return false;\n }\n\n // Super admin has all permissions (org_admin acts as super admin within org)\n if (userRole === 'org_admin' || permission === '*') {\n return true;\n }\n\n // Map permissions to roles using the defined permissions from organisation types\n const rolePermissions: Record<OrganisationRole, OrganisationPermission[]> = {\n supporter: ['view_basic'],\n member: ['view_basic', 'view_details'],\n leader: ['view_basic', 'view_details', 'moderate_content', 'manage_events'],\n org_admin: ['view_basic', 'view_details', 'moderate_content', 'manage_events', 'manage_members', 'manage_settings']\n };\n\n const userPermissions = rolePermissions[userRole as OrganisationRole] || [];\n return userPermissions.includes(permission) || userPermissions.includes('*');\n };\n }, [hasOrganisationAccess, userRole]);\n\n const getAllPermissions = useMemo(() => {\n return (): OrganisationPermission[] => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return [];\n }\n\n const rolePermissions: Record<OrganisationRole, OrganisationPermission[]> = {\n supporter: ['view_basic'],\n member: ['view_basic', 'view_details'],\n leader: ['view_basic', 'view_details', 'moderate_content', 'manage_events'],\n org_admin: ['view_basic', 'view_details', 'moderate_content', 'manage_events', 'manage_members', 'manage_settings']\n };\n\n return rolePermissions[userRole as OrganisationRole] || [];\n };\n }, [hasOrganisationAccess, userRole]);\n\n return useMemo(() => ({\n userRole,\n organisationId,\n hasOrganisationAccess,\n hasPermission,\n getAllPermissions,\n ...permissions\n }), [userRole, organisationId, hasOrganisationAccess, hasPermission, getAllPermissions, permissions]);\n} ","/**\n * Storage utilities for pace-core\n * \n * Provides app-segregated file storage with organisation-scoped access\n */\n\nexport * from './types';\nexport * from './config';\nexport * from './helpers';\n\n// Import functions for StorageUtils class\nimport {\n uploadFile,\n getPublicUrl,\n getSignedUrl,\n deleteFile,\n downloadFile,\n listFiles,\n archiveFile,\n generateFilePath,\n generateUniqueFileName,\n extractFileMetadata\n} from './helpers';\n\n// Re-export commonly used functions for convenience\nexport {\n uploadFile,\n getPublicUrl,\n getSignedUrl,\n deleteFile,\n downloadFile,\n listFiles,\n archiveFile,\n generateFilePath,\n generateUniqueFileName,\n extractFileMetadata\n};\n\nexport {\n validateFileSize,\n getFileSizeLimit,\n formatFileSize\n} from './config';\n\n\nexport {\n FILE_SIZE_LIMITS,\n DEFAULT_FILE_SIZE_LIMIT,\n STORAGE_CONFIG,\n APP_PATH_MAPPING\n} from './config';\n\n/**\n * StorageUtils class for convenient access to storage functions\n */\nexport class StorageUtils {\n static generateFilePath = generateFilePath;\n static generateUniqueFileName = generateUniqueFileName;\n static extractFileMetadata = extractFileMetadata;\n static uploadFile = uploadFile;\n static getPublicUrl = getPublicUrl;\n static getSignedUrl = getSignedUrl;\n static deleteFile = deleteFile;\n static downloadFile = downloadFile;\n static listFiles = listFiles;\n static archiveFile = archiveFile;\n}\n","/**\n * @file Public Event Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Public\n * @since 1.0.0\n *\n * A React hook for accessing public event data without authentication.\n * Provides event information by event_code for public pages.\n *\n * Features:\n * - No authentication required\n * - Caching for performance\n * - Error handling and loading states\n * - TypeScript support\n * - Automatic refetch capabilities\n *\n * @example\n * ```tsx\n * import { usePublicEvent } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * const { eventCode } = usePublicRouteParams();\n * const { event, isLoading, error, refetch } = usePublicEvent(eventCode);\n *\n * if (isLoading) return <div>Loading event...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!event) return <div>Event not found</div>;\n *\n * return (\n * <div>\n * <h1>{event.event_name}</h1>\n * <p>Date: {event.event_date}</p>\n * <p>Venue: {event.event_venue}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @accessibility\n * - No direct accessibility concerns (hook)\n * - Enables accessible public event display\n * - Supports screen reader friendly loading states\n *\n * @security\n * - Only returns public-safe event data\n * - Validates event_code before querying\n * - No sensitive information exposed\n * - Rate limiting applied at database level\n *\n * @performance\n * - Built-in caching with TTL\n * - Minimal re-renders with stable references\n * - Lazy loading support\n * - Error boundary integration\n *\n * @dependencies\n * - React 18+ - Hooks and effects\n * - @supabase/supabase-js - Database integration\n * - Event types - Type definitions\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport { createClient } from '@supabase/supabase-js';\nimport type { Event } from '../../types/event';\nimport type { Database } from '../../types/database';\nimport { assertOrganisationId } from '../../types/core';\nimport { usePublicPageContext } from '../../components/PublicLayout/PublicPageProvider';\nimport { logger } from '../../utils/core/logger';\n\n// Simple in-memory cache for public data\nconst publicDataCache = new Map<string, { data: any; timestamp: number; ttl: number }>();\n\nexport interface UsePublicEventReturn {\n /** The event data, null if not loaded or not found */\n event: Event | null;\n /** Whether the data is currently loading */\n isLoading: boolean;\n /** Any error that occurred during loading */\n error: Error | null;\n /** Function to manually refetch the data */\n refetch: () => Promise<void>;\n}\n\nexport interface UsePublicEventOptions {\n /** Cache TTL in milliseconds (default: 5 minutes) */\n cacheTtl?: number;\n /** Whether to enable caching (default: true) */\n enableCache?: boolean;\n}\n\n/**\n * Hook for accessing public event data by event_code\n * \n * This hook provides access to public event information without requiring\n * authentication. It includes caching, error handling, and loading states.\n * \n * @param eventCode - The event code to look up\n * @param options - Configuration options for caching and behavior\n * @returns Object containing event data, loading state, error, and refetch function\n */\nexport function usePublicEvent(\n eventCode: string,\n options: UsePublicEventOptions = {}\n): UsePublicEventReturn {\n const {\n cacheTtl = 5 * 60 * 1000, // 5 minutes\n enableCache = true\n } = options;\n\n const [event, setEvent] = useState<Event | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Get environment variables from public page context or fallback to direct access\n let environment: { supabaseUrl: string | null; supabaseKey: string | null };\n \n try {\n environment = usePublicPageContext().environment;\n } catch {\n // Fallback to direct environment variable access if not in PublicPageProvider\n environment = {\n supabaseUrl: (import.meta as any).env?.VITE_SUPABASE_URL || (import.meta as any).env?.NEXT_PUBLIC_SUPABASE_URL || null,\n supabaseKey: (import.meta as any).env?.VITE_SUPABASE_PUBLISHABLE_KEY || (import.meta as any).env?.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY || null\n };\n }\n \n // Create a simple Supabase client for public access\n const supabase = useMemo(() => {\n if (typeof window === 'undefined') return null;\n \n if (!environment.supabaseUrl || !environment.supabaseKey) {\n logger.warn('usePublicEvent', 'Missing Supabase environment variables. Please ensure VITE_SUPABASE_URL and VITE_SUPABASE_PUBLISHABLE_KEY are set in your environment.');\n return null;\n }\n\n return createClient<Database>(environment.supabaseUrl, environment.supabaseKey);\n }, [environment.supabaseUrl, environment.supabaseKey]);\n\n // Helper function to try refreshing schema cache\n const refreshSchemaCache = useCallback(async () => {\n try {\n // Try to trigger a schema refresh by querying a system table\n await (supabase as any).from('information_schema.routines').select('routine_name').limit(1);\n } catch (error) {\n // Ignore errors, this is just an attempt to refresh cache\n logger.debug('usePublicEvent', 'Schema cache refresh attempt failed:', error);\n }\n }, [supabase]);\n\n const fetchEvent = useCallback(async (): Promise<void> => {\n if (!eventCode || !supabase) {\n setError(new Error('Invalid event code or Supabase client not available'));\n setIsLoading(false);\n return;\n }\n\n // Check cache first\n const cacheKey = `public_event_${eventCode}`;\n if (enableCache) {\n const cached = publicDataCache.get(cacheKey);\n if (cached && Date.now() - cached.timestamp < cached.ttl) {\n setEvent(cached.data);\n setIsLoading(false);\n setError(null);\n return;\n }\n }\n\n try {\n setIsLoading(true);\n setError(null);\n\n let eventData: any = null;\n\n try {\n // Try to call the public event RPC function first\n const response = await (supabase as any).rpc('get_public_event_by_code', {\n event_code_param: eventCode\n });\n \n const data = response?.data;\n const rpcError = response?.error;\n\n if (rpcError) {\n // If RPC function doesn't exist or schema cache issue, try refresh first, then fallback\n if (rpcError.message?.includes('Could not find the function') || \n rpcError.message?.includes('does not exist') ||\n rpcError.message?.includes('schema cache')) {\n logger.warn('usePublicEvent', 'RPC function not found or schema cache issue, attempting refresh:', rpcError.message);\n \n // Try to refresh schema cache first\n await refreshSchemaCache();\n \n // Try RPC call one more time after refresh\n try {\n const retryResponse = await (supabase as any).rpc('get_public_event_by_code', {\n event_code_param: eventCode\n });\n \n const retryData = retryResponse?.data;\n const retryError = retryResponse?.error;\n \n if (!retryError && retryData && retryData.length > 0) {\n eventData = retryData[0];\n } else {\n throw new Error('RPC still failing after cache refresh');\n }\n } catch (retryError) {\n logger.warn('usePublicEvent', 'RPC still failing after cache refresh, falling back to direct table access');\n \n // Fallback: Direct table access with public RLS policy\n const tableResponse2 = await (supabase as any)\n .from('event')\n .select(`\n event_id,\n event_name,\n event_date,\n event_venue,\n event_participants,\n event_colours,\n organisation_id,\n event_days,\n event_typicalunit,\n event_rounddown,\n event_youthmultiplier,\n event_catering_email,\n event_news,\n event_billing,\n event_email\n `)\n .eq('event_code', eventCode)\n .eq('is_visible', true)\n .not('organisation_id', 'is', null)\n .limit(1)\n .single();\n\n const tableData = tableResponse2?.data;\n const tableError = tableResponse2?.error;\n\n if (tableError) {\n throw new Error(tableError?.message || 'Failed to fetch event from table');\n }\n\n if (!tableData) {\n setEvent(null);\n setError(new Error('Event not found'));\n return;\n }\n\n // Get event logo from file_references\n const logoResponse = await (supabase as any)\n .from('file_references')\n .select('file_path')\n .eq('table_name', 'event')\n .eq('record_id', tableData.event_id)\n .eq('is_public', true)\n .eq('file_metadata->>category', 'event_logos')\n .limit(1)\n .single();\n \n const logoData = logoResponse?.data;\n\n eventData = {\n ...tableData,\n event_logo: logoData?.file_path || null\n };\n }\n } else {\n // For RPC errors that aren't schema cache issues, throw immediately without fallback\n const errorMessage = rpcError?.message || rpcError?.toString() || 'Failed to fetch event';\n setEvent(null);\n setError(new Error(errorMessage));\n setIsLoading(false);\n return;\n }\n } else {\n if (!data || data.length === 0 || !data[0]) {\n setEvent(null);\n setError(new Error('Event not found'));\n return;\n }\n eventData = data[0];\n }\n } catch (rpcError) {\n // If RPC call fails for any reason (including schema cache issues), try direct table access\n logger.warn('usePublicEvent', 'RPC call failed, falling back to direct table access:', rpcError);\n \n const tableResponse = await (supabase as any)\n .from('event')\n .select(`\n event_id,\n event_name,\n event_date,\n event_venue,\n event_participants,\n event_colours,\n organisation_id,\n event_days,\n event_typicalunit,\n event_rounddown,\n event_youthmultiplier,\n event_catering_email,\n event_news,\n event_billing,\n event_email\n `)\n .eq('event_code', eventCode)\n .eq('is_visible', true)\n .not('organisation_id', 'is', null)\n .limit(1)\n .single();\n\n const tableData = tableResponse?.data;\n const tableError = tableResponse?.error;\n\n if (tableError) {\n throw new Error(tableError?.message || 'Failed to fetch event from table');\n }\n\n if (!tableData) {\n setEvent(null);\n setError(new Error('Event not found'));\n return;\n }\n\n // Get event logo from file_references\n const logoResponse = await (supabase as any)\n .from('file_references')\n .select('file_path')\n .eq('table_name', 'event')\n .eq('record_id', tableData.event_id)\n .eq('is_public', true)\n .eq('file_metadata->>category', 'event_logos')\n .limit(1)\n .single();\n \n const logoData = logoResponse?.data;\n\n eventData = {\n ...tableData,\n event_logo: logoData?.file_path || null\n };\n }\n \n // Transform to Event type\n const transformedEvent: Event = {\n id: eventData.event_id,\n event_id: eventData.event_id,\n event_name: eventData.event_name,\n event_code: eventCode,\n event_date: eventData.event_date,\n event_venue: eventData.event_venue,\n event_participants: eventData.event_participants,\n event_logo: eventData.event_logo,\n event_colours: eventData.event_colours,\n organisation_id: assertOrganisationId(eventData.organisation_id),\n is_visible: true,\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString()\n };\n\n setEvent(transformedEvent);\n\n // Cache the result\n if (enableCache) {\n publicDataCache.set(cacheKey, {\n data: transformedEvent,\n timestamp: Date.now(),\n ttl: cacheTtl\n });\n }\n\n } catch (err) {\n logger.error('usePublicEvent', 'Error fetching event:', err);\n const error = err instanceof Error ? err : new Error('Unknown error occurred');\n setError(error);\n setEvent(null);\n } finally {\n setIsLoading(false);\n }\n }, [eventCode, supabase, cacheTtl, enableCache]);\n\n // Fetch event when eventCode changes\n useEffect(() => {\n fetchEvent();\n }, [fetchEvent]);\n\n const refetch = useCallback(async (): Promise<void> => {\n // Clear cache for this event\n if (enableCache) {\n const cacheKey = `public_event_${eventCode}`;\n publicDataCache.delete(cacheKey);\n }\n await fetchEvent();\n }, [fetchEvent, eventCode, enableCache]);\n\n return {\n event,\n isLoading,\n error,\n refetch\n };\n}\n\n/**\n * Clear all cached public event data\n * Useful for testing or when you need to force refresh all data\n */\nexport function clearPublicEventCache(): void {\n for (const [key] of publicDataCache) {\n if (key.startsWith('public_event_')) {\n publicDataCache.delete(key);\n }\n }\n}\n\n/**\n * Get cache statistics for debugging\n */\nexport function getPublicEventCacheStats(): { size: number; keys: string[] } {\n const keys = Array.from(publicDataCache.keys()).filter(key => key.startsWith('public_event_'));\n return {\n size: keys.length,\n keys\n };\n}\n","/**\n * @file Public Event Logo Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Public\n * @since 1.0.0\n *\n * A React hook for accessing public event logo URLs without authentication.\n * Provides logo URLs with fallback handling for public pages.\n *\n * Features:\n * - No authentication required\n * - Automatic fallback to event initials\n * - Caching for performance\n * - Error handling and loading states\n * - TypeScript support\n * - Image validation\n *\n * @example\n * ```tsx\n * import { usePublicEventLogo } from '@jmruthers/pace-core';\n *\n * function EventHeader() {\n * const { logoUrl, fallbackText, isLoading, error } = usePublicEventLogo(\n * eventId, \n * eventName, \n * organisationId\n * );\n *\n * if (isLoading) return <div>Loading logo...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return (\n * <div>\n * {logoUrl ? (\n * <img src={logoUrl} alt={`${eventName} logo`} />\n * ) : (\n * <div className=\"logo-fallback\">{fallbackText}</div>\n * )}\n * </div>\n * );\n * }\n * ```\n *\n * @accessibility\n * - No direct accessibility concerns (hook)\n * - Enables accessible logo display with proper alt text\n * - Supports screen reader friendly fallbacks\n *\n * @security\n * - Only returns public-safe logo URLs\n * - Validates image existence before returning URL\n * - No sensitive information exposed\n * - Rate limiting applied at storage level\n *\n * @performance\n * - Built-in caching with TTL\n * - Image validation and optimization\n * - Minimal re-renders with stable references\n * - Lazy loading support\n *\n * @dependencies\n * - React 18+ - Hooks and effects\n * - @supabase/supabase-js - Storage integration\n * - Event types - Type definitions\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport type { Database } from '../../types/database';\nimport { createLogger } from '../../utils/core/logger';\n\nconst log = createLogger('usePublicEventLogo');\n\n// Simple in-memory cache for public data\nconst publicDataCache = new Map<string, { data: any; timestamp: number; ttl: number }>();\n\nexport interface UsePublicEventLogoReturn {\n /** The logo URL if available, null if not found or error */\n logoUrl: string | null;\n /** Fallback text (event initials) if no logo is available */\n fallbackText: string;\n /** Whether the logo is currently loading */\n isLoading: boolean;\n /** Any error that occurred during loading */\n error: Error | null;\n /** Function to manually refetch the logo */\n refetch: () => Promise<void>;\n}\n\nexport interface UsePublicEventLogoOptions {\n /** Cache TTL in milliseconds (default: 30 minutes) */\n cacheTtl?: number;\n /** Whether to enable caching (default: true) */\n enableCache?: boolean;\n /** Whether to validate image existence (default: true) */\n validateImage?: boolean;\n /** Custom fallback text generator */\n generateFallbackText?: (eventName: string) => string;\n /** Supabase client instance (required) */\n supabase: SupabaseClient<Database>;\n}\n\n/**\n * Generate fallback text from event name (first letter of each word)\n */\nfunction defaultGenerateFallbackText(eventName: string): string {\n if (!eventName) return 'EV';\n \n return eventName\n .split(' ')\n .map(word => word.charAt(0).toUpperCase())\n .join('')\n .substring(0, 3); // Max 3 characters\n}\n\n/**\n * Hook for accessing public event logo URLs\n * \n * This hook provides access to event logo URLs without requiring\n * authentication. It includes fallback handling and image validation.\n * \n * @param eventId - The event ID to fetch logo for\n * @param eventName - The event name for fallback text generation\n * @param organisationId - The organisation ID for storage path\n * @param options - Configuration options for caching and behavior\n * @returns Object containing logo URL, fallback text, loading state, error, and refetch function\n */\nexport function usePublicEventLogo(\n eventId: string | undefined,\n eventName: string | undefined,\n organisationId: string | undefined,\n options: UsePublicEventLogoOptions\n): UsePublicEventLogoReturn {\n const {\n cacheTtl = 30 * 60 * 1000, // 30 minutes\n enableCache = true,\n validateImage = true,\n generateFallbackText = defaultGenerateFallbackText,\n supabase\n } = options;\n\n const [logoUrl, setLogoUrl] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Generate fallback text\n const fallbackText = useMemo(() => {\n return eventName ? generateFallbackText(eventName) : 'EV';\n }, [eventName, generateFallbackText]);\n\n const fetchLogo = useCallback(async (): Promise<void> => {\n if (!eventId || !organisationId || !supabase) {\n setLogoUrl(null);\n setIsLoading(false);\n return;\n }\n\n // Validate UUID format for organisationId to prevent database errors\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(organisationId)) {\n log.warn('Invalid organisationId format (not a valid UUID):', organisationId);\n // Don't return early - let the database handle the validation\n // This allows for more graceful error handling\n }\n\n // Check cache first\n const cacheKey = `public_logo_${eventId}_${organisationId}`;\n if (enableCache) {\n const cached = publicDataCache.get(cacheKey);\n if (cached && Date.now() - cached.timestamp < cached.ttl) {\n setLogoUrl(cached.data);\n setIsLoading(false);\n setError(null);\n return;\n }\n }\n\n try {\n setIsLoading(true);\n setError(null);\n\n // Call the public logo RPC function\n const { data, error: rpcError } = await (supabase as any).rpc('get_public_event_logo', {\n event_id_param: eventId,\n organisation_id_param: organisationId\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to fetch logo');\n }\n\n if (!data || data.length === 0 || !data[0] || !data[0].logo_url) {\n setLogoUrl(null);\n return;\n }\n\n const logoUrl = data[0].logo_url;\n\n // Validate image existence if requested\n if (validateImage) {\n try {\n const response = await fetch(logoUrl, { method: 'HEAD' });\n if (!response.ok) {\n log.warn('Logo URL not accessible:', logoUrl);\n setLogoUrl(null);\n return;\n }\n } catch (fetchError) {\n log.warn('Error validating logo URL:', fetchError);\n setLogoUrl(null);\n return;\n }\n }\n\n setLogoUrl(logoUrl);\n\n // Cache the result\n if (enableCache) {\n publicDataCache.set(cacheKey, {\n data: logoUrl,\n timestamp: Date.now(),\n ttl: cacheTtl\n });\n }\n\n } catch (err) {\n log.error('Error fetching logo:', err);\n const error = err instanceof Error ? err : new Error('Unknown error occurred');\n setError(error);\n setLogoUrl(null);\n } finally {\n setIsLoading(false);\n }\n }, [eventId, organisationId, supabase, cacheTtl, enableCache, validateImage]);\n\n // Fetch logo when parameters change\n useEffect(() => {\n if (eventId && organisationId) {\n fetchLogo();\n } else {\n setLogoUrl(null);\n setIsLoading(false);\n setError(null);\n }\n }, [fetchLogo, eventId, organisationId]);\n\n const refetch = useCallback(async (): Promise<void> => {\n if (!eventId || !organisationId) return;\n \n // Clear cache for this logo\n if (enableCache) {\n const cacheKey = `public_logo_${eventId}_${organisationId}`;\n publicDataCache.delete(cacheKey);\n }\n await fetchLogo();\n }, [fetchLogo, eventId, organisationId, enableCache]);\n\n return {\n logoUrl,\n fallbackText,\n isLoading,\n error,\n refetch\n };\n}\n\n/**\n * Clear all cached public logo data\n * Useful for testing or when you need to force refresh all data\n */\nexport function clearPublicLogoCache(): void {\n for (const [key] of publicDataCache) {\n if (key.startsWith('public_logo_')) {\n publicDataCache.delete(key);\n }\n }\n}\n\n/**\n * Get cache statistics for debugging\n */\nexport function getPublicLogoCacheStats(): { size: number; keys: string[] } {\n const keys = Array.from(publicDataCache.keys()).filter(key => key.startsWith('public_logo_'));\n return {\n size: keys.length,\n keys\n };\n}\n","/**\n * @file Public Route Params Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Public\n * @since 1.0.0\n *\n * A React hook for extracting and validating public route parameters.\n * Provides event code extraction and validation for public pages.\n *\n * Features:\n * - URL parameter extraction\n * - Event code validation\n * - TypeScript support\n * - Error handling\n * - Route pattern support\n *\n * @example\n * ```tsx\n * import { usePublicRouteParams } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * const { eventCode, eventId, event, error, isLoading } = usePublicRouteParams();\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!event) return <div>Event not found</div>;\n *\n * return (\n * <div>\n * <h1>{event.event_name}</h1>\n * <p>Event Code: {eventCode}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @accessibility\n * - No direct accessibility concerns (hook)\n * - Enables accessible route parameter handling\n * - Supports screen reader friendly error states\n *\n * @security\n * - Validates event codes before processing\n * - Sanitizes URL parameters\n * - No sensitive information exposed\n * - Rate limiting applied at route level\n *\n * @performance\n * - Minimal re-renders with stable references\n * - Efficient parameter extraction\n * - Caching integration\n *\n * @dependencies\n * - React 18+ - Hooks and effects\n * - React Router - URL parameter extraction\n * - Event types - Type definitions\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useParams, useLocation } from 'react-router-dom';\nimport type { Event } from '../../types/event';\nimport { usePublicEvent } from './usePublicEvent';\n\nexport interface UsePublicRouteParamsReturn {\n /** The event code from the URL */\n eventCode: string | null;\n /** The event ID (resolved from event code) */\n eventId: string | null;\n /** The full event object */\n event: Event | null;\n /** Whether the route parameters are being processed */\n isLoading: boolean;\n /** Any error that occurred during processing */\n error: Error | null;\n /** Function to manually refetch the event data */\n refetch: () => Promise<void>;\n}\n\ninterface UsePublicRouteParamsOptions {\n /** Whether to automatically fetch event data (default: true) */\n fetchEventData?: boolean;\n /** Custom event code parameter name (default: 'eventCode') */\n eventCodeParam?: string;\n /** Whether to validate event code format (default: true) */\n validateEventCode?: boolean;\n}\n\n/**\n * Validate event code format\n * Event codes should be alphanumeric with optional hyphens/underscores in the middle\n * Supports 2-50 characters\n */\nfunction validateEventCodeFormat(eventCode: string): boolean {\n if (!eventCode || typeof eventCode !== 'string') return false;\n \n // Length check: 2-50 characters\n if (eventCode.length < 2 || eventCode.length > 50) return false;\n \n // For 2-character codes: both must be alphanumeric\n if (eventCode.length === 2) {\n return /^[a-zA-Z0-9]{2}$/.test(eventCode);\n }\n \n // For 3+ character codes: alphanumeric at start and end, hyphens/underscores allowed in middle\n // Must not start or end with hyphen/underscore\n const eventCodeRegex = /^[a-zA-Z0-9][a-zA-Z0-9_-]{1,48}[a-zA-Z0-9]$/;\n const matchesFormat = eventCodeRegex.test(eventCode);\n \n if (!matchesFormat) return false;\n \n // Additional check: no consecutive hyphens or underscores\n if (eventCode.includes('--') || eventCode.includes('__') || eventCode.includes('-_') || eventCode.includes('_-')) {\n return false;\n }\n \n return true;\n}\n\n/**\n * Hook for extracting and validating public route parameters\n * \n * This hook extracts event codes from URL parameters and optionally\n * fetches the corresponding event data. It provides validation and\n * error handling for public routes.\n * \n * @param options - Configuration options for behavior\n * @returns Object containing route parameters, event data, loading state, error, and refetch function\n */\nexport function usePublicRouteParams(\n options: UsePublicRouteParamsOptions = {}\n): UsePublicRouteParamsReturn {\n const {\n fetchEventData = true,\n eventCodeParam = 'eventCode',\n validateEventCode = true\n } = options;\n\n const params = useParams();\n const location = useLocation();\n \n const [error, setError] = useState<Error | null>(null);\n\n // Extract event code from URL parameters\n const eventCode = useMemo(() => {\n const code = params[eventCodeParam] as string;\n \n if (!code) {\n // Don't set error immediately - let the component handle missing eventCode gracefully\n return null;\n }\n\n // Validate event code format if requested\n if (validateEventCode && !validateEventCodeFormat(code)) {\n setError(new Error(`Invalid event code format: ${code}`));\n return null;\n }\n\n setError(null);\n return code;\n }, [params, eventCodeParam, validateEventCode]);\n\n // Use the public event hook to fetch event data\n const {\n event,\n isLoading: eventLoading,\n error: eventError,\n refetch: refetchEvent\n } = usePublicEvent(eventCode || '', {\n enableCache: true,\n cacheTtl: 5 * 60 * 1000 // 5 minutes\n });\n\n // Determine if we should show loading state\n const isLoading = useMemo(() => {\n if (!fetchEventData) return false;\n return eventLoading;\n }, [fetchEventData, eventLoading]);\n\n // Determine the final error state\n const finalError = useMemo(() => {\n if (error) return error;\n if (eventError) return eventError;\n return null;\n }, [error, eventError]);\n\n // Extract event ID from event data\n const eventId = useMemo(() => {\n if (!event) return null;\n return event.event_id || event.id;\n }, [event]);\n\n // Refetch function\n const refetch = useCallback(async (): Promise<void> => {\n if (!fetchEventData) return;\n await refetchEvent();\n }, [fetchEventData, refetchEvent]);\n\n return {\n eventCode,\n eventId,\n event: fetchEventData ? event : null,\n isLoading,\n error: finalError,\n refetch\n };\n}\n\n/**\n * Hook for extracting just the event code without fetching event data\n * Useful when you only need the event code and will fetch data separately\n */\nexport function usePublicEventCode(\n eventCodeParam: string = 'eventCode'\n): { eventCode: string | null; error: Error | null } {\n const params = useParams();\n \n const eventCode = useMemo(() => {\n const code = params[eventCodeParam] as string;\n \n if (!code) {\n return null;\n }\n\n // Validate event code format\n if (!validateEventCodeFormat(code)) {\n return null;\n }\n\n return code;\n }, [params, eventCodeParam]);\n\n const error = useMemo(() => {\n if (!eventCode) {\n return new Error(`Event code parameter '${eventCodeParam}' not found or invalid`);\n }\n return null;\n }, [eventCode, eventCodeParam]);\n\n return {\n eventCode,\n error\n };\n}\n\n/**\n * Utility function to generate public route paths\n */\nexport function generatePublicRoutePath(\n eventCode: string,\n pageName: string = 'index'\n): string {\n if (!eventCode || !validateEventCodeFormat(eventCode)) {\n throw new Error('Invalid event code for route generation');\n }\n \n return `/public/event/${eventCode}/${pageName}`;\n}\n\n/**\n * Utility function to extract event code from a public route path\n * Supports 2-50 character event codes\n */\nexport function extractEventCodeFromPath(path: string): string | null {\n const match = path.match(/^\\/public\\/event\\/([a-zA-Z0-9_-]{2,50})(?:\\/.*)?$/);\n if (!match) return null;\n \n const eventCode = match[1];\n // Validate the extracted code using the same validation function\n if (!validateEventCodeFormat(eventCode)) {\n return null;\n }\n \n return eventCode;\n}\n"],"mappings":"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","names":["useCallback","useState","useState","useCallback","useMemo","useMemo","useState","useEffect","useCallback","useMemo","useState","useMemo","useCallback","error","useEffect","useState","useEffect","useCallback","useMemo","publicDataCache","useState","useMemo","useCallback","logoUrl","error","useEffect","useState","useCallback","useMemo","useState","useMemo","useCallback"]}