@jmruthers/pace-core 0.5.135 → 0.5.136
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DataTable-C7GaRZye.d.ts → DataTable-CWAZZcXC.d.ts} +1 -1
- package/dist/{DataTable-A36PJG6N.js → DataTable-CYOHOX3O.js} +25 -13
- package/dist/{PublicLoadingSpinner-CUAnTvcg.d.ts → EventLogo-801uofbR.d.ts} +51 -135
- package/dist/UnifiedAuthProvider-5E5TUNMS.js +17 -0
- package/dist/{UnifiedAuthProvider-BVKmQd9u.d.ts → UnifiedAuthProvider-DJxGTftH.d.ts} +1 -1
- package/dist/{api-TNIBJWLM.js → api-45XYYO2A.js} +4 -3
- package/dist/{audit-T36HM7IM.js → audit-64X3VJXB.js} +3 -2
- package/dist/{chunk-CTJRBUX2.js → chunk-2TWNJ46Y.js} +2 -2
- package/dist/{chunk-UJI6WSMD.js → chunk-444EZN6N.js} +3 -3
- package/dist/chunk-444EZN6N.js.map +1 -0
- package/dist/{chunk-3CG5L6RN.js → chunk-4MT5BGGL.js} +90 -73
- package/dist/chunk-4MT5BGGL.js.map +1 -0
- package/dist/{chunk-PYUXFQJ3.js → chunk-56XJ3TU6.js} +2 -2
- package/dist/chunk-56XJ3TU6.js.map +1 -0
- package/dist/chunk-5DPZ5EAT.js +60 -0
- package/dist/chunk-5DPZ5EAT.js.map +1 -0
- package/dist/{chunk-66C4BSAY.js → chunk-ANBQRTPX.js} +9 -2
- package/dist/chunk-ANBQRTPX.js.map +1 -0
- package/dist/chunk-APIBCTL2.js +670 -0
- package/dist/chunk-APIBCTL2.js.map +1 -0
- package/dist/{chunk-GKHF54DI.js → chunk-BESYRHQM.js} +10 -4
- package/dist/chunk-BESYRHQM.js.map +1 -0
- package/dist/{chunk-WP5I5GLN.js → chunk-BVYWGZVV.js} +112 -97
- package/dist/chunk-BVYWGZVV.js.map +1 -0
- package/dist/{chunk-GEVIB2UB.js → chunk-ERISIBYU.js} +14 -5
- package/dist/chunk-ERISIBYU.js.map +1 -0
- package/dist/{chunk-CQZU6TFE.js → chunk-FHWWBIHA.js} +100 -62
- package/dist/chunk-FHWWBIHA.js.map +1 -0
- package/dist/{chunk-O3NWNXDY.js → chunk-FMUCXFII.js} +2 -2
- package/dist/chunk-FMUCXFII.js.map +1 -0
- package/dist/{chunk-GVDR7WNV.js → chunk-HJGGOMQ6.js} +194 -518
- package/dist/chunk-HJGGOMQ6.js.map +1 -0
- package/dist/{chunk-BDZUMRBD.js → chunk-K2WWTH7O.js} +13 -6
- package/dist/chunk-K2WWTH7O.js.map +1 -0
- package/dist/{chunk-BYXRHAIF.js → chunk-L6PGMCMD.js} +23 -14
- package/dist/chunk-L6PGMCMD.js.map +1 -0
- package/dist/chunk-LMC26NLJ.js +84 -0
- package/dist/chunk-LMC26NLJ.js.map +1 -0
- package/dist/{chunk-M6DDYFUD.js → chunk-LS353YLY.js} +19 -16
- package/dist/chunk-LS353YLY.js.map +1 -0
- package/dist/{chunk-ZYZCRSBD.js → chunk-LTV3XIJJ.js} +16 -11
- package/dist/chunk-LTV3XIJJ.js.map +1 -0
- package/dist/{chunk-HMNOSGVA.js → chunk-NOHEVYVX.js} +377 -666
- package/dist/chunk-NOHEVYVX.js.map +1 -0
- package/dist/{chunk-JCQZ6LA7.js → chunk-Q5QRDWKI.js} +9 -3
- package/dist/chunk-Q5QRDWKI.js.map +1 -0
- package/dist/chunk-S5OFRT4M.js +94 -0
- package/dist/chunk-S5OFRT4M.js.map +1 -0
- package/dist/{chunk-3DBFLLLU.js → chunk-SBVILCCA.js} +14 -9
- package/dist/chunk-SBVILCCA.js.map +1 -0
- package/dist/{chunk-TGIY2AR2.js → chunk-SL2YQDR6.js} +4 -3
- package/dist/{chunk-TGIY2AR2.js.map → chunk-SL2YQDR6.js.map} +1 -1
- package/dist/{chunk-VZ5OR6HD.js → chunk-TVYPTYOY.js} +55 -179
- package/dist/chunk-TVYPTYOY.js.map +1 -0
- package/dist/{chunk-ZV77RZMU.js → chunk-XARJS7CD.js} +2 -2
- package/dist/chunk-XDNLUEXI.js +138 -0
- package/dist/chunk-XDNLUEXI.js.map +1 -0
- package/dist/{chunk-F64FFPOZ.js → chunk-YLKIDTUK.js} +26 -20
- package/dist/chunk-YLKIDTUK.js.map +1 -0
- package/dist/{chunk-5F3NDPJV.js → chunk-ZZ2SS7NI.js} +10 -5
- package/dist/chunk-ZZ2SS7NI.js.map +1 -0
- package/dist/components.d.ts +7 -287
- package/dist/components.js +26 -157
- package/dist/components.js.map +1 -1
- package/dist/{file-reference-C9isKNPn.d.ts → file-reference-C6Gkn77H.d.ts} +1 -1
- package/dist/{formatting-DFcCxUEk.d.ts → formatting-CvUXy2mF.d.ts} +1 -1
- package/dist/hooks.d.ts +3 -3
- package/dist/hooks.js +22 -16
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +101 -9
- package/dist/index.js +43 -31
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +5 -4
- package/dist/rbac/index.js +13 -12
- package/dist/styles/index.js +2 -1
- package/dist/theming/runtime.d.ts +2 -19
- package/dist/theming/runtime.js +2 -1
- package/dist/{types-D5rqZQXk.d.ts → types-Dfz9dmVH.d.ts} +12 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- package/dist/{useInactivityTracker-MRUU55XI.js → useInactivityTracker-TO6ZOF35.js} +3 -2
- package/dist/{usePublicRouteParams-Dyt1tzI9.d.ts → usePublicRouteParams-B7PabvuH.d.ts} +1 -1
- package/dist/utils.d.ts +195 -232
- package/dist/utils.js +173 -331
- package/dist/utils.js.map +1 -1
- package/dist/{validation-DnhrNMju.d.ts → validation-8npbysjg.d.ts} +26 -8
- package/dist/validation.d.ts +261 -10
- package/dist/validation.js +82 -440
- package/dist/validation.js.map +1 -1
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +6 -6
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +6 -6
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +7 -7
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +4 -4
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +29 -4
- package/docs/api/interfaces/DataAccessRecord.md +9 -9
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +18 -18
- package/docs/api/interfaces/DataTableColumn.md +61 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
- package/docs/api/interfaces/EmptyStateConfig.md +5 -5
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +14 -14
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +152 -0
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +8 -8
- package/docs/api/interfaces/FileDisplayProps.md +15 -15
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
- package/docs/api/interfaces/NavigationContextType.md +9 -9
- package/docs/api/interfaces/NavigationGuardProps.md +10 -10
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +7 -7
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +27 -27
- package/docs/api/interfaces/PaceLoginPageProps.md +4 -4
- package/docs/api/interfaces/PageAccessRecord.md +8 -8
- package/docs/api/interfaces/PagePermissionContextType.md +8 -8
- package/docs/api/interfaces/PagePermissionGuardProps.md +11 -11
- package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
- package/docs/api/interfaces/PaletteData.md +4 -4
- package/docs/api/interfaces/PermissionEnforcerProps.md +11 -11
- package/docs/api/interfaces/ProtectedRouteProps.md +6 -6
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
- package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +10 -10
- package/docs/api/interfaces/RouteConfig.md +10 -10
- package/docs/api/interfaces/SecureDataContextType.md +9 -9
- package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +21 -0
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +9 -9
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
- package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
- package/docs/api/interfaces/UsePublicEventReturn.md +5 -5
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +9 -9
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +4 -4
- package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
- package/docs/api/interfaces/UserEventAccess.md +11 -11
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +514 -212
- package/docs/api-reference/components.md +106 -26
- package/docs/architecture/README.md +0 -2
- package/docs/implementation-guides/data-tables.md +277 -13
- package/docs/implementation-guides/forms.md +1 -16
- package/docs/implementation-guides/permission-enforcement.md +8 -2
- package/examples/README.md +30 -14
- package/examples/STRUCTURE.md +125 -0
- package/examples/components/DataTable/HierarchicalActionsExample.tsx +421 -0
- package/examples/components/DataTable/HierarchicalExample.tsx +475 -0
- package/examples/components/DataTable/InitialPageSizeExample.tsx +177 -0
- package/examples/components/DataTable/PerformanceExample.tsx +506 -0
- package/examples/components/DataTable/index.ts +13 -0
- package/examples/components/Dialog/BasicHtmlTest.tsx +55 -0
- package/examples/components/Dialog/DebugHtmlExample.tsx +68 -0
- package/examples/components/Dialog/HtmlDialogExample.tsx +202 -0
- package/examples/components/Dialog/ScrollableDialogExample.tsx +290 -0
- package/examples/components/Dialog/SimpleHtmlTest.tsx +61 -0
- package/examples/components/Dialog/SmartDialogExample.tsx +322 -0
- package/examples/components/Dialog/index.ts +15 -0
- package/examples/components/index.ts +11 -0
- package/examples/features/index.ts +12 -0
- package/examples/{public-pages → features/public-pages}/CorrectPublicPageImplementation.tsx +1 -1
- package/examples/{public-pages → features/public-pages}/PublicEventPage.tsx +1 -1
- package/examples/{public-pages → features/public-pages}/PublicPageApp.tsx +1 -1
- package/examples/{public-pages → features/public-pages}/PublicPageUsageExample.tsx +1 -1
- package/examples/index.ts +11 -3
- package/package.json +30 -10
- package/src/components/Alert/Alert.tsx +1 -1
- package/src/components/Avatar/Avatar.tsx +1 -1
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Card/Card.tsx +1 -1
- package/src/components/Checkbox/Checkbox.tsx +1 -1
- package/src/components/DataTable/DataTable.test.tsx +1 -1
- package/src/components/DataTable/DataTable.tsx +1 -30
- package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +562 -0
- package/src/components/DataTable/__tests__/styles.test.ts +2 -2
- package/src/components/DataTable/components/ActionButtons.tsx +0 -15
- package/src/components/DataTable/components/DataTableCore.tsx +4 -185
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +1 -1
- package/src/components/DataTable/components/DataTableModals.tsx +1 -27
- package/src/components/DataTable/components/EditableRow.tsx +1 -1
- package/src/components/DataTable/components/ImportModal.tsx +2 -14
- package/src/components/DataTable/components/PaginationControls.tsx +1 -1
- package/src/components/DataTable/components/UnifiedTableBody.tsx +109 -82
- package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +1 -1
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +1 -1
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +1 -1
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +1 -1
- package/src/components/DataTable/examples/GroupingAggregationExample.tsx +273 -0
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +1 -1
- package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +1 -1
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +1 -1
- package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +1 -1
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +2 -23
- package/src/components/DataTable/index.ts +4 -0
- package/src/components/DataTable/styles.ts +1 -1
- package/src/components/DataTable/types.ts +13 -0
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +1 -1
- package/src/components/DataTable/utils/aggregationUtils.ts +161 -0
- package/src/components/DataTable/utils/exportUtils.ts +1 -1
- package/src/components/DataTable/utils/flexibleImport.ts +1 -11
- package/src/components/DataTable/utils/index.ts +1 -0
- package/src/components/DataTable/utils/paginationUtils.ts +1 -1
- package/src/components/Dialog/Dialog.tsx +2 -2
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +35 -7
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +5 -4
- package/src/components/EventSelector/EventSelector.tsx +3 -2
- package/src/components/FileDisplay/FileDisplay.tsx +2 -36
- package/src/components/FileUpload/FileUpload.test.tsx +2 -2
- package/src/components/FileUpload/FileUpload.tsx +2 -2
- package/src/components/Footer/Footer.tsx +1 -1
- package/src/components/Form/Form.test.tsx +4 -509
- package/src/components/Form/Form.tsx +1 -1
- package/src/components/Form/FormField.tsx +1 -1
- package/src/components/Form/index.ts +0 -12
- package/src/components/Header/Header.tsx +1 -1
- package/src/components/Input/Input.tsx +1 -1
- package/src/components/Label/Label.tsx +1 -1
- package/src/components/LoginForm/LoginForm.tsx +1 -1
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -3
- package/src/components/NavigationMenu/NavigationMenu.tsx +9 -8
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +4 -3
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +14 -12
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +0 -16
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +0 -1
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -9
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +35 -3
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +13 -12
- package/src/components/PasswordReset/PasswordChangeForm.tsx +1 -1
- package/src/components/PasswordReset/index.ts +0 -2
- package/src/components/Progress/Progress.tsx +1 -1
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +35 -8
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -2
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +1 -1
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +1 -1
- package/src/components/PublicLayout/PublicPageContextChecker.tsx +44 -43
- package/src/components/PublicLayout/PublicPageFooter.tsx +1 -1
- package/src/components/PublicLayout/PublicPageHeader.tsx +1 -15
- package/src/components/PublicLayout/PublicPageProvider.tsx +3 -2
- package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +2 -0
- package/src/components/PublicLayout/index.ts +4 -2
- package/src/components/Select/Select.tsx +1 -1
- package/src/components/{SessionRestorationLoader.tsx → SessionRestorationLoader/SessionRestorationLoader.tsx} +3 -2
- package/src/components/SessionRestorationLoader/index.ts +3 -0
- package/src/components/Switch/Switch.tsx +1 -1
- package/src/components/Table/Table.tsx +1 -1
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/components/Tooltip/Tooltip.tsx +1 -1
- package/src/components/index.ts +4 -10
- package/src/hooks/__tests__/hooks.integration.test.tsx +37 -22
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +33 -17
- package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +28 -3
- package/src/hooks/__tests__/useFileDisplay.unit.test.ts +36 -9
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +26 -2
- package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +19 -6
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +17 -4
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +17 -4
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +26 -6
- package/src/hooks/__tests__/usePublicFileDisplay.test.ts +16 -6
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +3 -3
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +17 -3
- package/src/hooks/public/usePublicEvent.ts +7 -6
- package/src/hooks/public/usePublicEventLogo.ts +7 -4
- package/src/hooks/public/usePublicFileDisplay.ts +6 -150
- package/src/hooks/useComponentPerformance.ts +4 -1
- package/src/hooks/useDataTablePerformance.ts +4 -3
- package/src/hooks/useEventTheme.test.ts +18 -5
- package/src/hooks/useEventTheme.ts +4 -1
- package/src/hooks/useEvents.ts +2 -0
- package/src/hooks/useFileDisplay.ts +9 -8
- package/src/hooks/useFileReference.ts +4 -1
- package/src/hooks/useFileUrl.ts +4 -1
- package/src/hooks/useInactivityTracker.ts +5 -4
- package/src/hooks/useOrganisationSecurity.test.ts +33 -12
- package/src/hooks/useOrganisationSecurity.ts +8 -7
- package/src/hooks/usePerformanceMonitor.ts +6 -3
- package/src/hooks/usePermissionCache.ts +13 -6
- package/src/hooks/useSecureDataAccess.test.ts +2 -2
- package/src/hooks/useSecureDataAccess.ts +9 -8
- package/src/hooks/useSessionRestoration.ts +4 -1
- package/src/hooks/useStorage.ts +4 -1
- package/src/index.ts +16 -7
- package/src/providers/services/AuthServiceProvider.tsx +3 -2
- package/src/providers/services/EventServiceProvider.tsx +2 -1
- package/src/providers/services/InactivityServiceProvider.tsx +2 -1
- package/src/providers/services/OrganisationServiceProvider.tsx +2 -1
- package/src/providers/services/UnifiedAuthProvider.tsx +4 -3
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +22 -2
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +24 -2
- package/src/rbac/__tests__/cache-invalidation.test.ts +20 -6
- package/src/rbac/api.ts +5 -2
- package/src/rbac/audit-enhanced.ts +6 -6
- package/src/rbac/audit.test.ts +60 -38
- package/src/rbac/audit.ts +8 -8
- package/src/rbac/cache-invalidation.ts +7 -4
- package/src/rbac/components/EnhancedNavigationMenu.tsx +11 -5
- package/src/rbac/components/NavigationGuard.tsx +7 -3
- package/src/rbac/components/NavigationProvider.tsx +6 -3
- package/src/rbac/components/PagePermissionGuard.tsx +28 -16
- package/src/rbac/components/PagePermissionProvider.tsx +4 -1
- package/src/rbac/components/PermissionEnforcer.tsx +9 -3
- package/src/rbac/components/RoleBasedRouter.tsx +3 -1
- package/src/rbac/components/SecureDataProvider.tsx +7 -3
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +87 -61
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +83 -33
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +36 -13
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +2 -2
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +22 -8
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +19 -6
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +43 -17
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +42 -17
- package/src/rbac/engine.ts +15 -7
- package/src/rbac/hooks/usePermissions.ts +7 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +2 -2
- package/src/rbac/hooks/useResolvedScope.ts +10 -7
- package/src/rbac/permissions.ts +5 -2
- package/src/rbac/security.test.ts +27 -16
- package/src/rbac/security.ts +5 -4
- package/src/services/AuthService.ts +22 -21
- package/src/services/EventService.ts +12 -12
- package/src/services/InactivityService.ts +5 -4
- package/src/services/OrganisationService.ts +26 -25
- package/src/services/__tests__/AuthService.test.ts +51 -19
- package/src/services/__tests__/EventService.test.ts +37 -5
- package/src/services/__tests__/InactivityService.test.ts +38 -4
- package/src/services/__tests__/OrganisationService.test.ts +3 -8
- package/src/services/base/BaseService.ts +3 -1
- package/src/theming/__tests__/runtime.test.ts +21 -12
- package/src/theming/parseEventColours.ts +5 -19
- package/src/theming/runtime.ts +8 -4
- package/src/types/validation.ts +2 -29
- package/src/utils/__tests__/appConfig.unit.test.ts +1 -1
- package/src/utils/__tests__/audit.unit.test.ts +1 -1
- package/src/utils/__tests__/auth-utils.unit.test.ts +1 -1
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +19 -19
- package/src/utils/__tests__/cn.unit.test.ts +1 -1
- package/src/utils/__tests__/debugLogger.test.ts +1 -1
- package/src/utils/__tests__/deviceFingerprint.unit.test.ts +1 -1
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +1 -1
- package/src/utils/__tests__/formatting.unit.test.ts +1 -1
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +1 -1
- package/src/utils/__tests__/logger.unit.test.ts +1 -1
- package/src/utils/__tests__/organisationContext.unit.test.ts +1 -1
- package/src/utils/__tests__/performanceBenchmark.test.ts +1 -1
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +1 -1
- package/src/utils/__tests__/permissionTypes.unit.test.ts +1 -1
- package/src/utils/__tests__/permissionUtils.unit.test.ts +1 -1
- package/src/utils/__tests__/sanitization.unit.test.ts +1 -1
- package/src/utils/__tests__/schemaUtils.unit.test.ts +1 -1
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +1 -1
- package/src/utils/__tests__/secureErrors.unit.test.ts +33 -15
- package/src/utils/__tests__/secureStorage.unit.test.ts +1 -1
- package/src/utils/__tests__/security.unit.test.ts +40 -18
- package/src/utils/__tests__/securityMonitor.unit.test.ts +1 -1
- package/src/utils/__tests__/sessionTracking.unit.test.ts +40 -29
- package/src/utils/__tests__/validationUtils.unit.test.ts +19 -6
- package/src/utils/{appIdResolver.test.ts → app/appIdResolver.test.ts} +28 -30
- package/src/utils/{appIdResolver.ts → app/appIdResolver.ts} +8 -5
- package/src/utils/{appNameResolver.test.ts → app/appNameResolver.test.ts} +1 -1
- package/src/utils/{appNameResolver.ts → app/appNameResolver.ts} +5 -1
- package/src/utils/{organisationContext.ts → context/organisationContext.ts} +6 -3
- package/src/utils/{sessionTracking.ts → context/sessionTracking.ts} +11 -12
- package/src/utils/{logger.ts → core/logger.ts} +4 -2
- package/src/utils/{deviceFingerprint.ts → device/deviceFingerprint.ts} +1 -1
- package/src/utils/{lazyLoad.tsx → dynamic/lazyLoad.tsx} +2 -2
- package/src/utils/{file-reference.test.ts → file-reference/__tests__/file-reference.test.ts} +5 -5
- package/src/utils/{file-reference.ts → file-reference/index.ts} +20 -38
- package/src/utils/index.ts +32 -54
- package/src/utils/{secureErrors.ts → security/secureErrors.ts} +6 -3
- package/src/utils/{security.ts → security/security.ts} +5 -2
- package/src/utils/storage/__tests__/helpers.unit.test.ts +1 -4
- package/src/utils/storage/helpers.ts +15 -8
- package/src/{components/Dialog/utils/__tests__/safeHtml.unit.test.ts → utils/validation/__tests__/htmlSanitization.unit.test.ts} +9 -15
- package/src/{validation → utils/validation}/csrf.ts +1 -1
- package/src/{components/Dialog/utils/safeHtml.ts → utils/validation/htmlSanitization.ts} +9 -10
- package/src/utils/validation/index.ts +79 -0
- package/src/utils/{sanitization.ts → validation/sanitization.ts} +71 -2
- package/src/{validation/schemaUtils.ts → utils/validation/schema.ts} +11 -6
- package/src/{validation → utils/validation}/sqlInjectionProtection.ts +2 -0
- package/src/utils/{validationUtils.ts → validation/validationUtils.ts} +4 -1
- package/src/validation/index.ts +3 -34
- package/dist/UnifiedAuthProvider-CQDZRJIS.js +0 -16
- package/dist/chunk-24MKLB7U.js +0 -81
- package/dist/chunk-24MKLB7U.js.map +0 -1
- package/dist/chunk-3CG5L6RN.js.map +0 -1
- package/dist/chunk-3DBFLLLU.js.map +0 -1
- package/dist/chunk-5F3NDPJV.js.map +0 -1
- package/dist/chunk-66C4BSAY.js.map +0 -1
- package/dist/chunk-BDZUMRBD.js.map +0 -1
- package/dist/chunk-BYXRHAIF.js.map +0 -1
- package/dist/chunk-CDQ3PX7L.js +0 -18
- package/dist/chunk-CDQ3PX7L.js.map +0 -1
- package/dist/chunk-CQZU6TFE.js.map +0 -1
- package/dist/chunk-F64FFPOZ.js.map +0 -1
- package/dist/chunk-GEVIB2UB.js.map +0 -1
- package/dist/chunk-GKHF54DI.js.map +0 -1
- package/dist/chunk-GVDR7WNV.js.map +0 -1
- package/dist/chunk-HMNOSGVA.js.map +0 -1
- package/dist/chunk-JCQZ6LA7.js.map +0 -1
- package/dist/chunk-M6DDYFUD.js.map +0 -1
- package/dist/chunk-O3NWNXDY.js.map +0 -1
- package/dist/chunk-PYUXFQJ3.js.map +0 -1
- package/dist/chunk-UJI6WSMD.js.map +0 -1
- package/dist/chunk-VZ5OR6HD.js.map +0 -1
- package/dist/chunk-WP5I5GLN.js.map +0 -1
- package/dist/chunk-ZYZCRSBD.js.map +0 -1
- package/src/components/Dialog/README.md +0 -804
- package/src/components/Form/FormErrorSummary.tsx +0 -113
- package/src/components/Form/FormFieldset.tsx +0 -127
- package/src/components/Form/FormLiveRegion.tsx +0 -198
- package/src/components/PasswordReset/PasswordResetForm.test.tsx +0 -597
- package/src/components/PasswordReset/PasswordResetForm.tsx +0 -201
- package/src/components/PublicLayout/PublicPageDebugger.tsx +0 -104
- package/src/components/PublicLayout/PublicPageDiagnostic.tsx +0 -162
- package/src/components/PublicLayout/__tests__/PublicPageDebugger.test.tsx +0 -185
- package/src/examples/CorrectPublicPageImplementation.tsx +0 -304
- package/src/examples/PublicEventPage.tsx +0 -287
- package/src/examples/PublicPageApp.tsx +0 -321
- package/src/examples/PublicPageUsageExample.tsx +0 -218
- package/src/utils/schemaUtils.ts +0 -37
- package/src/validation/__tests__/common.unit.test.ts +0 -101
- package/src/validation/__tests__/csrf.unit.test.ts +0 -365
- package/src/validation/__tests__/passwordSchema.unit.test.ts +0 -203
- package/src/validation/__tests__/sanitization.unit.test.ts +0 -250
- package/src/validation/__tests__/schemaUtils.unit.test.ts +0 -451
- package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +0 -462
- package/src/validation/__tests__/user.unit.test.ts +0 -440
- package/src/validation/sanitization.ts +0 -96
- /package/dist/{DataTable-A36PJG6N.js.map → DataTable-CYOHOX3O.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-CQDZRJIS.js.map → UnifiedAuthProvider-5E5TUNMS.js.map} +0 -0
- /package/dist/{api-TNIBJWLM.js.map → api-45XYYO2A.js.map} +0 -0
- /package/dist/{audit-T36HM7IM.js.map → audit-64X3VJXB.js.map} +0 -0
- /package/dist/{chunk-CTJRBUX2.js.map → chunk-2TWNJ46Y.js.map} +0 -0
- /package/dist/{chunk-ZV77RZMU.js.map → chunk-XARJS7CD.js.map} +0 -0
- /package/dist/{useInactivityTracker-MRUU55XI.js.map → useInactivityTracker-TO6ZOF35.js.map} +0 -0
- /package/examples/{public-pages → features/public-pages}/index.ts +0 -0
- /package/examples/{RBAC → features/rbac}/CompleteRBACExample.tsx +0 -0
- /package/examples/{RBAC → features/rbac}/EventBasedApp.tsx +0 -0
- /package/examples/{RBAC → features/rbac}/PermissionExample.tsx +0 -0
- /package/examples/{RBAC → features/rbac}/index.ts +0 -0
- /package/src/utils/{appConfig.ts → app/appConfig.ts} +0 -0
- /package/src/utils/{appNameResolver.simple.test.ts → app/appNameResolver.simple.test.ts} +0 -0
- /package/src/utils/{audit.ts → audit/audit.ts} +0 -0
- /package/src/utils/{organisationContext.test.ts → context/organisationContext.test.ts} +0 -0
- /package/src/utils/{cn.ts → core/cn.ts} +0 -0
- /package/src/utils/{debugLogger.ts → core/debugLogger.ts} +0 -0
- /package/src/utils/{dynamicUtils.ts → dynamic/dynamicUtils.ts} +0 -0
- /package/src/utils/{formatDate.test.ts → formatting/formatDate.test.ts} +0 -0
- /package/src/utils/{formatting.ts → formatting/formatting.ts} +0 -0
- /package/src/utils/{bundleAnalysis.ts → performance/bundleAnalysis.ts} +0 -0
- /package/src/utils/{performanceBenchmark.ts → performance/performanceBenchmark.ts} +0 -0
- /package/src/utils/{performanceBudgets.ts → performance/performanceBudgets.ts} +0 -0
- /package/src/utils/{permissionTypes.ts → permissions/permissionTypes.ts} +0 -0
- /package/src/utils/{permissionUtils.test.ts → permissions/permissionUtils.test.ts} +0 -0
- /package/src/utils/{permissionUtils.ts → permissions/permissionUtils.ts} +0 -0
- /package/src/utils/{auth-utils.ts → security/auth-utils.ts} +0 -0
- /package/src/utils/{secureDataAccess.test.ts → security/secureDataAccess.test.ts} +0 -0
- /package/src/utils/{secureDataAccess.ts → security/secureDataAccess.ts} +0 -0
- /package/src/utils/{secureStorage.ts → security/secureStorage.ts} +0 -0
- /package/src/utils/{securityMonitor.ts → security/securityMonitor.ts} +0 -0
- /package/src/{validation → utils/validation}/common.ts +0 -0
- /package/src/{validation → utils/validation}/passwordSchema.ts +0 -0
- /package/src/{validation → utils/validation}/user.ts +0 -0
- /package/src/utils/{validation.ts → validation/validation.ts} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/rbac/secureClient.ts","../src/rbac/components/PagePermissionProvider.tsx","../src/rbac/components/PagePermissionGuard.tsx","../src/rbac/components/SecureDataProvider.tsx","../src/rbac/components/PermissionEnforcer.tsx","../src/rbac/components/RoleBasedRouter.tsx","../src/rbac/components/NavigationProvider.tsx","../src/rbac/components/NavigationGuard.tsx","../src/rbac/components/EnhancedNavigationMenu.tsx","../src/rbac/adapters.tsx","../src/rbac/permissions.ts"],"sourcesContent":["/**\n * Secure Supabase Client for RBAC\n * @package @jmruthers/pace-core\n * @module RBAC/SecureClient\n * @since 1.0.0\n * \n * This module provides a secure Supabase client that enforces organisation context\n * and prevents direct database access outside of the RBAC system.\n */\n\nimport { createClient, SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../types/database';\nimport { UUID } from './types';\nimport { OrganisationContextRequiredError } from './types';\n\n/**\n * Secure Supabase Client that enforces organisation context\n * \n * This client automatically injects organisation context into all requests\n * and prevents queries that don't have the required context.\n */\nexport class SecureSupabaseClient {\n private supabase: SupabaseClient<Database>;\n private supabaseUrl: string;\n private supabaseKey: string;\n private organisationId: UUID;\n private eventId?: string;\n private appId?: UUID;\n\n constructor(\n supabaseUrl: string,\n supabaseKey: string,\n organisationId: UUID,\n eventId?: string,\n appId?: UUID\n ) {\n this.supabaseUrl = supabaseUrl;\n this.supabaseKey = supabaseKey;\n this.organisationId = organisationId;\n this.eventId = eventId;\n this.appId = appId;\n\n // Create the base Supabase client\n this.supabase = createClient<Database>(supabaseUrl, supabaseKey, {\n global: {\n headers: {\n 'x-organisation-id': organisationId,\n 'x-event-id': eventId || '',\n 'x-app-id': appId || '',\n },\n },\n });\n\n // Override the auth methods to inject context\n this.setupContextInjection();\n }\n\n /**\n * Setup context injection for all database operations\n */\n private setupContextInjection() {\n const originalFrom = this.supabase.from.bind(this.supabase);\n \n this.supabase.from = (table: string) => {\n // Validate context before allowing any database operations\n this.validateContext();\n \n const query = originalFrom(table);\n \n // Inject organisation context into all queries\n return this.injectContext(query);\n };\n\n const originalRpc = this.supabase.rpc.bind(this.supabase);\n \n // Override rpc method to inject context\n // Type assertion needed because we're wrapping the generic rpc method\n (this.supabase as any).rpc = (fn: string, args?: any, options?: any) => {\n // Validate context before allowing any RPC calls\n this.validateContext();\n \n // Inject context into RPC calls\n const contextArgs = {\n ...args,\n p_organisation_id: this.organisationId,\n p_event_id: this.eventId,\n p_app_id: this.appId,\n };\n \n return originalRpc(fn, contextArgs, options);\n };\n }\n\n /**\n * Inject organisation context into a query\n */\n private injectContext(query: any) {\n const originalSelect = query.select.bind(query);\n const originalInsert = query.insert.bind(query);\n const originalUpdate = query.update.bind(query);\n const originalDelete = query.delete.bind(query);\n\n // Override select to add organisation filter\n query.select = (columns?: string) => {\n const result = originalSelect(columns);\n return this.addOrganisationFilter(result);\n };\n\n // Override insert to add organisation context\n query.insert = (values: any) => {\n const contextValues = Array.isArray(values) \n ? values.map(v => ({ ...v, organisation_id: this.organisationId }))\n : { ...values, organisation_id: this.organisationId };\n \n return originalInsert(contextValues);\n };\n\n // Override update to add organisation filter\n query.update = (values: any) => {\n const result = originalUpdate(values);\n return this.addOrganisationFilter(result);\n };\n\n // Override delete to add organisation filter\n query.delete = () => {\n const result = originalDelete();\n return this.addOrganisationFilter(result);\n };\n\n return query;\n }\n\n /**\n * Add organisation filter to a query\n */\n private addOrganisationFilter(query: any) {\n // Add organisation_id filter to all queries\n return query.eq('organisation_id', this.organisationId);\n }\n\n /**\n * Validate that required context is present\n */\n private validateContext() {\n if (!this.organisationId) {\n throw new OrganisationContextRequiredError();\n }\n }\n\n /**\n * Get the current organisation ID\n */\n getOrganisationId(): UUID {\n return this.organisationId;\n }\n\n /**\n * Get the current event ID\n */\n getEventId(): string | undefined {\n return this.eventId;\n }\n\n /**\n * Get the current app ID\n */\n getAppId(): UUID | undefined {\n return this.appId;\n }\n\n /**\n * Create a new client with updated context\n */\n withContext(updates: {\n organisationId?: UUID;\n eventId?: string;\n appId?: UUID;\n }): SecureSupabaseClient {\n return new SecureSupabaseClient(\n this.supabaseUrl,\n this.supabaseKey,\n updates.organisationId || this.organisationId,\n updates.eventId !== undefined ? updates.eventId : this.eventId,\n updates.appId !== undefined ? updates.appId : this.appId\n );\n }\n\n /**\n * Get the underlying Supabase client (for internal use only)\n * @internal\n */\n getClient(): SupabaseClient<Database> {\n return this.supabase;\n }\n}\n\n/**\n * Create a secure Supabase client with organisation context\n * \n * @param supabaseUrl - Supabase project URL\n * @param supabaseKey - Supabase anon key\n * @param organisationId - Required organisation ID\n * @param eventId - Optional event ID\n * @param appId - Optional app ID\n * @returns SecureSupabaseClient instance\n * \n * @example\n * ```typescript\n * const client = createSecureClient(\n * 'https://your-project.supabase.co',\n * 'your-anon-key',\n * 'org-123',\n * 'event-456',\n * 'app-789'\n * );\n * ```\n */\nexport function createSecureClient(\n supabaseUrl: string,\n supabaseKey: string,\n organisationId: UUID,\n eventId?: string,\n appId?: UUID\n): SecureSupabaseClient {\n return new SecureSupabaseClient(supabaseUrl, supabaseKey, organisationId, eventId, appId);\n}\n\n/**\n * Create a secure client from an existing Supabase client\n * \n * @param client - Existing Supabase client\n * @param organisationId - Required organisation ID\n * @param eventId - Optional event ID\n * @param appId - Optional app ID\n * @returns SecureSupabaseClient instance\n */\nexport function fromSupabaseClient(\n client: SupabaseClient<Database>,\n organisationId: UUID,\n eventId?: string,\n appId?: UUID\n): SecureSupabaseClient {\n // We need the URL and key to create a new client, but they're not accessible\n // This function should be used with createSecureClient instead\n throw new Error('fromSupabaseClient is not supported. Use createSecureClient instead.');\n}\n","/**\n * @file Page Permission Provider Component\n * @package @jmruthers/pace-core\n * @module RBAC/Components/PagePermissionProvider\n * @since 2.0.0\n *\n * A context provider that manages page-level permissions across the entire application.\n * This component ensures that all pages are properly protected and provides centralized\n * page permission management.\n *\n * Features:\n * - App-wide page permission management\n * - Strict mode to prevent bypassing\n * - Automatic audit logging\n * - Integration with existing RBAC system\n * - Page permission tracking\n * - Error handling and recovery\n *\n * @example\n * ```tsx\n * // Basic app setup with page permissions\n * <PagePermissionProvider strictMode={true} auditLog={true}>\n * <App />\n * </PagePermissionProvider>\n * \n * // With custom configuration\n * <PagePermissionProvider\n * strictMode={true}\n * auditLog={true}\n * onPageAccess={(pageName, operation, allowed) => {\n * console.log(`Page access: ${pageName} ${operation} - ${allowed ? 'allowed' : 'denied'}`);\n * }}\n * >\n * <App />\n * </PagePermissionProvider>\n * ```\n *\n * @security\n * - Enforces page-level permissions across the app\n * - Prevents apps from bypassing permission checks\n * - Automatic audit logging for all page access attempts\n * - Integration with existing RBAC system\n * - Page permission tracking and monitoring\n *\n * @performance\n * - Optimized with useMemo and useCallback\n * - Efficient context updates\n * - Minimal re-renders\n * - Cached permission checks\n *\n * @dependencies\n * - React 18+ - Context and hooks\n * - useUnifiedAuth - Authentication context\n * - RBAC types - Type definitions\n */\n\nimport React, { createContext, useContext, useState, useCallback, useMemo, useEffect } from 'react';\nimport { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';\nimport { UUID, Scope, Permission } from '../types';\n\nexport interface PagePermissionContextType {\n /** Check if user has permission for a page */\n hasPagePermission: (pageName: string, operation: string, pageId?: string, scope?: Scope) => boolean;\n \n /** Get all page permissions for current user */\n getPagePermissions: () => Record<string, string[]>;\n \n /** Check if page permission checking is enabled */\n isEnabled: boolean;\n \n /** Check if strict mode is enabled */\n isStrictMode: boolean;\n \n /** Check if audit logging is enabled */\n isAuditLogEnabled: boolean;\n \n /** Get page access history */\n getPageAccessHistory: () => PageAccessRecord[];\n \n /** Clear page access history */\n clearPageAccessHistory: () => void;\n}\n\nexport interface PageAccessRecord {\n pageName: string;\n operation: string;\n userId: UUID;\n scope: Scope;\n allowed: boolean;\n timestamp: string;\n pageId?: string;\n}\n\nexport interface PagePermissionProviderProps {\n /** Child components */\n children: React.ReactNode;\n \n /** Enable strict mode to prevent bypassing (default: true) */\n strictMode?: boolean;\n \n /** Enable audit logging (default: true) */\n auditLog?: boolean;\n \n /** Callback when page access is attempted */\n onPageAccess?: (pageName: string, operation: string, allowed: boolean, record: PageAccessRecord) => void;\n \n /** Callback when strict mode violation occurs */\n onStrictModeViolation?: (pageName: string, operation: string, record: PageAccessRecord) => void;\n \n /** Maximum number of access records to keep in history */\n maxHistorySize?: number;\n}\n\nconst PagePermissionContext = createContext<PagePermissionContextType | null>(null);\n\n/**\n * PagePermissionProvider - Manages page-level permissions across the app\n * \n * This provider ensures that all pages are properly protected and provides\n * centralized page permission management with strict enforcement.\n * \n * @param props - Provider props\n * @returns React element with page permission context\n */\nexport function PagePermissionProvider({\n children,\n strictMode = true,\n auditLog = true,\n onPageAccess,\n onStrictModeViolation,\n maxHistorySize = 1000\n}: PagePermissionProviderProps) {\n const { user, selectedOrganisation, selectedEvent } = useUnifiedAuth();\n const [pageAccessHistory, setPageAccessHistory] = useState<PageAccessRecord[]>([]);\n const [isEnabled, setIsEnabled] = useState(true);\n\n // Get current scope\n const currentScope = useMemo((): Scope | null => {\n if (!selectedOrganisation) return null;\n \n return {\n organisationId: selectedOrganisation.id,\n eventId: selectedEvent?.event_id || undefined,\n appId: undefined\n };\n }, [selectedOrganisation, selectedEvent]);\n\n // Check if user has permission for a page\n const hasPagePermission = useCallback((\n pageName: string, \n operation: string, \n pageId?: string, \n scope?: Scope\n ): boolean => {\n if (!isEnabled) return true;\n if (!user?.id) return false;\n \n const effectiveScope = scope || currentScope;\n if (!effectiveScope) return false;\n \n // Use the existing RBAC system to check permissions\n // This is a synchronous check for the context - actual permission checking\n // happens in the PagePermissionGuard component using useCan hook\n const permission = `${operation}:page.${pageName}` as Permission;\n \n // Return false by default (secure by default) - let individual PagePermissionGuard\n // components handle the actual permission checking asynchronously\n // This context is mainly for tracking and audit purposes\n return false;\n }, [isEnabled, user?.id, currentScope]);\n\n // Get all page permissions for current user\n const getPagePermissions = useCallback((): Record<string, string[]> => {\n if (!isEnabled || !user?.id) return {};\n \n // For now, return empty object - this will be enhanced with actual permission checking\n // when we integrate with the existing RBAC system\n return {};\n }, [isEnabled, user?.id]);\n\n // Get page access history\n const getPageAccessHistory = useCallback((): PageAccessRecord[] => {\n return [...pageAccessHistory];\n }, [pageAccessHistory]);\n\n // Clear page access history\n const clearPageAccessHistory = useCallback(() => {\n setPageAccessHistory([]);\n }, []);\n\n // Record page access attempt\n const recordPageAccess = useCallback((\n pageName: string,\n operation: string,\n allowed: boolean,\n pageId?: string,\n scope?: Scope\n ) => {\n if (!auditLog || !user?.id) return;\n \n const record: PageAccessRecord = {\n pageName,\n operation,\n userId: user.id,\n scope: scope || currentScope || { organisationId: '' },\n allowed,\n timestamp: new Date().toISOString(),\n pageId\n };\n \n setPageAccessHistory(prev => {\n const newHistory = [record, ...prev];\n return newHistory.slice(0, maxHistorySize);\n });\n \n if (onPageAccess) {\n onPageAccess(pageName, operation, allowed, record);\n }\n \n if (strictMode && !allowed && onStrictModeViolation) {\n onStrictModeViolation(pageName, operation, record);\n }\n }, [auditLog, user?.id, currentScope, maxHistorySize, onPageAccess, onStrictModeViolation, strictMode]);\n\n // Context value\n const contextValue = useMemo((): PagePermissionContextType => ({\n hasPagePermission,\n getPagePermissions,\n isEnabled,\n isStrictMode: strictMode,\n isAuditLogEnabled: auditLog,\n getPageAccessHistory,\n clearPageAccessHistory\n }), [\n hasPagePermission,\n getPagePermissions,\n isEnabled,\n strictMode,\n auditLog,\n getPageAccessHistory,\n clearPageAccessHistory\n ]);\n\n // Log strict mode violations\n useEffect(() => {\n if (strictMode && auditLog) {\n console.log(`[PagePermissionProvider] Strict mode enabled - all page access attempts will be logged and enforced`);\n }\n }, [strictMode, auditLog]);\n\n return (\n <PagePermissionContext.Provider value={contextValue}>\n {children}\n </PagePermissionContext.Provider>\n );\n}\n\n/**\n * Hook to use page permission context\n * \n * @returns Page permission context\n * @throws Error if used outside of PagePermissionProvider\n */\nexport function usePagePermissions(): PagePermissionContextType {\n const context = useContext(PagePermissionContext);\n \n if (!context) {\n throw new Error('usePagePermissions must be used within a PagePermissionProvider');\n }\n \n return context;\n}\n\nexport default PagePermissionProvider;\n","/**\n * @file Page Permission Guard Component\n * @package @jmruthers/pace-core\n * @module RBAC/Components/PagePermissionGuard\n * @since 2.0.0\n *\n * A component that enforces page-level permissions and prevents apps from bypassing\n * permission checks. This is a critical security component that ensures all pages\n * are properly protected.\n *\n * Features:\n * - Page-level permission enforcement\n * - Strict mode to prevent bypassing\n * - Automatic audit logging\n * - Integration with existing RBAC system\n * - Clear error messages for unauthorized access\n * - TypeScript support with strict typing\n *\n * @example\n * ```tsx\n * // Basic page protection\n * <PagePermissionGuard\n * pageName=\"dashboard\"\n * operation=\"read\"\n * fallback={<AccessDeniedPage />}\n * >\n * <DashboardPage />\n * </PagePermissionGuard>\n * \n * // Strict mode (prevents bypassing)\n * <PagePermissionGuard\n * pageName=\"admin\"\n * operation=\"read\"\n * strictMode={true}\n * fallback={<AccessDeniedPage />}\n * >\n * <AdminPage />\n * </PagePermissionGuard>\n * \n * // With custom fallback\n * <PagePermissionGuard\n * pageName=\"settings\"\n * operation=\"update\"\n * fallback={<div>You don't have permission to access settings</div>}\n * >\n * <SettingsPage />\n * </PagePermissionGuard>\n * ```\n *\n * @security\n * - Enforces page-level permissions\n * - Prevents apps from bypassing permission checks\n * - Automatic audit logging for all page access attempts\n * - Integration with existing RBAC system\n * - Clear error messages for unauthorized access\n *\n * @performance\n * - Optimized with useMemo and useCallback\n * - Cached permission checks\n * - Minimal re-renders\n * - Efficient error handling\n *\n * @dependencies\n * - React 18+ - Component framework\n * - useCan hook - Permission checking\n * - useUnifiedAuth - Authentication context\n * - RBAC types - Type definitions\n */\n\nimport React, { useMemo, useCallback, useEffect, useState, useRef } from 'react';\nimport { useCan } from '../hooks';\nimport { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';\nimport { UUID, Permission, Scope } from '../types';\nimport { createScopeFromEvent } from '../utils/eventContext';\nimport { getCurrentAppName } from '../../utils/appNameResolver';\n\nexport interface PagePermissionGuardProps {\n /** Name of the page being protected */\n pageName: string;\n \n /** Operation being performed on the page */\n operation: 'read' | 'create' | 'update' | 'delete';\n \n /** Content to render when user has permission */\n children: React.ReactNode;\n \n /** Content to render when user lacks permission */\n fallback?: React.ReactNode;\n \n /** Enable strict mode to prevent bypassing (default: true) */\n strictMode?: boolean;\n \n /** Force audit logging for this page access (default: true) */\n auditLog?: boolean;\n \n /** Custom page ID for permission checking */\n pageId?: string;\n \n /** Custom scope for permission checking */\n scope?: Scope;\n \n /** Callback when access is denied */\n onDenied?: (pageName: string, operation: string) => void;\n \n /** Loading state content */\n loading?: React.ReactNode;\n}\n\n/**\n * PagePermissionGuard - Enforces page-level permissions\n * \n * This component ensures that users can only access pages they have permission for.\n * It integrates with the existing RBAC system and provides strict enforcement to\n * prevent apps from bypassing permission checks.\n * \n * @param props - Component props\n * @returns React element with permission enforcement\n */\nconst PagePermissionGuardComponent = ({\n pageName,\n operation,\n children,\n fallback = <DefaultAccessDenied />,\n strictMode = true,\n auditLog = true,\n pageId,\n scope,\n onDenied,\n loading = <DefaultLoading />\n}: PagePermissionGuardProps) => {\n // Generate a unique instance ID for debugging\n const instanceId = useMemo(() => Math.random().toString(36).substr(2, 9), []);\n \n // Track render count for debugging\n const renderCountRef = useRef(0);\n renderCountRef.current += 1;\n \n \n \n const { user, selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();\n \n const [hasChecked, setHasChecked] = useState(false);\n const [checkError, setCheckError] = useState<Error | null>(null);\n const [resolvedScope, setResolvedScope] = useState<Scope | null>(null);\n const scopeResolutionAbortRef = useRef<AbortController | null>(null);\n \n // Use ref to avoid infinite re-renders from supabase dependency\n const supabaseRef = useRef(supabase);\n supabaseRef.current = supabase;\n \n // Resolve scope - either use provided scope or resolve from context\n useEffect(() => {\n const abortController = new AbortController();\n scopeResolutionAbortRef.current?.abort();\n scopeResolutionAbortRef.current = abortController;\n const { signal } = abortController;\n\n const safeSetResolvedScope = (value: Scope | null) => {\n if (!signal.aborted) {\n setResolvedScope(value);\n }\n };\n\n const safeSetCheckError = (value: Error | null) => {\n if (!signal.aborted) {\n setCheckError(value);\n }\n };\n\n const resolveScope = async () => {\n if (signal.aborted) {\n return;\n }\n\n if (scope) {\n safeSetResolvedScope(scope);\n safeSetCheckError(null);\n return;\n }\n\n // Get app ID from package.json or environment\n let appId: string | undefined = undefined;\n\n // Try to resolve from database\n if (supabaseRef.current) {\n const appName = getCurrentAppName();\n if (appName) {\n try {\n const { data: app, error } = await supabaseRef.current\n .from('rbac_apps')\n .select('id, name, is_active')\n .eq('name', appName)\n .eq('is_active', true)\n .single() as { data: { id: string; name: string; is_active: boolean } | null; error: any };\n\n if (signal.aborted) {\n return;\n }\n\n if (error) {\n console.error('[PagePermissionGuard] Database error resolving app ID:', error);\n if (signal.aborted) {\n return;\n }\n const { data: inactiveApp } = await supabaseRef.current\n .from('rbac_apps')\n .select('id, name, is_active')\n .eq('name', appName)\n .single() as { data: { id: string; name: string; is_active: boolean } | null };\n\n if (signal.aborted) {\n return;\n }\n\n if (inactiveApp) {\n console.error(`[PagePermissionGuard] App \"${appName}\" exists but is inactive (is_active: ${inactiveApp.is_active})`);\n } else {\n console.error(`[PagePermissionGuard] App \"${appName}\" not found in rbac_apps table`);\n }\n } else if (app) {\n appId = app.id;\n } else {\n console.error('[PagePermissionGuard] No app data returned for:', appName);\n }\n } catch (error) {\n if (signal.aborted) {\n return;\n }\n console.error('[PagePermissionGuard] Unexpected error resolving app ID:', error);\n }\n } else {\n console.error('[PagePermissionGuard] No app name found. Make sure to call setRBACAppName() in your app setup.');\n }\n }\n\n if (signal.aborted) {\n return;\n }\n\n // If we have both organisation and event, use them directly\n if (selectedOrganisation && selectedEvent) {\n if (!appId) {\n if (import.meta.env.MODE === 'test') {\n console.warn('[PagePermissionGuard] App ID not resolved in test environment, proceeding without it');\n } else {\n console.error('[PagePermissionGuard] CRITICAL: App ID not resolved. Check console for details.');\n safeSetCheckError(new Error('App ID not resolved. Check console for database errors.'));\n safeSetResolvedScope(null);\n return;\n }\n }\n\n if (import.meta.env.MODE === 'production' && appId) {\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(appId)) {\n console.error('[PagePermissionGuard] CRITICAL: App ID is not a valid UUID:', appId);\n safeSetCheckError(new Error(`Invalid app ID format: ${appId}. Expected UUID.`));\n safeSetResolvedScope(null);\n return;\n }\n }\n const resolvedContext = {\n organisationId: selectedOrganisation.id,\n eventId: selectedEvent.event_id,\n appId: appId\n };\n safeSetResolvedScope(resolvedContext);\n safeSetCheckError(null);\n return;\n }\n\n if (signal.aborted) {\n return;\n }\n\n // If we only have organisation, use it\n if (selectedOrganisation) {\n if (!appId) {\n if (import.meta.env.MODE === 'test') {\n console.warn('[PagePermissionGuard] App ID not resolved in test environment, proceeding without it');\n } else {\n console.error('[PagePermissionGuard] CRITICAL: App ID not resolved. Check console for details.');\n safeSetCheckError(new Error('App ID not resolved. Check console for database errors.'));\n safeSetResolvedScope(null);\n return;\n }\n }\n\n if (import.meta.env.MODE === 'production' && appId) {\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(appId)) {\n console.error('[PagePermissionGuard] CRITICAL: App ID is not a valid UUID:', appId);\n safeSetCheckError(new Error(`Invalid app ID format: ${appId}. Expected UUID.`));\n safeSetResolvedScope(null);\n return;\n }\n }\n const resolvedContext = {\n organisationId: selectedOrganisation.id,\n eventId: selectedEvent?.event_id || undefined,\n appId: appId\n };\n safeSetResolvedScope(resolvedContext);\n safeSetCheckError(null);\n return;\n }\n\n if (signal.aborted) {\n return;\n }\n\n // If we only have event, resolve organisation from event\n if (selectedEvent && supabaseRef.current) {\n try {\n const eventScope = await createScopeFromEvent(supabaseRef.current, selectedEvent.event_id);\n\n if (signal.aborted) {\n return;\n }\n\n if (!eventScope) {\n safeSetCheckError(new Error('Could not resolve organization from event context'));\n safeSetResolvedScope(null);\n return;\n }\n safeSetResolvedScope({\n ...eventScope,\n appId: appId || eventScope.appId\n });\n safeSetCheckError(null);\n } catch (error) {\n if (signal.aborted) {\n return;\n }\n safeSetCheckError(error as Error);\n safeSetResolvedScope(null);\n }\n return;\n }\n\n if (signal.aborted) {\n return;\n }\n\n const errorMessage = !selectedOrganisation && !selectedEvent\n ? 'Either organisation context or event context is required for page permission checking'\n : 'Insufficient context for permission checking. Please ensure you are properly authenticated and have selected an organisation or event.';\n\n console.error('[PagePermissionGuard] Context resolution failed:', {\n selectedOrganisation: selectedOrganisation ? (selectedOrganisation as any).id : null,\n selectedEvent: selectedEvent ? (selectedEvent as any).event_id : null,\n appId,\n error: errorMessage\n });\n\n safeSetCheckError(new Error(errorMessage));\n safeSetResolvedScope(null);\n };\n\n resolveScope();\n\n return () => {\n abortController.abort();\n if (scopeResolutionAbortRef.current === abortController) {\n scopeResolutionAbortRef.current = null;\n }\n };\n }, [scope, selectedOrganisation, selectedEvent]);\n\n // Determine the page ID for permission checking\n const effectivePageId = useMemo((): string => {\n return pageId || pageName;\n }, [pageId, pageName]);\n\n // Build the permission string\n const permission = useMemo((): Permission => {\n return `${operation}:page.${pageName}` as Permission;\n }, [operation, pageName]);\n\n // Create a stable scope that only includes valid values\n // OrganisationId is required - use undefined if not available, useCan will handle loading state\n const stableScope = useMemo(() => {\n if (resolvedScope && resolvedScope.organisationId) {\n return {\n organisationId: resolvedScope.organisationId,\n appId: resolvedScope.appId || undefined,\n eventId: resolvedScope.eventId || undefined\n };\n }\n // Return scope without organisationId - useCan will keep loading state until resolved\n // Scope.organisationId is optional, so undefined is valid\n return { organisationId: undefined, appId: undefined, eventId: undefined };\n }, [resolvedScope]);\n\n // Check if user has permission - only call useCan when we have a resolved scope with valid organisationId\n // If resolvedScope is null or has no organisationId, useCan will keep isLoading=true\n const { can, isLoading: canIsLoading, error: canError } = useCan(\n user?.id || '',\n stableScope,\n permission,\n effectivePageId,\n true // Use cache\n );\n \n \n // Combine loading states - we're loading if either scope is resolving OR permission check is loading\n const isLoading = !resolvedScope || canIsLoading;\n const error = checkError || canError;\n\n // Handle permission check completion\n useEffect(() => {\n if (!isLoading && !error) {\n setHasChecked(true);\n setCheckError(null); // Clear any previous errors when permission check succeeds\n \n if (!can && onDenied) {\n onDenied(pageName, operation);\n }\n } else if (error) {\n setCheckError(error);\n setHasChecked(true);\n }\n }, [can, isLoading, error, pageName, operation, onDenied]);\n\n // Log page access attempt for audit\n useEffect(() => {\n if (auditLog && hasChecked && !isLoading) {\n console.log(`[PagePermissionGuard] Page access attempt:`, {\n pageName,\n operation,\n userId: user?.id,\n scope: resolvedScope,\n allowed: can,\n timestamp: new Date().toISOString()\n });\n }\n }, [auditLog, hasChecked, isLoading, pageName, operation, user?.id, resolvedScope, can]);\n\n\n // Handle strict mode violations\n useEffect(() => {\n if (strictMode && hasChecked && !isLoading && !can) {\n console.error(`[PagePermissionGuard] STRICT MODE VIOLATION: User attempted to access protected page without permission`, {\n pageName,\n operation,\n permission: `${operation}:page.${pageName}`,\n pageId: effectivePageId,\n userId: user?.id,\n scope: resolvedScope,\n scopeValid: resolvedScope && resolvedScope.organisationId ? true : false,\n checkError,\n canError,\n timestamp: new Date().toISOString()\n });\n }\n }, [strictMode, hasChecked, isLoading, can, pageName, operation, effectivePageId, user?.id, resolvedScope, checkError, canError]);\n\n // Calculate the actual render state - FIXED: Proper state calculation\n // Add defensive checks to ensure we have valid state\n const hasValidScope = resolvedScope && resolvedScope.organisationId;\n const hasValidUser = user && user.id;\n const isPermissionCheckComplete = hasChecked && !isLoading;\n \n const shouldShowAccessDenied = isPermissionCheckComplete && hasValidScope && hasValidUser && !checkError && !can;\n const shouldShowContent = isPermissionCheckComplete && hasValidScope && hasValidUser && !checkError && can;\n\n // Create a key to force re-render when scope or permission state changes\n const scopeKey = resolvedScope ? `${resolvedScope.organisationId}-${resolvedScope.eventId}-${resolvedScope.appId}` : 'no-scope';\n const permissionKey = `${scopeKey}-${can}-${isLoading}-${!!checkError}-${hasChecked}`;\n \n \n\n // Show loading state - if we're still loading or don't have valid state\n if (isLoading || !hasValidScope || !hasValidUser || !hasChecked) {\n return loading || <div>Checking permissions...</div>;\n }\n\n // Show error state - only if we have an error AND no permission\n if (checkError && !can) {\n return fallback;\n }\n\n // Show access denied - if permission check is complete and user doesn't have permission\n if (shouldShowAccessDenied) {\n return fallback;\n }\n\n // Show protected content - if permission check is complete and user has permission\n if (shouldShowContent) {\n return <>{children}</>;\n }\n\n // Fallback: This should never happen, but just in case\n return fallback;\n}\n\n/**\n * Default access denied component\n */\nfunction DefaultAccessDenied() {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-[200px] p-8 text-center\">\n <div className=\"mb-4\">\n <svg className=\"w-16 h-16 text-acc-500 mx-auto\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z\" />\n </svg>\n </div>\n <h2 className=\"text-xl font-semibold text-sec-900 mb-2\">Access Denied</h2>\n <p className=\"text-sec-600 mb-4\">You don't have permission to access this page.</p>\n <button \n onClick={() => window.history.back()}\n className=\"px-4 py-2 bg-main-600 text-main-50 rounded-md hover:bg-main-700 transition-colors\"\n >\n Go Back\n </button>\n </div>\n );\n}\n\n/**\n * Default loading component\n */\nfunction DefaultLoading() {\n return (\n <div className=\"flex items-center justify-center min-h-[200px] p-8\">\n <div className=\"flex items-center space-x-2\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-main-600\"></div>\n <span className=\"text-sec-600\">Checking permissions...</span>\n </div>\n </div>\n );\n};\n\nexport const PagePermissionGuard = PagePermissionGuardComponent;\nexport default PagePermissionGuard;\n","/**\n * @file Secure Data Provider Component\n * @package @jmruthers/pace-core\n * @module RBAC/Components/SecureDataProvider\n * @since 2.0.0\n *\n * A context provider that prevents apps from accessing Supabase directly and ensures\n * all data access goes through the secure RBAC system. This is a critical security\n * component that enforces data access control.\n *\n * Features:\n * - Prevents direct Supabase client access\n * - Enforces secure data access patterns\n * - Automatic organisation context injection\n * - RLS policy enforcement\n * - Audit logging for all data access\n * - Integration with existing RBAC system\n *\n * @example\n * ```tsx\n * // Basic app setup with secure data access\n * <SecureDataProvider strictMode={true} auditLog={true}>\n * <App />\n * </SecureDataProvider>\n * \n * // With custom configuration\n * <SecureDataProvider\n * strictMode={true}\n * auditLog={true}\n * onDataAccess={(table, operation, allowed) => {\n * console.log(`Data access: ${table} ${operation} - ${allowed ? 'allowed' : 'denied'}`);\n * }}\n * >\n * <App />\n * </SecureDataProvider>\n * ```\n *\n * @security\n * - Prevents direct Supabase client access\n * - Enforces secure data access patterns\n * - Automatic organisation context injection\n * - RLS policy enforcement\n * - Audit logging for all data access\n * - Integration with existing RBAC system\n *\n * @performance\n * - Optimized with useMemo and useCallback\n * - Efficient context updates\n * - Minimal re-renders\n * - Cached permission checks\n *\n * @dependencies\n * - React 18+ - Context and hooks\n * - useUnifiedAuth - Authentication context\n * - useSecureDataAccess - Secure data access hook\n * - RBAC types - Type definitions\n */\n\nimport React, { createContext, useContext, useState, useCallback, useMemo, useEffect } from 'react';\nimport { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';\nimport { useSecureDataAccess } from '../../hooks/useSecureDataAccess';\nimport { UUID, Scope, Permission } from '../types';\n\nexport interface DataAccessRecord {\n table: string;\n operation: string;\n userId: UUID;\n scope: Scope;\n allowed: boolean;\n timestamp: string;\n query?: string;\n filters?: Record<string, any>;\n}\n\nexport interface SecureDataContextType {\n /** Check if data access is allowed for a table and operation */\n isDataAccessAllowed: (table: string, operation: string, scope?: Scope) => boolean;\n \n /** Get all data access permissions for current user */\n getDataAccessPermissions: () => Record<string, string[]>;\n \n /** Check if secure data access is enabled */\n isEnabled: boolean;\n \n /** Check if strict mode is enabled */\n isStrictMode: boolean;\n \n /** Check if audit logging is enabled */\n isAuditLogEnabled: boolean;\n \n /** Get data access history */\n getDataAccessHistory: () => DataAccessRecord[];\n \n /** Clear data access history */\n clearDataAccessHistory: () => void;\n \n /** Validate data access attempt */\n validateDataAccess: (table: string, operation: string, scope?: Scope) => boolean;\n}\n\nexport interface SecureDataProviderProps {\n /** Child components */\n children: React.ReactNode;\n \n /** Enable strict mode to prevent bypassing (default: true) */\n strictMode?: boolean;\n \n /** Enable audit logging (default: true) */\n auditLog?: boolean;\n \n /** Callback when data access is attempted */\n onDataAccess?: (table: string, operation: string, allowed: boolean, record: DataAccessRecord) => void;\n \n /** Callback when strict mode violation occurs */\n onStrictModeViolation?: (table: string, operation: string, record: DataAccessRecord) => void;\n \n /** Maximum number of access records to keep in history */\n maxHistorySize?: number;\n \n /** Enable RLS enforcement (default: true) */\n enforceRLS?: boolean;\n}\n\nconst SecureDataContext = createContext<SecureDataContextType | null>(null);\n\n/**\n * SecureDataProvider - Prevents direct Supabase access and enforces secure data patterns\n * \n * This provider ensures that all data access goes through the secure RBAC system\n * and prevents apps from bypassing data access controls.\n * \n * @param props - Provider props\n * @returns React element with secure data context\n */\nexport function SecureDataProvider({\n children,\n strictMode = true,\n auditLog = true,\n onDataAccess,\n onStrictModeViolation,\n maxHistorySize = 1000,\n enforceRLS = true\n}: SecureDataProviderProps) {\n const { user, selectedOrganisation, selectedEvent } = useUnifiedAuth();\n const { validateContext } = useSecureDataAccess();\n const [dataAccessHistory, setDataAccessHistory] = useState<DataAccessRecord[]>([]);\n const [isEnabled, setIsEnabled] = useState(true);\n\n // Get current scope\n const currentScope = useMemo((): Scope | null => {\n if (!selectedOrganisation) return null;\n \n return {\n organisationId: selectedOrganisation.id,\n eventId: selectedEvent?.event_id || undefined,\n appId: undefined\n };\n }, [selectedOrganisation, selectedEvent]);\n\n // Check if data access is allowed for a table and operation\n const isDataAccessAllowed = useCallback((\n table: string, \n operation: string, \n scope?: Scope\n ): boolean => {\n if (!isEnabled) return true;\n if (!user?.id) return false;\n \n const effectiveScope = scope || currentScope;\n if (!effectiveScope) return false;\n \n // Use the existing RBAC system to check data access permissions\n // This is a synchronous check for the context - actual permission checking\n // happens in the useSecureDataAccess hook using the RBAC engine\n const permission = `${operation}:data.${table}` as Permission;\n \n // For now, we'll return true and let the useSecureDataAccess hook\n // handle the actual permission checking asynchronously\n // This context is mainly for tracking and audit purposes\n return true;\n }, [isEnabled, user?.id, currentScope]);\n\n // Get all data access permissions for current user\n const getDataAccessPermissions = useCallback((): Record<string, string[]> => {\n if (!isEnabled || !user?.id) return {};\n \n // For now, return empty object - this will be enhanced with actual permission checking\n // when we integrate with the existing RBAC system\n return {};\n }, [isEnabled, user?.id]);\n\n // Get data access history\n const getDataAccessHistory = useCallback((): DataAccessRecord[] => {\n return [...dataAccessHistory];\n }, [dataAccessHistory]);\n\n // Clear data access history\n const clearDataAccessHistory = useCallback(() => {\n setDataAccessHistory([]);\n }, []);\n\n // Validate data access attempt\n const validateDataAccess = useCallback((\n table: string,\n operation: string,\n scope?: Scope\n ): boolean => {\n if (!isEnabled) return true;\n if (!user?.id) return false;\n \n const effectiveScope = scope || currentScope;\n if (!effectiveScope) return false;\n \n // Validate organisation context\n try {\n validateContext();\n } catch (error) {\n console.error(`[SecureDataProvider] Organisation context validation failed:`, error);\n return false;\n }\n \n return isDataAccessAllowed(table, operation, effectiveScope);\n }, [isEnabled, user?.id, currentScope, validateContext, isDataAccessAllowed]);\n\n // Record data access attempt\n const recordDataAccess = useCallback((\n table: string,\n operation: string,\n allowed: boolean,\n query?: string,\n filters?: Record<string, any>,\n scope?: Scope\n ) => {\n if (!auditLog || !user?.id) return;\n \n const record: DataAccessRecord = {\n table,\n operation,\n userId: user.id,\n scope: scope || currentScope || { organisationId: '' },\n allowed,\n timestamp: new Date().toISOString(),\n query,\n filters\n };\n \n setDataAccessHistory(prev => {\n const newHistory = [record, ...prev];\n return newHistory.slice(0, maxHistorySize);\n });\n \n if (onDataAccess) {\n onDataAccess(table, operation, allowed, record);\n }\n \n if (strictMode && !allowed && onStrictModeViolation) {\n onStrictModeViolation(table, operation, record);\n }\n }, [auditLog, user?.id, currentScope, maxHistorySize, onDataAccess, onStrictModeViolation, strictMode]);\n\n // Context value\n const contextValue = useMemo((): SecureDataContextType => ({\n isDataAccessAllowed,\n getDataAccessPermissions,\n isEnabled,\n isStrictMode: strictMode,\n isAuditLogEnabled: auditLog,\n getDataAccessHistory,\n clearDataAccessHistory,\n validateDataAccess\n }), [\n isDataAccessAllowed,\n getDataAccessPermissions,\n isEnabled,\n strictMode,\n auditLog,\n getDataAccessHistory,\n clearDataAccessHistory,\n validateDataAccess\n ]);\n\n // Log strict mode violations\n useEffect(() => {\n if (strictMode && auditLog) {\n console.log(`[SecureDataProvider] Strict mode enabled - all data access attempts will be logged and enforced`);\n }\n }, [strictMode, auditLog]);\n\n // Log RLS enforcement\n useEffect(() => {\n if (enforceRLS && auditLog) {\n console.log(`[SecureDataProvider] RLS enforcement enabled - all queries will include organisation context`);\n }\n }, [enforceRLS, auditLog]);\n\n return (\n <SecureDataContext.Provider value={contextValue}>\n {children}\n </SecureDataContext.Provider>\n );\n}\n\n/**\n * Hook to use secure data context\n * \n * @returns Secure data context\n * @throws Error if used outside of SecureDataProvider\n */\nexport function useSecureData(): SecureDataContextType {\n const context = useContext(SecureDataContext);\n \n if (!context) {\n throw new Error('useSecureData must be used within a SecureDataProvider');\n }\n \n return context;\n}\n\nexport default SecureDataProvider;\n","/**\n * @file Permission Enforcer Component\n * @package @jmruthers/pace-core\n * @module RBAC/Components/PermissionEnforcer\n * @since 2.0.0\n *\n * A component that enforces permissions and prevents apps from bypassing permission checks.\n * This is a critical security component that provides centralized permission enforcement.\n *\n * Features:\n * - Centralized permission enforcement\n * - Strict mode to prevent bypassing\n * - Automatic audit logging\n * - Integration with existing RBAC system\n * - Multiple permission checking\n * - Clear error messages for unauthorized access\n *\n * @example\n * ```tsx\n * // Basic permission enforcement\n * <PermissionEnforcer\n * permissions={['read:events', 'update:events']}\n * operation=\"event-management\"\n * fallback={<AccessDeniedPage />}\n * >\n * <EventManagementPage />\n * </PermissionEnforcer>\n * \n * // Strict mode (prevents bypassing)\n * <PermissionEnforcer\n * permissions={['admin:system']}\n * operation=\"system-administration\"\n * strictMode={true}\n * fallback={<AccessDeniedPage />}\n * >\n * <SystemAdminPage />\n * </PermissionEnforcer>\n * \n * // With custom fallback\n * <PermissionEnforcer\n * permissions={['update:settings']}\n * operation=\"settings-update\"\n * fallback={<div>You don't have permission to update settings</div>}\n * >\n * <SettingsUpdatePage />\n * </PermissionEnforcer>\n * ```\n *\n * @security\n * - Enforces permissions for all operations\n * - Prevents apps from bypassing permission checks\n * - Automatic audit logging for all permission checks\n * - Integration with existing RBAC system\n * - Clear error messages for unauthorized access\n *\n * @performance\n * - Optimized with useMemo and useCallback\n * - Cached permission checks\n * - Minimal re-renders\n * - Efficient error handling\n *\n * @dependencies\n * - React 18+ - Component framework\n * - useCan hook - Permission checking\n * - useUnifiedAuth - Authentication context\n * - RBAC types - Type definitions\n */\n\nimport React, { useMemo, useCallback, useEffect, useState } from 'react';\nimport { useMultiplePermissions } from '../hooks/usePermissions';\nimport { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';\nimport { UUID, Permission, Scope } from '../types';\nimport { createScopeFromEvent } from '../utils/eventContext';\n\nexport interface PermissionEnforcerProps {\n /** Permissions required for access */\n permissions: Permission[];\n \n /** Operation being performed */\n operation: string;\n \n /** Content to render when user has permission */\n children: React.ReactNode;\n \n /** Content to render when user lacks permission */\n fallback?: React.ReactNode;\n \n /** Enable strict mode to prevent bypassing (default: true) */\n strictMode?: boolean;\n \n /** Force audit logging for this operation (default: true) */\n auditLog?: boolean;\n \n /** Custom scope for permission checking */\n scope?: Scope;\n \n /** Callback when access is denied */\n onDenied?: (permissions: Permission[], operation: string) => void;\n \n /** Loading state content */\n loading?: React.ReactNode;\n \n /** Require all permissions (AND) or any permission (OR) */\n requireAll?: boolean;\n}\n\n/**\n * PermissionEnforcer - Enforces permissions for operations\n * \n * This component ensures that users can only perform operations they have permission for.\n * It integrates with the existing RBAC system and provides strict enforcement to\n * prevent apps from bypassing permission checks.\n * \n * @param props - Component props\n * @returns React element with permission enforcement\n */\nexport function PermissionEnforcer({\n permissions,\n operation,\n children,\n fallback = <DefaultAccessDenied />,\n strictMode = true,\n auditLog = true,\n scope,\n onDenied,\n loading = <DefaultLoading />,\n requireAll = true\n}: PermissionEnforcerProps) {\n const { user, selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();\n const [hasChecked, setHasChecked] = useState(false);\n const [checkError, setCheckError] = useState<Error | null>(null);\n const [resolvedScope, setResolvedScope] = useState<Scope | null>(null);\n\n // Resolve scope - either use provided scope or resolve from context\n useEffect(() => {\n const resolveScope = async () => {\n if (scope) {\n setResolvedScope(scope);\n return;\n }\n\n // If we have both organisation and event, use them directly\n if (selectedOrganisation && selectedEvent) {\n setResolvedScope({\n organisationId: selectedOrganisation.id,\n eventId: selectedEvent.event_id,\n appId: undefined\n });\n return;\n }\n\n // If we only have organisation, use it\n if (selectedOrganisation) {\n setResolvedScope({\n organisationId: selectedOrganisation.id,\n eventId: selectedEvent?.event_id || undefined,\n appId: undefined\n });\n return;\n }\n\n // If we only have event, resolve organisation from event\n if (selectedEvent && supabase) {\n try {\n const eventScope = await createScopeFromEvent(supabase, selectedEvent.event_id);\n if (!eventScope) {\n setCheckError(new Error('Could not resolve organization from event context'));\n return;\n }\n setResolvedScope(eventScope);\n } catch (error) {\n setCheckError(error as Error);\n }\n return;\n }\n\n // No context available\n setCheckError(new Error('Either organisation context or event context is required for permission checking'));\n };\n\n resolveScope();\n }, [scope, selectedOrganisation, selectedEvent, supabase]);\n\n // Check all permissions using useMultiplePermissions hook\n const { results: permissionResults, isLoading, error } = useMultiplePermissions(\n user?.id || '',\n resolvedScope || { eventId: selectedEvent?.event_id || undefined },\n permissions,\n true // Use cache\n );\n\n // Determine if user has required permissions based on requireAll prop\n const hasRequiredPermissions = useMemo((): boolean => {\n if (permissions.length === 0) return true;\n \n // If permissionResults is not yet available or empty, deny access\n if (!permissionResults || Object.keys(permissionResults).length === 0) {\n return false;\n }\n \n if (requireAll) {\n // User must have ALL permissions\n return Object.values(permissionResults).every(result => result === true);\n } else {\n // User must have ANY permission (default behavior)\n return Object.values(permissionResults).some(result => result === true);\n }\n }, [permissions, permissionResults, requireAll]);\n\n // Handle permission check completion\n useEffect(() => {\n if (!isLoading && !error) {\n setHasChecked(true);\n setCheckError(null);\n \n if (!hasRequiredPermissions && onDenied) {\n onDenied(permissions, operation);\n }\n } else if (error) {\n setCheckError(error);\n setHasChecked(true);\n }\n }, [hasRequiredPermissions, isLoading, error, permissions, operation, onDenied]);\n\n // Log permission check attempt for audit\n useEffect(() => {\n if (auditLog && hasChecked && !isLoading) {\n console.log(`[PermissionEnforcer] Permission check attempt:`, {\n permissions,\n operation,\n userId: user?.id,\n scope: resolvedScope,\n allowed: hasRequiredPermissions,\n requireAll,\n timestamp: new Date().toISOString()\n });\n }\n }, [auditLog, hasChecked, isLoading, permissions, operation, user?.id, resolvedScope, hasRequiredPermissions, requireAll]);\n\n // Handle strict mode violations\n useEffect(() => {\n if (strictMode && hasChecked && !isLoading && !hasRequiredPermissions) {\n console.error(`[PermissionEnforcer] STRICT MODE VIOLATION: User attempted to perform operation without permission`, {\n permissions,\n operation,\n userId: user?.id,\n scope: resolvedScope,\n requireAll,\n timestamp: new Date().toISOString()\n });\n }\n }, [strictMode, hasChecked, isLoading, hasRequiredPermissions, permissions, operation, user?.id, resolvedScope, requireAll]);\n\n // Show loading state\n if (isLoading || !hasChecked) {\n return <>{loading}</>;\n }\n\n // Show error state\n if (checkError) {\n console.error(`[PermissionEnforcer] Permission check failed for operation ${operation}:`, checkError);\n return <>{fallback}</>;\n }\n\n // Show access denied\n if (!hasRequiredPermissions) {\n return <>{fallback}</>;\n }\n\n // Show protected content\n return <>{children}</>;\n}\n\n/**\n * Default access denied component\n */\nfunction DefaultAccessDenied() {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-[200px] p-8 text-center\">\n <div className=\"mb-4\">\n <svg className=\"w-16 h-16 text-acc-500 mx-auto\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z\" />\n </svg>\n </div>\n <h2 className=\"text-xl font-semibold text-sec-900 mb-2\">Access Denied</h2>\n <p className=\"text-sec-600 mb-4\">You don't have permission to perform this operation.</p>\n <button \n onClick={() => window.history.back()}\n className=\"px-4 py-2 bg-main-600 text-main-50 rounded-md hover:bg-main-700 transition-colors\"\n >\n Go Back\n </button>\n </div>\n );\n}\n\n/**\n * Default loading component\n */\nfunction DefaultLoading() {\n return (\n <div className=\"flex items-center justify-center min-h-[200px] p-8\">\n <div className=\"flex items-center space-x-2\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-main-600\"></div>\n <span className=\"text-sec-600\">Checking permissions...</span>\n </div>\n </div>\n );\n}\n\nexport default PermissionEnforcer;\n","/**\n * @file Role Based Router Component\n * @package @jmruthers/pace-core\n * @module RBAC/Components/RoleBasedRouter\n * @since 2.0.0\n *\n * A component that provides centralized routing control and prevents apps from\n * implementing custom routing that bypasses permission checks. This is a critical\n * security component that ensures all routes are properly protected.\n *\n * Features:\n * - Centralized routing control\n * - Role-based route protection\n * - Permission-based route filtering\n * - Strict mode to prevent bypassing\n * - Automatic audit logging\n * - Integration with existing RBAC system\n * - Clear error messages for unauthorized routes\n *\n * @example\n * ```tsx\n * // Basic role-based routing\n * <RoleBasedRouter\n * routes={routeConfig}\n * fallbackRoute=\"/unauthorized\"\n * strictMode={true}\n * >\n * <App />\n * </RoleBasedRouter>\n * \n * // With custom configuration\n * <RoleBasedRouter\n * routes={routeConfig}\n * fallbackRoute=\"/unauthorized\"\n * strictMode={true}\n * auditLog={true}\n * onRouteAccess={(route, allowed) => {\n * console.log(`Route access: ${route} - ${allowed ? 'allowed' : 'denied'}`);\n * }}\n * >\n * <App />\n * </RoleBasedRouter>\n * ```\n *\n * @security\n * - Enforces route-level permissions\n * - Prevents apps from bypassing route protection\n * - Automatic audit logging for all route access attempts\n * - Integration with existing RBAC system\n * - Clear error messages for unauthorized routes\n *\n * @performance\n * - Optimized with useMemo and useCallback\n * - Cached permission checks\n * - Minimal re-renders\n * - Efficient route matching\n *\n * @dependencies\n * - React 18+ - Component framework\n * - React Router - Routing functionality\n * - useCan hook - Permission checking\n * - useUnifiedAuth - Authentication context\n * - RBAC types - Type definitions\n */\n\nimport React, { useMemo, useCallback, useEffect, useState, createContext, useContext } from 'react';\nimport { useLocation, useNavigate, Outlet } from 'react-router-dom';\nimport { useCan } from '../hooks';\nimport { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';\nimport { UUID, Permission, Scope, AccessLevel } from '../types';\n\nexport interface RouteConfig {\n /** Route path */\n path: string;\n \n /** React component to render */\n component: React.ComponentType;\n \n /** Permissions required for this route */\n permissions: Permission[];\n \n /** If true, this route is public and doesn't require permission checks */\n public?: boolean;\n \n /** Roles that can access this route */\n roles?: string[];\n \n /** Minimum access level required */\n accessLevel?: AccessLevel;\n \n /** Page ID for permission checking */\n pageId?: string;\n \n /** Enable strict mode for this route */\n strictMode?: boolean;\n \n /** Route metadata */\n meta?: {\n title?: string;\n description?: string;\n requiresAuth?: boolean;\n hidden?: boolean;\n };\n}\n\nexport interface RouteAccessRecord {\n route: string;\n permissions: Permission[];\n userId: UUID;\n scope: Scope;\n allowed: boolean;\n timestamp: string;\n pageId?: string;\n roles?: string[];\n accessLevel?: AccessLevel;\n}\n\nexport interface RoleBasedRouterContextType {\n /** Get all accessible routes for current user */\n getAccessibleRoutes: () => RouteConfig[];\n \n /** Check if user can access a specific route */\n canAccessRoute: (path: string) => boolean;\n \n /** Get route configuration for a path */\n getRouteConfig: (path: string) => RouteConfig | null;\n \n /** Get route access history */\n getRouteAccessHistory: () => RouteAccessRecord[];\n \n /** Clear route access history */\n clearRouteAccessHistory: () => void;\n \n /** Check if strict mode is enabled */\n isStrictMode: boolean;\n \n /** Check if audit logging is enabled */\n isAuditLogEnabled: boolean;\n}\n\nexport interface RoleBasedRouterProps {\n /** Route configuration */\n routes: RouteConfig[];\n \n /** Fallback route for unauthorized access */\n fallbackRoute?: string;\n \n /** Child components */\n children: React.ReactNode;\n \n /** Enable strict mode to prevent bypassing (default: true) */\n strictMode?: boolean;\n \n /** Enable audit logging (default: true) */\n auditLog?: boolean;\n \n /** Callback when route access is attempted */\n onRouteAccess?: (route: string, allowed: boolean, record: RouteAccessRecord) => void;\n \n /** Callback when strict mode violation occurs */\n onStrictModeViolation?: (route: string, record: RouteAccessRecord) => void;\n \n /** Maximum number of access records to keep in history */\n maxHistorySize?: number;\n \n /** Custom unauthorized component */\n unauthorizedComponent?: React.ComponentType<{ route: string; reason: string }>;\n}\n\nconst RoleBasedRouterContext = createContext<RoleBasedRouterContextType | null>(null);\n\n/**\n * RoleBasedRouter - Centralized routing control with role-based protection\n * \n * This component ensures that all routes are properly protected and provides\n * centralized routing control to prevent apps from bypassing route protection.\n * \n * @param props - Router props\n * @returns React element with role-based routing\n */\nexport function RoleBasedRouter({\n routes,\n fallbackRoute = '/unauthorized',\n children,\n strictMode = true,\n auditLog = true,\n onRouteAccess,\n onStrictModeViolation,\n maxHistorySize = 1000,\n unauthorizedComponent: UnauthorizedComponent = DefaultUnauthorizedComponent\n}: RoleBasedRouterProps) {\n const { user, selectedOrganisation, selectedEvent } = useUnifiedAuth();\n const location = useLocation();\n const navigate = useNavigate();\n const [routeAccessHistory, setRouteAccessHistory] = useState<RouteAccessRecord[]>([]);\n const [currentRoute, setCurrentRoute] = useState<string>('');\n\n // Get current scope\n const currentScope = useMemo((): Scope | null => {\n if (!selectedOrganisation) return null;\n \n return {\n organisationId: selectedOrganisation.id,\n eventId: selectedEvent?.event_id || undefined,\n appId: undefined\n };\n }, [selectedOrganisation, selectedEvent]);\n\n // Get route configuration for current path\n const currentRouteConfig = useMemo((): RouteConfig | null => {\n const currentPath = location.pathname;\n return routes.find(route => route.path === currentPath) || null;\n }, [routes, location.pathname]);\n\n // Check if user can access a specific route\n const canAccessRoute = useCallback((path: string): boolean => {\n if (!user?.id || !currentScope) return false;\n \n const routeConfig = routes.find(route => route.path === path);\n if (!routeConfig) return false;\n \n // Use the existing RBAC system to check route permissions\n // This is a synchronous check for the context - actual permission checking\n // happens in the individual route components using useCan hook\n // For now, we'll return true and let the individual route components\n // handle the actual permission checking asynchronously\n return true;\n }, [user?.id, currentScope, routes]);\n\n // Use useCan hook for actual permission checking\n const { can: canAccessCurrentRoute, isLoading: permissionLoading } = useCan(\n user?.id || '',\n currentScope || { organisationId: '', eventId: undefined, appId: undefined },\n currentRouteConfig?.permissions?.[0] || 'read:page',\n currentRouteConfig?.pageId\n );\n\n // Check if route is public\n const isPublicRoute = currentRouteConfig?.public === true;\n \n // If route has no permissions and is not public, deny access (secure by default)\n const hasPermissions = currentRouteConfig?.permissions && currentRouteConfig.permissions.length > 0;\n const finalCanAccess = isPublicRoute ? true : (hasPermissions ? canAccessCurrentRoute : false);\n const finalLoading = isPublicRoute ? false : (hasPermissions ? permissionLoading : false);\n\n // Get all accessible routes for current user\n const getAccessibleRoutes = useCallback((): RouteConfig[] => {\n if (!user?.id || !currentScope) return [];\n \n return routes.filter(route => canAccessRoute(route.path));\n }, [user?.id, currentScope, routes, canAccessRoute]);\n\n // Get route configuration for a path\n const getRouteConfig = useCallback((path: string): RouteConfig | null => {\n return routes.find(route => route.path === path) || null;\n }, [routes]);\n\n // Get route access history\n const getRouteAccessHistory = useCallback((): RouteAccessRecord[] => {\n return [...routeAccessHistory];\n }, [routeAccessHistory]);\n\n // Clear route access history\n const clearRouteAccessHistory = useCallback(() => {\n setRouteAccessHistory([]);\n }, []);\n\n // Record route access attempt\n const recordRouteAccess = useCallback((\n route: string,\n allowed: boolean,\n routeConfig: RouteConfig\n ) => {\n if (!auditLog || !user?.id || !currentScope) return;\n \n const record: RouteAccessRecord = {\n route,\n permissions: routeConfig.permissions,\n userId: user.id,\n scope: currentScope,\n allowed,\n timestamp: new Date().toISOString(),\n pageId: routeConfig.pageId,\n roles: routeConfig.roles,\n accessLevel: routeConfig.accessLevel\n };\n \n setRouteAccessHistory(prev => {\n const newHistory = [record, ...prev];\n return newHistory.slice(0, maxHistorySize);\n });\n \n if (onRouteAccess) {\n onRouteAccess(route, allowed, record);\n }\n \n if (strictMode && !allowed && onStrictModeViolation) {\n onStrictModeViolation(route, record);\n }\n }, [auditLog, user?.id, currentScope, maxHistorySize, onRouteAccess, onStrictModeViolation, strictMode]);\n\n // Check route access on location change\n useEffect(() => {\n const currentPath = location.pathname;\n setCurrentRoute(currentPath);\n \n if (!currentRouteConfig) {\n // Route not found in configuration\n if (strictMode) {\n console.error(`[RoleBasedRouter] STRICT MODE VIOLATION: Route not found in configuration`, {\n route: currentPath,\n userId: user?.id,\n timestamp: new Date().toISOString()\n });\n \n if (onStrictModeViolation) {\n onStrictModeViolation(currentPath, {\n route: currentPath,\n permissions: [],\n userId: user?.id || '',\n scope: currentScope || { organisationId: '' },\n allowed: false,\n timestamp: new Date().toISOString()\n });\n }\n }\n return;\n }\n \n // Use the actual permission check result\n const allowed = finalCanAccess;\n // Log route access (including public routes for audit monitoring)\n recordRouteAccess(currentPath, allowed, currentRouteConfig);\n \n if (!allowed && !isPublicRoute) {\n // Redirect to fallback route (skip for public routes)\n navigate(fallbackRoute, { replace: true });\n }\n }, [location.pathname, currentRouteConfig, canAccessCurrentRoute, recordRouteAccess, strictMode, user?.id, currentScope, onStrictModeViolation, navigate, fallbackRoute, isPublicRoute]);\n\n // Context value\n const contextValue = useMemo((): RoleBasedRouterContextType => ({\n getAccessibleRoutes,\n canAccessRoute,\n getRouteConfig,\n getRouteAccessHistory,\n clearRouteAccessHistory,\n isStrictMode: strictMode,\n isAuditLogEnabled: auditLog\n }), [\n getAccessibleRoutes,\n canAccessRoute,\n getRouteConfig,\n getRouteAccessHistory,\n clearRouteAccessHistory,\n strictMode,\n auditLog\n ]);\n\n // Show loading state while checking permissions (skip for public routes)\n if (finalLoading && !isPublicRoute) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"text-center\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-main-600 mx-auto mb-4\"></div>\n <p className=\"text-sec-600\">Checking permissions...</p>\n </div>\n </div>\n );\n }\n\n // Show unauthorized component if user can't access current route\n if (currentRouteConfig && !finalCanAccess && !isPublicRoute) {\n return (\n <UnauthorizedComponent \n route={currentRoute} \n reason=\"Insufficient permissions\" \n />\n );\n }\n return (\n <RoleBasedRouterContext.Provider value={contextValue}>\n {children}\n <Outlet />\n </RoleBasedRouterContext.Provider>\n );\n}\n\n/**\n * Hook to use role-based router context\n * \n * @returns Role-based router context\n * @throws Error if used outside of RoleBasedRouter\n */\nexport function useRoleBasedRouter(): RoleBasedRouterContextType {\n const context = useContext(RoleBasedRouterContext);\n \n if (!context) {\n throw new Error('useRoleBasedRouter must be used within a RoleBasedRouter');\n }\n \n return context;\n}\n\n/**\n * Default unauthorized component\n */\nfunction DefaultUnauthorizedComponent({ route, reason }: { route: string; reason: string }) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-screen p-8 text-center\">\n <div className=\"mb-4\">\n <svg className=\"w-16 h-16 text-acc-500 mx-auto\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z\" />\n </svg>\n </div>\n <h2 className=\"text-xl font-semibold text-sec-900 mb-2\">Access Denied</h2>\n <p className=\"text-sec-600 mb-4\">\n You don't have permission to access <code className=\"bg-sec-100 px-2 py-1 rounded\">{route}</code>\n </p>\n <p className=\"text-sm text-sec-500 mb-4\">Reason: {reason}</p>\n <button \n onClick={() => window.history.back()}\n className=\"px-4 py-2 bg-main-600 text-main-50 rounded-md hover:bg-main-700 transition-colors\"\n >\n Go Back\n </button>\n </div>\n );\n}\n\nexport default RoleBasedRouter;\n\n","/**\n * @file Navigation Provider Component\n * @package @jmruthers/pace-core\n * @module RBAC/Components/NavigationProvider\n * @since 2.0.0\n *\n * A context provider that manages navigation permissions across the entire application.\n * This component ensures that all navigation items are properly protected and provides\n * centralized navigation permission management.\n *\n * Features:\n * - App-wide navigation permission management\n * - Strict mode to prevent bypassing\n * - Automatic audit logging\n * - Integration with existing RBAC system\n * - Navigation permission tracking\n * - Error handling and recovery\n *\n * @example\n * ```tsx\n * // Basic app setup with navigation permissions\n * <NavigationProvider strictMode={true} auditLog={true}>\n * <App />\n * </NavigationProvider>\n * \n * // With custom configuration\n * <NavigationProvider\n * strictMode={true}\n * auditLog={true}\n * onNavigationAccess={(item, allowed) => {\n * console.log(`Navigation access: ${item} - ${allowed ? 'allowed' : 'denied'}`);\n * }}\n * >\n * <App />\n * </NavigationProvider>\n * ```\n *\n * @security\n * - Enforces navigation-level permissions across the app\n * - Prevents apps from bypassing navigation permission checks\n * - Automatic audit logging for all navigation access attempts\n * - Integration with existing RBAC system\n * - Navigation permission tracking and monitoring\n *\n * @performance\n * - Optimized with useMemo and useCallback\n * - Efficient context updates\n * - Minimal re-renders\n * - Cached permission checks\n *\n * @dependencies\n * - React 18+ - Context and hooks\n * - useUnifiedAuth - Authentication context\n * - RBAC types - Type definitions\n */\n\nimport React, { createContext, useContext, useState, useCallback, useMemo, useEffect } from 'react';\nimport { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';\nimport { useCan } from '../hooks';\nimport { UUID, Scope, Permission } from '../types';\n\nexport interface NavigationItem {\n /** Unique identifier for the navigation item */\n id: string;\n \n /** Display label for the navigation item */\n label: string;\n \n /** Navigation path/URL */\n path: string;\n \n /** Permissions required for this navigation item */\n permissions: Permission[];\n \n /** Roles that can access this navigation item */\n roles?: string[];\n \n /** Minimum access level required */\n accessLevel?: 'viewer' | 'participant' | 'planner' | 'admin' | 'super';\n \n /** Page ID for permission checking */\n pageId?: string;\n \n /** Enable strict mode for this navigation item */\n strictMode?: boolean;\n \n /** Navigation item metadata */\n meta?: {\n icon?: string;\n description?: string;\n hidden?: boolean;\n order?: number;\n };\n}\n\nexport interface NavigationAccessRecord {\n navigationItem: string;\n permissions: Permission[];\n userId: UUID;\n scope: Scope;\n allowed: boolean;\n timestamp: string;\n pageId?: string;\n roles?: string[];\n accessLevel?: string;\n}\n\nexport interface NavigationContextType {\n /** Check if user has permission for a navigation item */\n hasNavigationPermission: (item: NavigationItem) => boolean;\n \n /** Get all navigation permissions for current user */\n getNavigationPermissions: () => Record<string, string[]>;\n \n /** Get filtered navigation items based on permissions */\n getFilteredNavigationItems: (items: NavigationItem[]) => NavigationItem[];\n \n /** Check if navigation permission checking is enabled */\n isEnabled: boolean;\n \n /** Check if strict mode is enabled */\n isStrictMode: boolean;\n \n /** Check if audit logging is enabled */\n isAuditLogEnabled: boolean;\n \n /** Get navigation access history */\n getNavigationAccessHistory: () => NavigationAccessRecord[];\n \n /** Clear navigation access history */\n clearNavigationAccessHistory: () => void;\n}\n\nexport interface NavigationProviderProps {\n /** Child components */\n children: React.ReactNode;\n \n /** Enable strict mode to prevent bypassing (default: true) */\n strictMode?: boolean;\n \n /** Enable audit logging (default: true) */\n auditLog?: boolean;\n \n /** Callback when navigation access is attempted */\n onNavigationAccess?: (item: NavigationItem, allowed: boolean, record: NavigationAccessRecord) => void;\n \n /** Callback when strict mode violation occurs */\n onStrictModeViolation?: (item: NavigationItem, record: NavigationAccessRecord) => void;\n \n /** Maximum number of access records to keep in history */\n maxHistorySize?: number;\n}\n\nconst NavigationContext = createContext<NavigationContextType | null>(null);\n\n/**\n * NavigationProvider - Manages navigation-level permissions across the app\n * \n * This provider ensures that all navigation items are properly protected and provides\n * centralized navigation permission management with strict enforcement.\n * \n * @param props - Provider props\n * @returns React element with navigation permission context\n */\nexport function NavigationProvider({\n children,\n strictMode = true,\n auditLog = true,\n onNavigationAccess,\n onStrictModeViolation,\n maxHistorySize = 1000\n}: NavigationProviderProps) {\n const { user, selectedOrganisation, selectedEvent } = useUnifiedAuth();\n const [navigationAccessHistory, setNavigationAccessHistory] = useState<NavigationAccessRecord[]>([]);\n const [isEnabled, setIsEnabled] = useState(true);\n\n // Get current scope\n const currentScope = useMemo((): Scope | null => {\n if (!selectedOrganisation) return null;\n \n return {\n organisationId: selectedOrganisation.id,\n eventId: selectedEvent?.event_id || undefined,\n appId: undefined\n };\n }, [selectedOrganisation, selectedEvent]);\n\n // Check if user has permission for a navigation item\n // NOTE: This is a synchronous check for basic validation only.\n // Actual permission checking should be done by individual NavigationGuard components\n // using the useCan hook for proper async RBAC integration.\n const hasNavigationPermission = useCallback((\n item: NavigationItem\n ): boolean => {\n if (!isEnabled) return true;\n if (!user?.id) return false; // No user context - deny access for security\n \n if (!currentScope) return false; // No scope context - deny access for security\n \n // If no permissions are defined for the navigation item, deny access by default\n if (!item.permissions || item.permissions.length === 0) {\n console.warn(`[NavigationProvider] Navigation item \"${item.id}\" has no permissions defined - denying access`);\n return false;\n }\n \n // Use the first permission for checking (as per original implementation)\n const permission = item.permissions[0];\n \n // Call useCan hook for actual permission checking\n const { can, error } = useCan(\n user.id,\n currentScope,\n permission,\n item.pageId,\n true // useCache\n );\n \n // Handle errors gracefully - allow access when there are permission check errors (graceful degradation)\n // This ensures navigation doesn't break when the permission service has issues\n if (error) {\n console.warn(`[NavigationProvider] Permission check error for \"${item.id}\": ${error.message} - allowing access for graceful degradation`);\n return true;\n }\n \n return can;\n }, [isEnabled, user?.id, currentScope]);\n\n // Get all navigation permissions for current user\n const getNavigationPermissions = useCallback((): Record<string, string[]> => {\n if (!isEnabled || !user?.id) return {};\n \n // For now, return empty object - this will be enhanced with actual permission checking\n // when we integrate with the existing RBAC system\n return {};\n }, [isEnabled, user?.id]);\n\n // Get filtered navigation items based on permissions\n const getFilteredNavigationItems = useCallback((items: NavigationItem[]): NavigationItem[] => {\n if (!isEnabled) return items;\n \n return items.filter(item => hasNavigationPermission(item));\n }, [isEnabled, hasNavigationPermission]);\n\n // Get navigation access history\n const getNavigationAccessHistory = useCallback((): NavigationAccessRecord[] => {\n return [...navigationAccessHistory];\n }, [navigationAccessHistory]);\n\n // Clear navigation access history\n const clearNavigationAccessHistory = useCallback(() => {\n setNavigationAccessHistory([]);\n }, []);\n\n // Record navigation access attempt\n const recordNavigationAccess = useCallback((\n item: NavigationItem,\n allowed: boolean\n ) => {\n if (!auditLog || !user?.id || !currentScope) return;\n \n const record: NavigationAccessRecord = {\n navigationItem: item.id,\n permissions: item.permissions,\n userId: user.id,\n scope: currentScope,\n allowed,\n timestamp: new Date().toISOString(),\n pageId: item.pageId,\n roles: item.roles,\n accessLevel: item.accessLevel\n };\n \n setNavigationAccessHistory(prev => {\n const newHistory = [record, ...prev];\n return newHistory.slice(0, maxHistorySize);\n });\n \n if (onNavigationAccess) {\n onNavigationAccess(item, allowed, record);\n }\n \n if (strictMode && !allowed && onStrictModeViolation) {\n onStrictModeViolation(item, record);\n }\n }, [auditLog, user?.id, currentScope, maxHistorySize, onNavigationAccess, onStrictModeViolation, strictMode]);\n\n // Context value\n const contextValue = useMemo((): NavigationContextType => ({\n hasNavigationPermission,\n getNavigationPermissions,\n getFilteredNavigationItems,\n isEnabled,\n isStrictMode: strictMode,\n isAuditLogEnabled: auditLog,\n getNavigationAccessHistory,\n clearNavigationAccessHistory\n }), [\n hasNavigationPermission,\n getNavigationPermissions,\n getFilteredNavigationItems,\n isEnabled,\n strictMode,\n auditLog,\n getNavigationAccessHistory,\n clearNavigationAccessHistory\n ]);\n\n // Log strict mode violations\n useEffect(() => {\n if (strictMode && auditLog) {\n console.log(`[NavigationProvider] Strict mode enabled - all navigation access attempts will be logged and enforced`);\n }\n }, [strictMode, auditLog]);\n\n return (\n <NavigationContext.Provider value={contextValue}>\n {children}\n </NavigationContext.Provider>\n );\n}\n\n/**\n * Hook to use navigation permission context\n * \n * @returns Navigation permission context\n * @throws Error if used outside of NavigationProvider\n */\nexport function useNavigationPermissions(): NavigationContextType {\n const context = useContext(NavigationContext);\n \n if (!context) {\n throw new Error('useNavigationPermissions must be used within a NavigationProvider');\n }\n \n return context;\n}\n\nexport default NavigationProvider;","/**\n * @file Navigation Guard Component\n * @package @jmruthers/pace-core\n * @module RBAC/Components/NavigationGuard\n * @since 2.0.0\n *\n * A component that enforces navigation-level permissions and prevents apps from bypassing\n * navigation permission checks. This is a critical security component that ensures all\n * navigation items are properly protected.\n *\n * Features:\n * - Navigation-level permission enforcement\n * - Strict mode to prevent bypassing\n * - Automatic audit logging\n * - Integration with existing RBAC system\n * - Clear error messages for unauthorized navigation\n * - TypeScript support with strict typing\n *\n * @example\n * ```tsx\n * // Basic navigation protection\n * <NavigationGuard\n * navigationItem={navItem}\n * fallback={<AccessDeniedNavItem />}\n * >\n * <NavigationLink />\n * </NavigationGuard>\n * \n * // Strict mode (prevents bypassing)\n * <NavigationGuard\n * navigationItem={adminNavItem}\n * strictMode={true}\n * fallback={<AccessDeniedNavItem />}\n * >\n * <AdminNavigationLink />\n * </NavigationGuard>\n * \n * // With custom fallback\n * <NavigationGuard\n * navigationItem={settingsNavItem}\n * fallback={<div>You don't have permission to access settings</div>}\n * >\n * <SettingsNavigationLink />\n * </NavigationGuard>\n * ```\n *\n * @security\n * - Enforces navigation-level permissions\n * - Prevents apps from bypassing navigation permission checks\n * - Automatic audit logging for all navigation access attempts\n * - Integration with existing RBAC system\n * - Clear error messages for unauthorized navigation\n *\n * @performance\n * - Optimized with useMemo and useCallback\n * - Cached permission checks\n * - Minimal re-renders\n * - Efficient error handling\n *\n * @dependencies\n * - React 18+ - Component framework\n * - useCan hook - Permission checking\n * - useUnifiedAuth - Authentication context\n * - RBAC types - Type definitions\n */\n\nimport React, { useMemo, useCallback, useEffect, useState } from 'react';\nimport { useMultiplePermissions } from '../hooks/usePermissions';\nimport { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';\nimport { UUID, Permission, Scope } from '../types';\nimport { createScopeFromEvent } from '../utils/eventContext';\nimport { NavigationItem } from './NavigationProvider';\n\nexport interface NavigationGuardProps {\n /** Navigation item being protected */\n navigationItem: NavigationItem;\n \n /** Content to render when user has permission */\n children: React.ReactNode;\n \n /** Content to render when user lacks permission */\n fallback?: React.ReactNode;\n \n /** Enable strict mode to prevent bypassing (default: true) */\n strictMode?: boolean;\n \n /** Force audit logging for this navigation access (default: true) */\n auditLog?: boolean;\n \n /** Custom scope for permission checking */\n scope?: Scope;\n \n /** Callback when access is denied */\n onDenied?: (item: NavigationItem) => void;\n \n /** Loading state content */\n loading?: React.ReactNode;\n \n /** Require all permissions (AND) or any permission (OR) */\n requireAll?: boolean;\n}\n\n/**\n * NavigationGuard - Enforces navigation-level permissions\n * \n * This component ensures that users can only access navigation items they have permission for.\n * It integrates with the existing RBAC system and provides strict enforcement to\n * prevent apps from bypassing navigation permission checks.\n * \n * @param props - Component props\n * @returns React element with navigation permission enforcement\n */\nexport function NavigationGuard({\n navigationItem,\n children,\n fallback = <DefaultAccessDenied />,\n strictMode = true,\n auditLog = true,\n scope,\n onDenied,\n loading = <DefaultLoading />,\n requireAll = true\n}: NavigationGuardProps) {\n const { user, selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();\n const [hasChecked, setHasChecked] = useState(false);\n const [checkError, setCheckError] = useState<Error | null>(null);\n const [resolvedScope, setResolvedScope] = useState<Scope | null>(null);\n\n // Resolve scope - either use provided scope or resolve from context\n useEffect(() => {\n const resolveScope = async () => {\n if (scope) {\n setResolvedScope(scope);\n return;\n }\n\n // If we have both organisation and event, use them directly\n if (selectedOrganisation && selectedEvent) {\n setResolvedScope({\n organisationId: selectedOrganisation.id,\n eventId: selectedEvent.event_id,\n appId: undefined\n });\n return;\n }\n\n // If we only have organisation, use it\n if (selectedOrganisation) {\n setResolvedScope({\n organisationId: selectedOrganisation.id,\n eventId: selectedEvent?.event_id || undefined,\n appId: undefined\n });\n return;\n }\n\n // If we only have event, resolve organisation from event\n if (selectedEvent && supabase) {\n try {\n const eventScope = await createScopeFromEvent(supabase, selectedEvent.event_id);\n if (!eventScope) {\n setCheckError(new Error('Could not resolve organization from event context'));\n return;\n }\n setResolvedScope(eventScope);\n } catch (error) {\n setCheckError(error as Error);\n }\n return;\n }\n\n // No context available\n setCheckError(new Error('Either organisation context or event context is required for navigation permission checking'));\n };\n\n resolveScope();\n }, [scope, selectedOrganisation, selectedEvent, supabase]);\n\n // Check all permissions using useMultiplePermissions hook\n const { results: permissionResults, isLoading, error } = useMultiplePermissions(\n user?.id || '',\n resolvedScope || { eventId: selectedEvent?.event_id || undefined },\n navigationItem.permissions || [],\n true // Use cache\n );\n\n // Determine if user has required permissions based on requireAll prop\n const hasRequiredPermissions = useMemo((): boolean => {\n if (!navigationItem.permissions || navigationItem.permissions.length === 0) return true;\n \n if (requireAll) {\n // User must have ALL permissions\n return Object.values(permissionResults).every(result => result === true);\n } else {\n // User must have ANY permission (default behavior)\n return Object.values(permissionResults).some(result => result === true);\n }\n }, [navigationItem.permissions, permissionResults, requireAll]);\n\n // Handle permission check completion\n useEffect(() => {\n if (!isLoading && !error) {\n setHasChecked(true);\n setCheckError(null);\n \n if (!hasRequiredPermissions && onDenied) {\n onDenied(navigationItem);\n }\n } else if (error) {\n setCheckError(error);\n setHasChecked(true);\n }\n }, [hasRequiredPermissions, isLoading, error, navigationItem, onDenied]);\n\n // Log navigation access attempt for audit\n useEffect(() => {\n if (auditLog && hasChecked && !isLoading) {\n console.log(`[NavigationGuard] Navigation access attempt:`, {\n navigationItem: navigationItem.id,\n permissions: navigationItem.permissions,\n userId: user?.id,\n scope: resolvedScope,\n allowed: hasRequiredPermissions,\n requireAll,\n timestamp: new Date().toISOString()\n });\n }\n }, [auditLog, hasChecked, isLoading, navigationItem, user?.id, resolvedScope, hasRequiredPermissions, requireAll]);\n\n // Handle strict mode violations\n useEffect(() => {\n if (strictMode && hasChecked && !isLoading && !hasRequiredPermissions) {\n console.error(`[NavigationGuard] STRICT MODE VIOLATION: User attempted to access protected navigation item without permission`, {\n navigationItem: navigationItem.id,\n permissions: navigationItem.permissions,\n userId: user?.id,\n scope: resolvedScope,\n requireAll,\n timestamp: new Date().toISOString()\n });\n }\n }, [strictMode, hasChecked, isLoading, hasRequiredPermissions, navigationItem, user?.id, resolvedScope, requireAll]);\n\n // Show loading state\n if (isLoading || !resolvedScope || !hasChecked) {\n return <>{loading}</>;\n }\n\n // Show error state\n if (checkError) {\n console.error(`[NavigationGuard] Permission check failed for navigation item ${navigationItem.id}:`, checkError);\n return <>{fallback}</>;\n }\n\n // Show access denied\n if (!hasRequiredPermissions) {\n return <>{fallback}</>;\n }\n\n // Show protected content\n return <>{children}</>;\n}\n\n/**\n * Default access denied component\n */\nfunction DefaultAccessDenied() {\n return (\n <div className=\"flex items-center justify-center p-2 text-center\">\n <div className=\"flex items-center space-x-2\">\n <svg className=\"w-4 h-4 text-acc-500\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z\" />\n </svg>\n <span className=\"text-sm text-sec-600\">Access Denied</span>\n </div>\n </div>\n );\n}\n\n/**\n * Default loading component\n */\nfunction DefaultLoading() {\n return (\n <div className=\"flex items-center justify-center p-2\">\n <div className=\"flex items-center space-x-2\">\n <div className=\"animate-spin rounded-full h-4 w-4 border-b-2 border-main-600\"></div>\n <span className=\"text-sm text-sec-600\">Checking...</span>\n </div>\n </div>\n );\n}\n\nexport default NavigationGuard;","/**\n * @file Enhanced Navigation Menu Component\n * @package @jmruthers/pace-core\n * @module RBAC/Components/EnhancedNavigationMenu\n * @since 2.0.0\n *\n * An enhanced navigation menu component that integrates with the RBAC system to provide\n * secure navigation with automatic permission filtering and enforcement.\n *\n * Features:\n * - Automatic permission-based filtering\n * - Strict mode enforcement\n * - Audit logging for navigation access\n * - Integration with existing RBAC system\n * - Customizable navigation items\n * - Error handling and recovery\n *\n * @example\n * ```tsx\n * // Basic enhanced navigation menu\n * <EnhancedNavigationMenu\n * items={navigationItems}\n * strictMode={true}\n * auditLog={true}\n * />\n * \n * // With custom configuration\n * <EnhancedNavigationMenu\n * items={navigationItems}\n * strictMode={true}\n * auditLog={true}\n * onNavigationAccess={(item, allowed) => {\n * console.log(`Navigation access: ${item.id} - ${allowed ? 'allowed' : 'denied'}`);\n * }}\n * />\n * ```\n *\n * @security\n * - Enforces navigation-level permissions\n * - Prevents apps from bypassing navigation permission checks\n * - Automatic audit logging for all navigation access attempts\n * - Integration with existing RBAC system\n * - Clear error messages for unauthorized navigation\n *\n * @performance\n * - Optimized with useMemo and useCallback\n * - Cached permission checks\n * - Minimal re-renders\n * - Efficient filtering\n *\n * @dependencies\n * - React 18+ - Component framework\n * - NavigationProvider - Navigation permission context\n * - NavigationGuard - Individual navigation item protection\n * - RBAC types - Type definitions\n */\n\nimport React, { useMemo, useCallback, useEffect, useState } from 'react';\nimport { useNavigationPermissions, NavigationItem } from './NavigationProvider';\nimport NavigationGuard from './NavigationGuard';\n\nexport interface EnhancedNavigationMenuProps {\n /** Navigation items to display */\n items: NavigationItem[];\n \n /** Enable strict mode to prevent bypassing (default: true) */\n strictMode?: boolean;\n \n /** Enable audit logging (default: true) */\n auditLog?: boolean;\n \n /** Callback when navigation access is attempted */\n onNavigationAccess?: (item: NavigationItem, allowed: boolean) => void;\n \n /** Callback when strict mode violation occurs */\n onStrictModeViolation?: (item: NavigationItem) => void;\n \n /** Custom className for the navigation menu */\n className?: string;\n \n /** Custom className for navigation items */\n itemClassName?: string;\n \n /** Custom className for active navigation items */\n activeItemClassName?: string;\n \n /** Custom className for disabled navigation items */\n disabledItemClassName?: string;\n \n /** Show/hide navigation items that user doesn't have permission for */\n hideUnauthorizedItems?: boolean;\n \n /** Custom render function for navigation items */\n renderItem?: (item: NavigationItem, isAuthorized: boolean) => React.ReactNode;\n \n /** Current active path for highlighting */\n activePath?: string;\n \n /** Navigation item click handler */\n onItemClick?: (item: NavigationItem) => void;\n}\n\n/**\n * EnhancedNavigationMenu - Secure navigation menu with RBAC integration\n * \n * This component provides a navigation menu that automatically filters items based on\n * user permissions and enforces strict security controls.\n * \n * @param props - Component props\n * @returns React element with enhanced navigation menu\n */\nexport function EnhancedNavigationMenu({\n items,\n strictMode = true,\n auditLog = true,\n onNavigationAccess,\n onStrictModeViolation,\n className = 'flex flex-col space-y-1',\n itemClassName = 'px-3 py-2 rounded-md text-sm font-medium transition-colors',\n activeItemClassName = 'bg-main-100 text-main-700',\n disabledItemClassName = 'text-sec-400 cursor-not-allowed',\n hideUnauthorizedItems = false,\n renderItem,\n activePath,\n onItemClick\n}: EnhancedNavigationMenuProps) {\n const { \n hasNavigationPermission, \n getFilteredNavigationItems,\n isEnabled,\n isStrictMode,\n isAuditLogEnabled \n } = useNavigationPermissions();\n \n const [navigationHistory, setNavigationHistory] = useState<NavigationItem[]>([]);\n\n // Get filtered navigation items based on permissions\n const filteredItems = useMemo((): NavigationItem[] => {\n if (!isEnabled) return items;\n \n return getFilteredNavigationItems(items);\n }, [isEnabled, items, getFilteredNavigationItems]);\n\n // Handle navigation access attempt\n const handleNavigationAccess = useCallback((item: NavigationItem, allowed: boolean) => {\n if (onNavigationAccess) {\n onNavigationAccess(item, allowed);\n }\n \n if (auditLog) {\n console.log(`[EnhancedNavigationMenu] Navigation access attempt:`, {\n item: item.id,\n allowed,\n strictMode,\n timestamp: new Date().toISOString()\n });\n }\n }, [onNavigationAccess, auditLog, strictMode]);\n\n // Handle strict mode violation\n const handleStrictModeViolation = useCallback((item: NavigationItem) => {\n if (onStrictModeViolation) {\n onStrictModeViolation(item);\n }\n \n if (strictMode) {\n console.error(`[EnhancedNavigationMenu] STRICT MODE VIOLATION: User attempted to access protected navigation item without permission`, {\n item: item.id,\n path: item.path,\n permissions: item.permissions,\n timestamp: new Date().toISOString()\n });\n }\n }, [onStrictModeViolation, strictMode]);\n\n // Handle navigation item click\n const handleItemClick = useCallback((item: NavigationItem) => {\n // Check if user has permission for this item\n const isAuthorized = hasNavigationPermission(item);\n \n // Call navigation access handler\n handleNavigationAccess(item, isAuthorized);\n \n if (onItemClick) {\n onItemClick(item);\n }\n \n // Record navigation attempt\n if (auditLog) {\n console.log(`[EnhancedNavigationMenu] Navigation item clicked:`, {\n item: item.id,\n path: item.path,\n permissions: item.permissions,\n timestamp: new Date().toISOString()\n });\n }\n \n // Add to navigation history\n setNavigationHistory(prev => {\n const newHistory = [item, ...prev.filter(i => i.id !== item.id)];\n return newHistory.slice(0, 10); // Keep last 10 items\n });\n }, [onItemClick, auditLog, hasNavigationPermission, handleNavigationAccess]);\n\n // Default render function for navigation items\n const defaultRenderItem = useCallback((item: NavigationItem, isAuthorized: boolean) => {\n const isActive = activePath === item.path;\n const isDisabled = !isAuthorized;\n \n return (\n <NavigationGuard\n key={item.id}\n navigationItem={item}\n strictMode={strictMode}\n auditLog={auditLog}\n onDenied={handleStrictModeViolation}\n fallback={\n hideUnauthorizedItems ? null : (\n <div className={`${itemClassName} ${disabledItemClassName}`}>\n <div className=\"flex items-center space-x-2\">\n {item.meta?.icon && (\n <span className=\"text-sm\">{item.meta.icon}</span>\n )}\n <span>{item.label}</span>\n <span className=\"text-xs text-sec-400\">(Access Denied)</span>\n </div>\n </div>\n )\n }\n >\n <button\n onClick={() => handleItemClick(item)}\n className={`${itemClassName} ${\n isActive ? activeItemClassName : ''\n } ${\n isDisabled ? disabledItemClassName : 'hover:bg-sec-100'\n }`}\n disabled={isDisabled}\n >\n <div className=\"flex items-center space-x-2\">\n {item.meta?.icon && (\n <span className=\"text-sm\">{item.meta.icon}</span>\n )}\n <span>{item.label}</span>\n {item.meta?.description && (\n <span className=\"text-xs text-sec-500 ml-auto\">\n {item.meta.description}\n </span>\n )}\n </div>\n </button>\n </NavigationGuard>\n );\n }, [\n activePath,\n itemClassName,\n activeItemClassName,\n disabledItemClassName,\n hideUnauthorizedItems,\n strictMode,\n auditLog,\n handleStrictModeViolation,\n handleItemClick\n ]);\n\n // Log strict mode violations\n useEffect(() => {\n if (strictMode && auditLog) {\n console.log(`[EnhancedNavigationMenu] Strict mode enabled - all navigation access attempts will be logged and enforced`);\n }\n }, [strictMode, auditLog]);\n\n // Log navigation menu initialization\n useEffect(() => {\n if (auditLog) {\n console.log(`[EnhancedNavigationMenu] Navigation menu initialized:`, {\n totalItems: items.length,\n filteredItems: filteredItems.length,\n strictMode,\n timestamp: new Date().toISOString()\n });\n }\n }, [items.length, filteredItems.length, strictMode, auditLog]);\n\n return (\n <nav className={className}>\n {filteredItems.map(item => {\n const isAuthorized = hasNavigationPermission(item);\n \n if (renderItem) {\n return renderItem(item, isAuthorized);\n }\n \n return defaultRenderItem(item, isAuthorized);\n })}\n </nav>\n );\n}\n\nexport default EnhancedNavigationMenu;\n","/**\n * RBAC Adapters\n * @package @jmruthers/pace-core\n * @module RBAC/Adapters\n * @since 1.0.0\n * \n * This module provides adapters for different frameworks and server runtimes.\n */\n\nimport React, { ReactNode } from 'react';\nimport { UUID, Permission } from './types';\nimport { useCan } from './hooks';\nimport { rbacCache, RBACCache } from './cache';\nimport { getRBACLogger } from './config';\nimport { useUnifiedAuth } from '../providers/UnifiedAuthProvider';\n\n// ============================================================================\n// REACT COMPONENTS\n// ============================================================================\n\n/**\n * Permission Guard Component\n * \n * A React component that conditionally renders children based on permissions.\n * Can auto-infer userId from context if not provided.\n * \n * @example\n * ```tsx\n * // With explicit userId and scope\n * <PermissionGuard\n * userId=\"user-123\"\n * scope={{ organisationId: 'org-456' }}\n * permission=\"update:events\"\n * pageId=\"page-789\"\n * fallback={<AccessDenied />}\n * >\n * <AdminPanel />\n * </PermissionGuard>\n * \n * // With context inference (requires auth context)\n * <PermissionGuard\n * permission=\"update:events\"\n * scope={{ organisationId: 'org-456' }}\n * fallback={<AccessDenied />}\n * >\n * <AdminPanel />\n * </PermissionGuard>\n * ```\n */\nexport function PermissionGuard({\n userId,\n scope,\n permission,\n pageId,\n children,\n fallback = null,\n onDenied,\n loading = null,\n // NEW: Phase 1 - Enhanced Security Features\n strictMode = true,\n auditLog = true,\n enforceAudit = true,\n}: {\n userId?: UUID;\n scope: { organisationId: UUID; eventId?: string; appId?: UUID };\n permission: Permission;\n pageId?: UUID;\n children: ReactNode;\n fallback?: ReactNode;\n onDenied?: () => void;\n loading?: ReactNode;\n // NEW: Phase 1 - Enhanced Security Features\n strictMode?: boolean;\n auditLog?: boolean;\n enforceAudit?: boolean;\n}): React.ReactNode {\n const logger = getRBACLogger();\n\n let authContext: ReturnType<typeof useUnifiedAuth> | null = null;\n try {\n authContext = useUnifiedAuth();\n } catch (error) {\n if (error instanceof Error && error.message.includes('must be used within')) {\n authContext = null;\n } else {\n throw error;\n }\n }\n\n const effectiveUserId = userId ?? authContext?.user?.id ?? null;\n\n // Always call useCan hook, but handle the case where userId might be undefined\n const { can, isLoading, error } = useCan(effectiveUserId || '', scope, permission, pageId);\n\n // If still no userId, show helpful error\n if (!effectiveUserId) {\n logger.error('PermissionGuard: No userId provided and could not infer from context');\n return fallback ?? null;\n }\n\n // Handle loading state\n if (isLoading) {\n return loading || (\n <div className=\"rbac-loading\" role=\"status\" aria-live=\"polite\">\n <span className=\"sr-only\">Checking permissions...</span>\n </div>\n );\n }\n\n // Handle error state\n if (error) {\n logger.error('Permission check failed:', error);\n // NEW: Phase 1 - Record failed permission check for audit\n if (auditLog) {\n logger.info(`[PermissionGuard] Permission check failed:`, {\n userId: effectiveUserId,\n scope,\n permission,\n pageId,\n error: error.message,\n timestamp: new Date().toISOString()\n });\n }\n return fallback;\n }\n\n // Handle permission denied\n if (!can) {\n // NEW: Phase 1 - Record denied permission check for audit\n if (auditLog) {\n logger.info(`[PermissionGuard] Permission denied:`, {\n userId: effectiveUserId,\n scope,\n permission,\n pageId,\n timestamp: new Date().toISOString()\n });\n }\n \n // NEW: Phase 1 - Handle strict mode violations\n if (strictMode) {\n logger.error(`[PermissionGuard] STRICT MODE VIOLATION: User attempted to access protected resource without permission`, {\n userId: effectiveUserId,\n scope,\n permission,\n pageId,\n timestamp: new Date().toISOString()\n });\n }\n \n if (onDenied) {\n onDenied();\n }\n return <>{fallback}</>;\n }\n\n // NEW: Phase 1 - Record successful permission check for audit\n if (auditLog) {\n logger.info(`[PermissionGuard] Permission granted:`, {\n userId: effectiveUserId,\n scope,\n permission,\n pageId,\n timestamp: new Date().toISOString()\n });\n }\n\n // Render children if permission granted\n return <>{children}</>;\n}\n\n/**\n * Access Level Guard Component\n * \n * A React component that conditionally renders children based on access level.\n * Can auto-infer userId from context if not provided.\n * \n * @example\n * ```tsx\n * // With explicit userId and scope\n * <AccessLevelGuard\n * userId=\"user-123\"\n * scope={{ organisationId: 'org-456' }}\n * minLevel=\"admin\"\n * fallback={<AccessDenied />}\n * >\n * <AdminPanel />\n * </AccessLevelGuard>\n * \n * // With context inference (requires auth context)\n * <AccessLevelGuard\n * minLevel=\"admin\"\n * scope={{ organisationId: 'org-456' }}\n * fallback={<AccessDenied />}\n * >\n * <AdminPanel />\n * </AccessLevelGuard>\n * ```\n */\nexport function AccessLevelGuard({\n userId,\n scope,\n minLevel,\n children,\n fallback = null,\n loading = null,\n}: {\n userId?: UUID;\n scope: { organisationId: UUID; eventId?: string; appId?: UUID };\n minLevel: 'viewer' | 'participant' | 'planner' | 'admin' | 'super';\n children: ReactNode;\n fallback?: ReactNode;\n loading?: ReactNode;\n}): React.ReactNode {\n const logger = getRBACLogger();\n\n let authContext: ReturnType<typeof useUnifiedAuth> | null = null;\n try {\n authContext = useUnifiedAuth();\n } catch (error) {\n if (error instanceof Error && error.message.includes('must be used within')) {\n authContext = null;\n } else {\n throw error;\n }\n }\n\n const effectiveUserId = userId ?? authContext?.user?.id ?? null;\n\n // Always call useAccessLevel hook, but handle the case where userId might be undefined\n const { accessLevel, isLoading, error } = useAccessLevel(effectiveUserId || '', scope);\n\n // If still no userId, show helpful error\n if (!effectiveUserId) {\n logger.error('AccessLevelGuard: No userId provided and could not infer from context');\n return fallback ?? null;\n }\n\n // Handle loading state\n if (isLoading) {\n return loading || (\n <div className=\"rbac-loading\" role=\"status\" aria-live=\"polite\">\n <span className=\"sr-only\">Checking access level...</span>\n </div>\n );\n }\n\n // Handle error state\n if (error) {\n logger.error('Access level check failed:', error);\n return fallback;\n }\n\n // Check access level\n const levelHierarchy = ['viewer', 'participant', 'planner', 'admin', 'super'];\n const userLevelIndex = accessLevel ? levelHierarchy.indexOf(accessLevel) : -1;\n const requiredLevelIndex = levelHierarchy.indexOf(minLevel);\n\n if (userLevelIndex < requiredLevelIndex) {\n return <>{fallback}</>;\n }\n\n return <>{children}</>;\n}\n\n// ============================================================================\n// SERVER ADAPTERS\n// ============================================================================\n\n/**\n * Permission Guard for Server Handlers\n * \n * Wraps a server handler with permission checking.\n * \n * @param config - Permission guard configuration\n * @param handler - Handler function to wrap\n * @returns Wrapped handler function\n * \n * @example\n * ```typescript\n * const protectedHandler = withPermissionGuard(\n * { permission: 'update:events', pageId: 'page-789' },\n * async (req, res) => {\n * // Handler logic here\n * res.json({ success: true });\n * }\n * );\n * ```\n */\nexport function withPermissionGuard<T extends any[]>(\n config: {\n permission: Permission;\n pageId?: UUID;\n },\n handler: (...args: T) => Promise<any>\n) {\n return async (...args: T): Promise<any> => {\n // Extract user context from request\n const [req] = args;\n const userId = req.user?.id;\n const organisationId = req.organisationId;\n const eventId = req.eventId;\n const appId = req.appId;\n\n if (!userId || !organisationId) {\n throw new Error('User context required for permission check');\n }\n\n // Check permission\n const { isPermitted } = await import('./api');\n const hasPermission = await isPermitted({\n userId,\n scope: { organisationId, eventId, appId },\n permission: config.permission,\n pageId: config.pageId,\n });\n\n if (!hasPermission) {\n throw new Error(`Permission denied: ${config.permission}`);\n }\n\n // Execute handler\n return handler(...args);\n };\n}\n\n/**\n * Access Level Guard for Server Handlers\n * \n * Wraps a server handler with access level checking.\n * \n * @param minLevel - Minimum access level required\n * @param handler - Handler function to wrap\n * @returns Wrapped handler function\n * \n * @example\n * ```typescript\n * const adminHandler = withAccessLevelGuard(\n * 'admin',\n * async (req, res) => {\n * // Admin-only logic here\n * res.json({ success: true });\n * }\n * );\n * ```\n */\nexport function withAccessLevelGuard<T extends any[]>(\n minLevel: 'viewer' | 'participant' | 'planner' | 'admin' | 'super',\n handler: (...args: T) => Promise<any>\n) {\n return async (...args: T): Promise<any> => {\n // Extract user context from request\n const [req] = args;\n const userId = req.user?.id;\n const organisationId = req.organisationId;\n const eventId = req.eventId;\n const appId = req.appId;\n\n if (!userId || !organisationId) {\n throw new Error('User context required for access level check');\n }\n\n // Check access level\n const { getAccessLevel } = await import('./api');\n const accessLevel = await getAccessLevel({\n userId,\n scope: { organisationId, eventId, appId },\n });\n\n const levelHierarchy = ['viewer', 'participant', 'planner', 'admin', 'super'];\n const userLevelIndex = levelHierarchy.indexOf(accessLevel);\n const requiredLevelIndex = levelHierarchy.indexOf(minLevel);\n\n if (userLevelIndex < requiredLevelIndex) {\n throw new Error(`Access level required: ${minLevel}, got: ${accessLevel}`);\n }\n\n // Execute handler\n return handler(...args);\n };\n}\n\n/**\n * Role Guard for Server Handlers\n * \n * Wraps a server handler with role-based access control.\n * This is the primary middleware for routing protection as specified in the contract.\n * \n * @param config - Role guard configuration\n * @param handler - Handler function to wrap\n * @returns Wrapped handler function\n * \n * @example\n * ```typescript\n * const adminHandler = withRoleGuard(\n * { \n * globalRoles: ['super_admin'],\n * organisationRoles: ['org_admin', 'leader'],\n * eventAppRoles: ['event_admin', 'planner']\n * },\n * async (req, res) => {\n * // Admin-only logic here\n * res.json({ success: true });\n * }\n * );\n * ```\n */\nexport function withRoleGuard<T extends any[]>(\n config: {\n globalRoles?: string[];\n organisationRoles?: string[];\n eventAppRoles?: string[];\n requireAll?: boolean;\n },\n handler: (...args: T) => Promise<any>\n) {\n return async (...args: T): Promise<any> => {\n // Extract user context from request\n const [req] = args;\n const userId = req.user?.id;\n const organisationId = req.organisationId;\n const eventId = req.eventId;\n const appId = req.appId;\n\n if (!userId || !organisationId) {\n throw new Error('User context required for role check');\n }\n\n // Check global roles first (super_admin bypasses all)\n if (config.globalRoles && config.globalRoles.length > 0) {\n const { isSuperAdmin } = await import('./api');\n const isSuper = await isSuperAdmin(userId);\n \n if (isSuper) {\n // Log bypass for super admin - only if we have a valid organisation ID\n if (organisationId) {\n const { emitAuditEvent } = await import('./audit');\n await emitAuditEvent({\n type: 'permission_check',\n userId,\n organisationId,\n eventId,\n appId,\n permission: 'bypass:all',\n decision: true,\n source: 'api',\n bypass: true,\n duration_ms: 0,\n metadata: {\n operation: 'role_guard',\n reason: 'super_admin_bypass'\n }\n });\n }\n \n return handler(...args);\n }\n }\n\n // Check organisation roles\n if (config.organisationRoles && config.organisationRoles.length > 0) {\n const { isOrganisationAdmin } = await import('./api');\n const isOrgAdmin = await isOrganisationAdmin(userId, organisationId);\n \n if (!isOrgAdmin && config.requireAll !== false) {\n throw new Error(`Organisation admin role required`);\n }\n }\n\n // Check event-app roles if event and app context provided\n if (config.eventAppRoles && config.eventAppRoles.length > 0 && eventId && appId) {\n const { isEventAdmin } = await import('./api');\n const isEventAdminUser = await isEventAdmin(userId, { organisationId, eventId, appId });\n \n if (!isEventAdminUser && config.requireAll !== false) {\n throw new Error(`Event admin role required`);\n }\n }\n\n // Log successful role check - only if we have a valid organisation ID\n if (organisationId) {\n const { emitAuditEvent } = await import('./audit');\n await emitAuditEvent({\n type: 'permission_check',\n userId,\n organisationId,\n eventId,\n appId,\n permission: 'role:check',\n decision: true,\n source: 'api',\n bypass: false,\n duration_ms: 0,\n metadata: {\n operation: 'role_guard'\n }\n });\n }\n\n // Execute handler\n return handler(...args);\n };\n}\n\n// ============================================================================\n// NEXT.JS MIDDLEWARE\n// ============================================================================\n\n/**\n * Next.js Middleware for RBAC\n * \n * Middleware that checks permissions before allowing access to pages.\n * \n * @param config - Middleware configuration\n * @returns Next.js middleware function\n * \n * @example\n * ```typescript\n * // middleware.ts\n * import { createRBACMiddleware } from '@jmruthers/pace-core/rbac';\n * \n * export default createRBACMiddleware({\n * protectedRoutes: [\n * { path: '/admin', permission: 'update:admin' },\n * { path: '/events', permission: 'read:events' },\n * ],\n * fallbackUrl: '/access-denied',\n * });\n * ```\n */\nexport function createRBACMiddleware(config: {\n protectedRoutes: Array<{\n path: string;\n permission: Permission;\n pageId?: UUID;\n }>;\n fallbackUrl?: string;\n}) {\n return async (req: { nextUrl: { pathname: string }; user?: { id: string }; organisationId?: string }, res: { redirect: (url: string) => void }, next: () => void) => {\n const { pathname } = req.nextUrl;\n const userId = req.user?.id;\n const organisationId = req.organisationId;\n\n if (!userId || !organisationId) {\n return res.redirect(config.fallbackUrl || '/login');\n }\n\n // Find matching protected route\n const protectedRoute = config.protectedRoutes.find(route => \n pathname.startsWith(route.path)\n );\n\n if (protectedRoute) {\n try {\n const { isPermitted } = await import('./api');\n const hasPermission = await isPermitted({\n userId,\n scope: { organisationId },\n permission: protectedRoute.permission,\n pageId: protectedRoute.pageId,\n });\n\n if (!hasPermission) {\n return res.redirect(config.fallbackUrl || '/access-denied');\n }\n } catch (_error) {\n // Permission check failed - error logged via RBAC logger\n return res.redirect(config.fallbackUrl || '/access-denied');\n }\n }\n\n next();\n };\n}\n\n// ============================================================================\n// EXPRESS MIDDLEWARE\n// ============================================================================\n\n/**\n * Express Middleware for RBAC\n * \n * Middleware that checks permissions for Express routes.\n * \n * @param config - Middleware configuration\n * @returns Express middleware function\n * \n * @example\n * ```typescript\n * import { createRBACExpressMiddleware } from '@jmruthers/pace-core/rbac';\n * \n * app.use(createRBACExpressMiddleware({\n * permission: 'read:api',\n * pageId: 'api-page-123',\n * }));\n * ```\n */\nexport function createRBACExpressMiddleware(config: {\n permission: Permission;\n pageId?: UUID;\n}) {\n return async (req: { user?: { id: string }; organisationId?: string; eventId?: string; appId?: string }, res: { status: (code: number) => { json: (data: object) => void } }, next: () => void) => {\n const userId = req.user?.id;\n const organisationId = req.organisationId;\n const eventId = req.eventId;\n const appId = req.appId;\n\n if (!userId || !organisationId) {\n return res.status(401).json({ error: 'User context required' });\n }\n\n try {\n const { isPermitted } = await import('./api');\n const hasPermission = await isPermitted({\n userId,\n scope: { organisationId, eventId, appId },\n permission: config.permission,\n pageId: config.pageId,\n });\n\n if (!hasPermission) {\n return res.status(403).json({ error: 'Permission denied' });\n }\n\n next();\n } catch (_error) {\n // Permission check failed - error logged via RBAC logger\n return res.status(500).json({ error: 'Permission check failed' });\n }\n };\n}\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Check if a user has a permission (synchronous cache check only)\n * \n * @param userId - User ID\n * @param scope - Permission scope\n * @param permission - Permission to check\n * @param pageId - Optional page ID\n * @returns True if permission is cached and granted\n */\nexport function hasPermissionCached(\n userId: UUID,\n scope: { organisationId: UUID; eventId?: string; appId?: UUID },\n _permission: Permission,\n _pageId?: UUID\n): boolean {\n const cacheKey = RBACCache.generatePermissionKey({\n userId,\n organisationId: scope.organisationId,\n eventId: scope.eventId,\n appId: scope.appId,\n });\n \n return rbacCache.get<boolean>(cacheKey) || false;\n}\n\n/**\n * Check if a user has any of the specified permissions (synchronous cache check only)\n * \n * @param userId - User ID\n * @param scope - Permission scope\n * @param permissions - Array of permissions to check\n * @param pageId - Optional page ID\n * @returns True if any permission is cached and granted\n */\nexport function hasAnyPermissionCached(\n userId: UUID,\n scope: { organisationId: UUID; eventId?: string; appId?: UUID },\n permissions: Permission[],\n pageId?: UUID\n): boolean {\n return permissions.some(permission => \n hasPermissionCached(userId, scope, permission, pageId)\n );\n}\n\n// Import useAccessLevel for AccessLevelGuard\nimport { useAccessLevel } from './hooks';\n","/**\n * RBAC Permissions Definitions\n * @package @jmruthers/pace-core\n * @module RBAC/Permissions\n * @since 1.0.0\n * \n * This module defines all permissions used in the RBAC system.\n * All permission strings must be imported from this file to ensure consistency.\n */\n\nimport { Permission } from './types';\n\n// ============================================================================\n// GLOBAL PERMISSIONS\n// ============================================================================\n\nexport const GLOBAL_PERMISSIONS = {\n READ_ALL: 'read:*' as Permission,\n CREATE_ALL: 'create:*' as Permission,\n UPDATE_ALL: 'update:*' as Permission,\n DELETE_ALL: 'delete:*' as Permission,\n} as const;\n\n// ============================================================================\n// ORGANISATION PERMISSIONS\n// ============================================================================\n\nexport const ORGANISATION_PERMISSIONS = {\n // Organisation management\n READ_ORGANISATION: 'read:organisation' as Permission,\n UPDATE_ORGANISATION: 'update:organisation' as Permission,\n DELETE_ORGANISATION: 'delete:organisation' as Permission,\n \n // User management\n READ_USERS: 'read:users' as Permission,\n CREATE_USERS: 'create:users' as Permission,\n UPDATE_USERS: 'update:users' as Permission,\n DELETE_USERS: 'delete:users' as Permission,\n \n // Role management\n READ_ROLES: 'read:roles' as Permission,\n CREATE_ROLES: 'create:roles' as Permission,\n UPDATE_ROLES: 'update:roles' as Permission,\n DELETE_ROLES: 'delete:roles' as Permission,\n \n // Event management\n READ_EVENTS: 'read:events' as Permission,\n CREATE_EVENTS: 'create:events' as Permission,\n UPDATE_EVENTS: 'update:events' as Permission,\n DELETE_EVENTS: 'delete:events' as Permission,\n \n // App management\n READ_APPS: 'read:apps' as Permission,\n CREATE_APPS: 'create:apps' as Permission,\n UPDATE_APPS: 'update:apps' as Permission,\n DELETE_APPS: 'delete:apps' as Permission,\n} as const;\n\n// ============================================================================\n// EVENT-APP PERMISSIONS\n// ============================================================================\n\nexport const EVENT_APP_PERMISSIONS = {\n // Event management\n READ_EVENT: 'read:event' as Permission,\n CREATE_EVENT: 'create:event' as Permission,\n UPDATE_EVENT: 'update:event' as Permission,\n DELETE_EVENT: 'delete:event' as Permission,\n \n // App management\n READ_APP: 'read:app' as Permission,\n CREATE_APP: 'create:app' as Permission,\n UPDATE_APP: 'update:app' as Permission,\n DELETE_APP: 'delete:app' as Permission,\n \n // Team management\n READ_TEAM: 'read:team' as Permission,\n CREATE_TEAM: 'create:team' as Permission,\n UPDATE_TEAM: 'update:team' as Permission,\n DELETE_TEAM: 'delete:team' as Permission,\n \n // Team members\n READ_TEAM_MEMBERS: 'read:team.members' as Permission,\n CREATE_TEAM_MEMBERS: 'create:team.members' as Permission,\n UPDATE_TEAM_MEMBERS: 'update:team.members' as Permission,\n DELETE_TEAM_MEMBERS: 'delete:team.members' as Permission,\n \n // Event content\n READ_EVENT_CONTENT: 'read:event.content' as Permission,\n CREATE_EVENT_CONTENT: 'create:event.content' as Permission,\n UPDATE_EVENT_CONTENT: 'update:event.content' as Permission,\n DELETE_EVENT_CONTENT: 'delete:event.content' as Permission,\n \n // Event settings\n READ_EVENT_SETTINGS: 'read:event.settings' as Permission,\n CREATE_EVENT_SETTINGS: 'create:event.settings' as Permission,\n UPDATE_EVENT_SETTINGS: 'update:event.settings' as Permission,\n DELETE_EVENT_SETTINGS: 'delete:event.settings' as Permission,\n} as const;\n\n// ============================================================================\n// PAGE PERMISSIONS\n// ============================================================================\n\nexport const PAGE_PERMISSIONS = {\n // General page access\n READ_PAGE: 'read:page' as Permission,\n CREATE_PAGE: 'create:page' as Permission,\n UPDATE_PAGE: 'update:page' as Permission,\n DELETE_PAGE: 'delete:page' as Permission,\n \n // Admin pages\n READ_ADMIN: 'read:admin' as Permission,\n CREATE_ADMIN: 'create:admin' as Permission,\n UPDATE_ADMIN: 'update:admin' as Permission,\n DELETE_ADMIN: 'delete:admin' as Permission,\n \n // Dashboard pages\n READ_DASHBOARD: 'read:dashboard' as Permission,\n CREATE_DASHBOARD: 'create:dashboard' as Permission,\n UPDATE_DASHBOARD: 'update:dashboard' as Permission,\n DELETE_DASHBOARD: 'delete:dashboard' as Permission,\n \n // Settings pages\n READ_SETTINGS: 'read:settings' as Permission,\n CREATE_SETTINGS: 'create:settings' as Permission,\n UPDATE_SETTINGS: 'update:settings' as Permission,\n DELETE_SETTINGS: 'delete:settings' as Permission,\n \n // Reports pages\n READ_REPORTS: 'read:reports' as Permission,\n CREATE_REPORTS: 'create:reports' as Permission,\n UPDATE_REPORTS: 'update:reports' as Permission,\n DELETE_REPORTS: 'delete:reports' as Permission,\n} as const;\n\n// ============================================================================\n// PERMISSION GROUPS - REMOVED\n// ============================================================================\n// NOTE: Hardcoded permission groups have been removed to ensure RBAC compliance.\n// Permissions must be queried from the rbac_page_permissions database table.\n// This ensures organizations can customize their own page-level permissions.\n// The permission string constants above can still be used for TypeScript\n// type safety and autocomplete, but actual permission grants come from the database.\n\n// ============================================================================\n// PERMISSION VALIDATION\n// ============================================================================\n\n/**\n * Validate that a permission string is properly formatted\n * \n * @param permission - Permission string to validate\n * @returns True if valid, false otherwise\n */\nexport function isValidPermission(permission: string): permission is Permission {\n // Allow wildcard only at the end: read:* or read:events\n // But not: read:events* or read:*events\n // Also reject uppercase operations and resource names\n // NOTE: Only CRUD operations are allowed (read, create, update, delete)\n // Resource names must be lowercase letters, numbers, and dots only\n // Cannot start or end with dots, cannot have consecutive dots\n const pattern = /^(read|create|update|delete):[a-z0-9]+(\\.[a-z0-9]+)*$|^(read|create|update|delete):\\*$/;\n return pattern.test(permission);\n}\n\n/**\n * Get all permissions for a role - REMOVED\n * \n * @deprecated This function has been removed to ensure RBAC compliance.\n * Permissions must be queried from the rbac_page_permissions database table,\n * not hardcoded in application code. This allows organizations to customize\n * their own page-level permissions as required by the RBAC specification.\n * \n * To get permissions for a role, query the database:\n * ```typescript\n * const { data } = await supabase\n * .from('rbac_page_permissions')\n * .select('operation, allowed')\n * .eq('role_name', roleName)\n * .eq('organisation_id', organisationId)\n * .eq('allowed', true);\n * ```\n * \n * @param role - Role name\n * @returns Empty array (function deprecated)\n */\nexport function getPermissionsForRole(role: string): Permission[] {\n console.warn(\n '[RBAC] getPermissionsForRole() is deprecated. ' +\n 'Permissions must be queried from rbac_page_permissions table. ' +\n `Called with role: ${role}`\n );\n return [];\n}\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport const ALL_PERMISSIONS = {\n ...GLOBAL_PERMISSIONS,\n ...ORGANISATION_PERMISSIONS,\n ...EVENT_APP_PERMISSIONS,\n ...PAGE_PERMISSIONS,\n} as const;\n\nexport type AllPermissions = typeof ALL_PERMISSIONS;\n"],"mappings":"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","names":["useMemo","useEffect","useState","jsx","useMemo","useState","useEffect","error","createContext","useContext","useState","useCallback","useMemo","useEffect","jsx","createContext","useState","useMemo","useCallback","useEffect","useContext","useMemo","useEffect","useState","Fragment","jsx","jsxs","DefaultAccessDenied","DefaultLoading","useState","useEffect","error","useMemo","useMemo","useCallback","useEffect","useState","createContext","useContext","jsx","jsxs","createContext","useState","useMemo","useCallback","useEffect","useContext","createContext","useContext","useState","useCallback","useMemo","useEffect","jsx","createContext","useState","useMemo","useCallback","useEffect","useContext","useMemo","useEffect","useState","Fragment","jsx","jsxs","DefaultAccessDenied","DefaultLoading","useState","useEffect","error","useMemo","useMemo","useCallback","useEffect","useState","jsx","jsxs","useState","useMemo","useCallback","useEffect","Fragment","jsx","error","isPermitted","hasPermission","getAccessLevel","emitAuditEvent"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useOrganisationSecurity.ts","../src/hooks/useOrganisationPermissions.ts","../src/hooks/public/usePublicEvent.ts","../src/hooks/public/usePublicRouteParams.ts"],"sourcesContent":["/**\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';\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?: any) => 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 console.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 console.error('[useOrganisationSecurity] Error validating organisation access:', error);\n return false;\n }\n\n return !!data;\n } catch (error) {\n console.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\n const { isPermitted } = 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 isPermitted({\n userId: user.id,\n scope,\n permission: permission as Permission\n });\n } catch (error) {\n console.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 console.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?: any): 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 console.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 console.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 '../providers/OrganisationProvider';\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 * @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/unified';\nimport type { Database } from '../../types/database';\nimport { usePublicPageContext } from '../../components/PublicLayout/PublicPageProvider';\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_ANON_KEY || (import.meta as any).env?.NEXT_PUBLIC_SUPABASE_ANON_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 console.warn('[usePublicEvent] Missing Supabase environment variables. Please ensure VITE_SUPABASE_URL and VITE_SUPABASE_ANON_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 console.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 console.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 console.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 console.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: eventData.organisation_id,\n is_visible: true,\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n // Legacy compatibility\n name: eventData.event_name,\n start_date: eventData.event_date\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 console.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 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/unified';\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":["useMemo","useMemo","useState","useEffect","useCallback","useMemo","useState","useMemo","useCallback","error","useEffect","useState","useCallback","useMemo","useState","useMemo","useCallback"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/theming/parseEventColours.ts","../src/theming/runtime.ts"],"sourcesContent":["/**\n * @file Event Colours Parser\n * @package @jmruthers/pace-core\n * @module Theming/ParseEventColours\n * @since 2.0.0\n * \n * Shared utility for parsing and normalizing event_colours from database.\n * Handles multiple input formats and ensures consistent palette structure.\n * \n * Supports:\n * - Object format: { main: {...}, sec: {...}, acc: {...} }\n * - String format: JSON string that will be parsed\n * - Legacy format: { \"ev-main\": {...}, \"ev-sec\": {...}, \"ev-acc\": {...} }\n * \n * The function only includes explicitly defined color values, ensuring\n * that undefined shades are not included in the palette.\n * \n * @example\n * ```ts\n * import { parseAndNormalizeEventColours } from '@jmruthers/pace-core/theming/parseEventColours';\n * \n * const palette = parseAndNormalizeEventColours(event.event_colours);\n * if (palette) {\n * applyPalette(palette);\n * }\n * ```\n */\n\n/**\n * Parse and normalize event_colours to PaletteData\n * \n * Supports multiple input formats:\n * - Object with 'main', 'sec', 'acc' keys\n * - Object with 'ev-main', 'ev-sec', 'ev-acc' keys (legacy)\n * - JSON string that will be parsed\n * \n * Only includes explicitly defined color values. Does not fill\n * missing shades - only shades that are present in the input will\n * be included in the output.\n * \n * @param input - Event colours from database (JSONB field)\n * @returns Normalized palette data with main, sec, acc palettes, or null if invalid\n * \n * @example\n * ```ts\n * // Standard format\n * const colours = {\n * main: { 500: { L: 0.5, C: 0.2, H: 0 }, raw: { L: 0.5, C: 0.2, H: 0 } },\n * sec: { 500: { L: 0.5, C: 0.2, H: 120 } },\n * acc: { 500: { L: 0.5, C: 0.2, H: 240 } }\n * };\n * const palette = parseAndNormalizeEventColours(colours);\n * // Returns: { main: { 500: {...}, raw: {...} }, sec: { 500: {...} }, acc: { 500: {...} } }\n * ```\n * \n * @example\n * ```ts\n * // Legacy format with ev-* keys\n * const colours = {\n * \"ev-main\": { 500: { L: 0.5, C: 0.2, H: 0 } },\n * \"ev-sec\": { 500: { L: 0.5, C: 0.2, H: 120 } },\n * \"ev-acc\": { 500: { L: 0.5, C: 0.2, H: 240 } }\n * };\n * const palette = parseAndNormalizeEventColours(colours);\n * // Returns normalized palette with only defined shades included\n * ```\n */\nexport function parseAndNormalizeEventColours(input: unknown): { main: any; sec: any; acc: any } | null {\n try {\n if (!input) return null;\n let obj: any = input;\n \n // Handle string input (JSON string from database)\n if (typeof input === 'string') {\n try {\n obj = JSON.parse(input);\n } catch {\n return null;\n }\n } else if (typeof input !== 'object') {\n return null;\n }\n\n // Support both 'ev-main'/'ev-sec'/'ev-acc' (legacy) and 'main'/'sec'/'acc' (standard) keys\n // Prefer standard keys over legacy keys when both exist\n const pick = (o: any, standard: string, legacy: string) => (o?.[standard] ?? o?.[legacy]) || null;\n const main = pick(obj, 'main', 'ev-main');\n const sec = pick(obj, 'sec', 'ev-sec');\n const acc = pick(obj, 'acc', 'ev-acc');\n \n // If no palette data found, return null\n if (!main && !sec && !acc) return null;\n\n // Helper: only include explicitly defined color values\n // This ensures we don't include undefined shades in the palette\n const fill = (p: any) => {\n if (!p || typeof p !== 'object') return {} as any;\n const out: any = {};\n \n // Only include shades that are explicitly defined in the input\n // Iterate over all keys in the palette object\n for (const key in p) {\n // Only include the key if it has a defined value (not null, undefined, or empty)\n const value = p[key];\n if (value !== null && value !== undefined && value !== '') {\n out[key] = value;\n }\n }\n \n return out;\n };\n\n return { \n main: fill(main), \n sec: fill(sec), \n acc: fill(acc) \n };\n } catch (error) {\n console.warn('[parseEventColours] Failed to parse/normalize event colours:', error);\n return null;\n }\n}\n\n","/**\n * @file PACE Core Theming Runtime\n * @package @jmruthers/pace-core\n * @module Theming/Runtime\n * @since 2.0.0\n * \n * Runtime helpers for palette replacement from organisation/event payloads.\n * Provides simple applyPalette() and clearPalette() API with SSR support.\n * \n * @example\n * ```ts\n * import { applyPalette, clearPalette } from '@jmruthers/pace-core/theming/runtime';\n * \n * // Apply organisation colors\n * applyPalette({\n * main: { // main palette shades\n * 50: { L: 0.95, C: 0.02, H: 0 },\n * 500: { L: 0.5, C: 0.2, H: 0 }\n * },\n * sec: { // secondary palette shades\n * 50: { L: 0.95, C: 0.02, H: 120 },\n * 500: { L: 0.5, C: 0.2, H: 120 }\n * },\n * acc: { // accent palette shades\n * 50: { L: 0.95, C: 0.02, H: 240 },\n * 500: { L: 0.5, C: 0.2, H: 240 }\n * }\n * });\n * \n * // Clear dynamic theming\n * clearPalette();\n * ```\n */\n\nexport interface ColorShade {\n L: number;\n C: number;\n H: number;\n}\n\nexport interface ColorPalette {\n [shade: string]: ColorShade;\n}\n\nexport interface PaletteData {\n main: ColorPalette;\n sec: ColorPalette;\n acc: ColorPalette;\n}\n\n/**\n * Converts OKLCH color data to CSS string\n */\nfunction formatOklchCss(color: ColorShade): string {\n return `oklch(${color.L} ${color.C} ${color.H})`;\n}\n\n/**\n * Applies a complete palette to the document by setting CSS variables on :root.\n * Uses document.documentElement.style.setProperty() for runtime updates.\n * \n * @param palette - Complete palette data with main, sec, and acc palettes\n */\nexport function applyPalette(palette: PaletteData): void {\n if (typeof document === 'undefined' || document === null) {\n if (typeof console !== 'undefined' && console?.warn) {\n console.warn('applyPalette: Document not available (SSR)');\n }\n return;\n }\n\n const root = document.documentElement;\n const main = palette.main || {};\n const sec = palette.sec || {};\n const acc = palette.acc || {};\n\n // Apply main palette\n if (main.raw) {\n root.style.setProperty('--color-main-raw', formatOklchCss(main.raw));\n }\n for (let i = 50; i <= 950; i += 50) {\n const shade = i.toString();\n if (main[shade]) {\n root.style.setProperty(`--color-main-${shade}`, formatOklchCss(main[shade]));\n }\n }\n\n // Apply sec palette\n if (sec.raw) {\n root.style.setProperty('--color-sec-raw', formatOklchCss(sec.raw));\n }\n for (let i = 50; i <= 950; i += 50) {\n const shade = i.toString();\n if (sec[shade]) {\n root.style.setProperty(`--color-sec-${shade}`, formatOklchCss(sec[shade]));\n }\n }\n\n // Apply acc palette\n if (acc.raw) {\n root.style.setProperty('--color-acc-raw', formatOklchCss(acc.raw));\n }\n for (let i = 50; i <= 950; i += 50) {\n const shade = i.toString();\n if (acc[shade]) {\n root.style.setProperty(`--color-acc-${shade}`, formatOklchCss(acc[shade]));\n }\n }\n\n}\n\n/**\n * Clears dynamic theming by removing CSS variables from :root.\n * This allows the browser to fall back to static CSS values.\n */\nexport function clearPalette(): void {\n if (typeof document === 'undefined' || document === null) {\n return;\n }\n\n const root = document.documentElement;\n const prefixes = ['--color-main-', '--color-sec-', '--color-acc-'];\n \n // Remove all dynamically set color variables\n for (let i = root.style.length - 1; i >= 0; i--) {\n const propertyName = root.style[i];\n if (prefixes.some(prefix => propertyName.startsWith(prefix))) {\n root.style.removeProperty(propertyName);\n }\n }\n}\n\n/**\n * Generates CSS for SSR rendering (for server-side rendering)\n * Creates a :root rule with all color variables\n */\nfunction generateThemeCSS(palette: PaletteData): string {\n // Handle null/undefined palette\n if (!palette) {\n throw new Error('Palette data is required');\n }\n \n const main = palette.main || {};\n const sec = palette.sec || {};\n const acc = palette.acc || {};\n \n let css = ':root {\\n';\n \n // MAIN palette\n css += ' /* MAIN */\\n';\n if (main.raw) {\n css += ` --color-main-raw: ${formatOklchCss(main.raw)};\\n`;\n }\n for (let i = 50; i <= 950; i += 50) {\n const shade = i.toString();\n if (main[shade]) {\n css += ` --color-main-${shade}: ${formatOklchCss(main[shade])};\\n`;\n }\n }\n \n // SEC palette\n css += ' /* SEC */\\n';\n if (sec.raw) {\n css += ` --color-sec-raw: ${formatOklchCss(sec.raw)};\\n`;\n }\n for (let i = 50; i <= 950; i += 50) {\n const shade = i.toString();\n if (sec[shade]) {\n css += ` --color-sec-${shade}: ${formatOklchCss(sec[shade])};\\n`;\n }\n }\n \n // ACC palette\n css += ' /* ACC */\\n';\n if (acc.raw) {\n css += ` --color-acc-raw: ${formatOklchCss(acc.raw)};\\n`;\n }\n for (let i = 50; i <= 950; i += 50) {\n const shade = i.toString();\n if (acc[shade]) {\n css += ` --color-acc-${shade}: ${formatOklchCss(acc[shade])};\\n`;\n }\n }\n \n css += '}\\n';\n \n return css;\n}\n\n/**\n * Generates the same CSS block for SSR rendering\n * Use this in your SSR setup to avoid FOUC\n */\nexport function generateSSRThemeCSS(palette: PaletteData): string {\n return generateThemeCSS(palette);\n}\n\n/**\n * Checks if dynamic theming is currently active\n */\nexport function isDynamicThemingActive(): boolean {\n if (typeof document === 'undefined' || document === null) {\n return false;\n }\n \n const root = document.documentElement;\n // Check if any color variables are set on :root\n return root.style.getPropertyValue('--color-main-500') !== '';\n}\n\n/**\n * Gets the current dynamic theme data (if any)\n * Useful for debugging or persistence\n */\nexport function getCurrentThemeData(): PaletteData | null {\n if (typeof document === 'undefined' || document === null) {\n return null;\n }\n\n const root = document.documentElement;\n const main: ColorPalette = {};\n const sec: ColorPalette = {};\n const acc: ColorPalette = {};\n\n // Extract CSS variables from :root\n // This is a simplified implementation\n // In a real scenario, you might want to parse the actual color values\n // For now, we'll return null as the theme data isn't easily extractable\n return null;\n}\n\n// Re-export parseEventColours utility for convenience\nexport { parseAndNormalizeEventColours } from './parseEventColours';"],"mappings":"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","names":[]}
|