@jmruthers/pace-core 0.6.5 → 0.6.7
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/CHANGELOG.md +104 -0
- package/README.md +5 -403
- package/audit-tool/00-dependencies.cjs +394 -0
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +255 -0
- package/audit-tool/audits/03-architecture.cjs +196 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +544 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +291 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +241 -0
- package/core-usage-manifest.json +93 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/01-pace-core-compliance.mdc +586 -0
- package/cursor-rules/02-project-structure.mdc +42 -4
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
- package/cursor-rules/06-security-rbac.mdc +518 -0
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/DataTable-7PMH7XN7.js +15 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
- package/dist/chunk-6F3IILHI.js +62 -0
- package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
- package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
- package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
- package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
- package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/chunk-GHYHJTYV.js +994 -0
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
- package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
- package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
- package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
- package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
- package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
- package/dist/components.d.ts +7 -5
- package/dist/components.js +46 -257
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +35 -0
- package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
- package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/eslint-rules/utils/helpers.cjs +42 -0
- package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/dist/hooks.d.ts +6 -6
- package/dist/hooks.js +62 -172
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +12 -11
- package/dist/index.js +67 -660
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +8 -35
- package/dist/rbac/eslint-rules.d.ts +46 -44
- package/dist/rbac/eslint-rules.js +7 -4
- package/dist/rbac/index.d.ts +109 -586
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- package/dist/theming/runtime.d.ts +14 -1
- package/dist/theming/runtime.js +3 -19
- package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
- package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +17 -7
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +301 -871
- package/docs/api-reference/components.md +21 -21
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/rpc-functions.md +78 -3
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/installation-guide.md +20 -7
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/getting-started/quick-start.md +23 -12
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +126 -33
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +5 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +17 -8
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/edge-functions-guide.md +376 -0
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -35
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/1-pace-core-compliance-standards.md +986 -0
- package/docs/standards/2-project-structure-standards.md +949 -0
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/5-styling-standards.md +348 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +185 -57
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +33 -6
- package/package.json +35 -23
- package/scripts/install-cursor-rules.cjs +25 -6
- package/scripts/install-eslint-config.cjs +284 -0
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +106 -119
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +12 -9
- package/src/components/DataTable/components/EmptyState.tsx +10 -9
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/RowComponent.tsx +12 -0
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
- package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
- package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
- package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
- package/src/components/DataTable/types.ts +5 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +10 -9
- package/src/components/Dialog/Dialog.test.tsx +128 -104
- package/src/components/Dialog/Dialog.tsx +742 -24
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
- package/src/components/FileDisplay/FileDisplay.tsx +23 -17
- package/src/components/FileUpload/FileUpload.test.tsx +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- package/src/components/Form/Form.test.tsx +6 -8
- package/src/components/Form/Form.tsx +365 -4
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +109 -98
- package/src/components/Select/types.ts +4 -1
- package/src/components/UserMenu/UserMenu.tsx +9 -6
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
- package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
- package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
- package/src/hooks/public/usePublicEvent.ts +67 -195
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +24 -14
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +5 -5
- package/src/hooks/useAppConfig.ts +28 -26
- package/src/hooks/useEventTheme.test.ts +217 -239
- package/src/hooks/useEventTheme.ts +16 -28
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useOrganisationPermissions.ts +5 -7
- package/src/hooks/useQueryCache.ts +0 -1
- package/src/hooks/useSessionDraft.ts +380 -0
- package/src/hooks/useSessionRestoration.ts +3 -1
- package/src/icons/index.ts +27 -0
- package/src/index.ts +5 -0
- package/src/providers/OrganisationProvider.tsx +23 -14
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
- package/src/rbac/adapters.tsx +7 -295
- package/src/rbac/api.test.ts +44 -56
- package/src/rbac/api.ts +10 -17
- package/src/rbac/cache-invalidation.ts +0 -1
- package/src/rbac/compliance/index.ts +10 -0
- package/src/rbac/compliance/pattern-detector.ts +553 -0
- package/src/rbac/compliance/runtime-compliance.ts +22 -0
- package/src/rbac/components/AccessDenied.tsx +150 -0
- package/src/rbac/components/NavigationGuard.tsx +12 -20
- package/src/rbac/components/PagePermissionGuard.tsx +4 -24
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
- package/src/rbac/components/index.ts +3 -41
- package/src/rbac/eslint-rules.js +1 -1
- package/src/rbac/hooks/index.ts +0 -3
- package/src/rbac/hooks/permissions/index.ts +0 -3
- package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
- package/src/rbac/hooks/usePermissions.ts +0 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
- package/src/rbac/hooks/useResolvedScope.ts +58 -140
- package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
- package/src/rbac/hooks/useResourcePermissions.ts +139 -48
- package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
- package/src/rbac/hooks/useRoleManagement.ts +147 -19
- package/src/rbac/hooks/useSecureSupabase.ts +4 -8
- package/src/rbac/index.ts +7 -9
- package/src/rbac/utils/contextValidator.ts +9 -7
- package/src/services/AuthService.ts +130 -18
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +16 -0
- package/src/services/OrganisationService.ts +7 -44
- package/src/services/__tests__/OrganisationService.test.ts +26 -8
- package/src/services/base/BaseService.ts +0 -3
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +9 -3
- package/src/theming/parseEventColours.ts +22 -10
- package/src/types/database.generated.ts +4733 -3809
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
- package/src/utils/context/organisationContext.test.ts +13 -28
- package/src/utils/context/organisationContext.ts +21 -52
- package/src/utils/dynamic/dynamicUtils.ts +1 -1
- package/src/utils/file-reference/index.ts +39 -15
- package/src/utils/formatting/formatDateTime.test.ts +3 -2
- package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
- package/src/utils/index.ts +4 -1
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
- package/src/utils/persistence/keyDerivation.ts +304 -0
- package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
- package/src/utils/security/secureStorage.ts +5 -5
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/helpers.ts +3 -3
- package/src/utils/supabase/createBaseClient.ts +147 -0
- package/src/utils/timezone/timezone.test.ts +1 -2
- package/src/utils/timezone/timezone.ts +1 -1
- package/src/utils/validation/csrf.ts +4 -4
- package/cursor-rules/00-pace-core-compliance.mdc +0 -331
- package/cursor-rules/01-standards-compliance.mdc +0 -244
- package/cursor-rules/04-testing-standards.mdc +0 -268
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
- package/cursor-rules/06-code-quality.mdc +0 -309
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
- package/cursor-rules/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-AOVNCPTX.js +0 -175
- package/dist/DataTable-AOVNCPTX.js.map +0 -1
- package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
- package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
- package/dist/api-O6HTBX5Y.js +0 -52
- package/dist/api-O6HTBX5Y.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6COVEUS7.js.map +0 -1
- package/dist/chunk-AFVQODI2.js +0 -263
- package/dist/chunk-AFVQODI2.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.js.map +0 -1
- package/dist/chunk-EFN2EIMK.js.map +0 -1
- package/dist/chunk-FFQEQTNW.js.map +0 -1
- package/dist/chunk-FMUCXFII.js.map +0 -1
- package/dist/chunk-G37KK66H.js.map +0 -1
- package/dist/chunk-G7QEZTYQ.js +0 -2053
- package/dist/chunk-G7QEZTYQ.js.map +0 -1
- package/dist/chunk-HU2C6SSC.js.map +0 -1
- package/dist/chunk-IHB5DR3H.js.map +0 -1
- package/dist/chunk-IVOFDYWT.js.map +0 -1
- package/dist/chunk-J36DSWQK.js.map +0 -1
- package/dist/chunk-JGRYX5UX.js.map +0 -1
- package/dist/chunk-KQCRWDSA.js +0 -1
- package/dist/chunk-KQCRWDSA.js.map +0 -1
- package/dist/chunk-L4OXEN46.js.map +0 -1
- package/dist/chunk-LMC26NLJ.js +0 -84
- package/dist/chunk-LMC26NLJ.js.map +0 -1
- package/dist/chunk-M43Y4SSO.js.map +0 -1
- package/dist/chunk-M7MPQISP.js.map +0 -1
- package/dist/chunk-NTM7ZSB6.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-RGAWHO7N.js.map +0 -1
- package/dist/chunk-UPPMRMYG.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-5OGXSPKS.js +0 -9
- package/dist/contextValidator-5OGXSPKS.js.map +0 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
- package/dist/hooks.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers.js.map +0 -1
- package/dist/rbac/eslint-rules.js.map +0 -1
- package/dist/rbac/index.js.map +0 -1
- package/dist/styles/index.js.map +0 -1
- package/dist/theming/runtime.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -601
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- package/docs/standards/01-architecture-standard.md +0 -44
- package/docs/standards/02-api-and-rpc-standard.md +0 -39
- package/docs/standards/03-component-standard.md +0 -32
- package/docs/standards/04-code-style-standard.md +0 -32
- package/docs/standards/05-security-standard.md +0 -44
- package/docs/standards/06-testing-and-docs-standard.md +0 -29
- package/docs/standards/pace-core-compliance.md +0 -432
- package/scripts/audit/core/checks/accessibility.cjs +0 -197
- package/scripts/audit/core/checks/api-usage.cjs +0 -191
- package/scripts/audit/core/checks/bundle.cjs +0 -142
- package/scripts/audit/core/checks/compliance.cjs +0 -2706
- package/scripts/audit/core/checks/config.cjs +0 -54
- package/scripts/audit/core/checks/coverage.cjs +0 -84
- package/scripts/audit/core/checks/dependencies.cjs +0 -994
- package/scripts/audit/core/checks/documentation.cjs +0 -268
- package/scripts/audit/core/checks/environment.cjs +0 -116
- package/scripts/audit/core/checks/error-handling.cjs +0 -340
- package/scripts/audit/core/checks/forms.cjs +0 -172
- package/scripts/audit/core/checks/heuristics.cjs +0 -68
- package/scripts/audit/core/checks/hooks.cjs +0 -334
- package/scripts/audit/core/checks/imports.cjs +0 -244
- package/scripts/audit/core/checks/performance.cjs +0 -325
- package/scripts/audit/core/checks/routes.cjs +0 -117
- package/scripts/audit/core/checks/state.cjs +0 -130
- package/scripts/audit/core/checks/structure.cjs +0 -65
- package/scripts/audit/core/checks/style.cjs +0 -584
- package/scripts/audit/core/checks/testing.cjs +0 -122
- package/scripts/audit/core/checks/typescript.cjs +0 -61
- package/scripts/audit/core/scanner.cjs +0 -199
- package/scripts/audit/core/utils.cjs +0 -137
- package/scripts/audit/index.cjs +0 -223
- package/scripts/audit/reporters/console.cjs +0 -151
- package/scripts/audit/reporters/json.cjs +0 -54
- package/scripts/audit/reporters/markdown.cjs +0 -124
- package/scripts/audit-consuming-app.cjs +0 -86
- package/src/components/DataTable/components/DataTableBody.tsx +0 -454
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- package/src/eslint-rules/pace-core-compliance.js +0 -638
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
- package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
- package/src/rbac/components/NavigationProvider.test.tsx +0 -481
- package/src/rbac/components/NavigationProvider.tsx +0 -345
- package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
- package/src/rbac/components/PagePermissionProvider.tsx +0 -279
- package/src/rbac/components/PermissionEnforcer.tsx +0 -312
- package/src/rbac/components/RoleBasedRouter.tsx +0 -440
- package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
- package/src/rbac/components/SecureDataProvider.tsx +0 -339
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
|
@@ -1,440 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Role Based Router Component
|
|
3
|
-
* @package @jmruthers/pace-core
|
|
4
|
-
* @module RBAC/Components/RoleBasedRouter
|
|
5
|
-
* @since 2.0.0
|
|
6
|
-
*
|
|
7
|
-
* A component that provides centralized routing control and prevents apps from
|
|
8
|
-
* implementing custom routing that bypasses permission checks. This is a critical
|
|
9
|
-
* security component that ensures all routes are properly protected.
|
|
10
|
-
*
|
|
11
|
-
* Features:
|
|
12
|
-
* - Centralized routing control
|
|
13
|
-
* - Role-based route protection
|
|
14
|
-
* - Permission-based route filtering
|
|
15
|
-
* - Strict mode to prevent bypassing
|
|
16
|
-
* - Automatic audit logging
|
|
17
|
-
* - Integration with existing RBAC system
|
|
18
|
-
* - Clear error messages for unauthorized routes
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* ```tsx
|
|
22
|
-
* // Basic role-based routing
|
|
23
|
-
* <RoleBasedRouter
|
|
24
|
-
* routes={routeConfig}
|
|
25
|
-
* fallbackRoute="/unauthorized"
|
|
26
|
-
* strictMode={true}
|
|
27
|
-
* >
|
|
28
|
-
* <App />
|
|
29
|
-
* </RoleBasedRouter>
|
|
30
|
-
*
|
|
31
|
-
* // With custom configuration
|
|
32
|
-
* <RoleBasedRouter
|
|
33
|
-
* routes={routeConfig}
|
|
34
|
-
* fallbackRoute="/unauthorized"
|
|
35
|
-
* strictMode={true}
|
|
36
|
-
* auditLog={true}
|
|
37
|
-
* onRouteAccess={(route, allowed) => {
|
|
38
|
-
* console.log(`Route access: ${route} - ${allowed ? 'allowed' : 'denied'}`);
|
|
39
|
-
* }}
|
|
40
|
-
* >
|
|
41
|
-
* <App />
|
|
42
|
-
* </RoleBasedRouter>
|
|
43
|
-
* ```
|
|
44
|
-
*
|
|
45
|
-
* @security
|
|
46
|
-
* - Enforces route-level permissions
|
|
47
|
-
* - Prevents apps from bypassing route protection
|
|
48
|
-
* - Automatic audit logging for all route access attempts
|
|
49
|
-
* - Integration with existing RBAC system
|
|
50
|
-
* - Clear error messages for unauthorized routes
|
|
51
|
-
*
|
|
52
|
-
* @performance
|
|
53
|
-
* - Optimized with useMemo and useCallback
|
|
54
|
-
* - Cached permission checks
|
|
55
|
-
* - Minimal re-renders
|
|
56
|
-
* - Efficient route matching
|
|
57
|
-
*
|
|
58
|
-
* @dependencies
|
|
59
|
-
* - React 19+ - Component framework
|
|
60
|
-
* - React Router - Routing functionality
|
|
61
|
-
* - useCan hook - Permission checking
|
|
62
|
-
* - useUnifiedAuth - Authentication context
|
|
63
|
-
* - RBAC types - Type definitions
|
|
64
|
-
*/
|
|
65
|
-
|
|
66
|
-
import React, { useMemo, useCallback, useEffect, useState, createContext, useContext } from 'react';
|
|
67
|
-
import { useLocation, useNavigate, Outlet } from 'react-router-dom';
|
|
68
|
-
import { useCan } from '../hooks';
|
|
69
|
-
import { useResolvedScope } from '../hooks/useResolvedScope';
|
|
70
|
-
import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
|
|
71
|
-
import { UUID, Permission, Scope, AccessLevel } from '../types';
|
|
72
|
-
import { getRBACLogger } from '../config';
|
|
73
|
-
|
|
74
|
-
export interface RouteConfig {
|
|
75
|
-
/** Route path */
|
|
76
|
-
path: string;
|
|
77
|
-
|
|
78
|
-
/** React component to render */
|
|
79
|
-
component: React.ComponentType;
|
|
80
|
-
|
|
81
|
-
/** Permissions required for this route */
|
|
82
|
-
permissions: Permission[];
|
|
83
|
-
|
|
84
|
-
/** If true, this route is public and doesn't require permission checks */
|
|
85
|
-
public?: boolean;
|
|
86
|
-
|
|
87
|
-
/** Roles that can access this route */
|
|
88
|
-
roles?: string[];
|
|
89
|
-
|
|
90
|
-
/** Minimum access level required */
|
|
91
|
-
accessLevel?: AccessLevel;
|
|
92
|
-
|
|
93
|
-
/** Page ID for permission checking */
|
|
94
|
-
pageId?: string;
|
|
95
|
-
|
|
96
|
-
/** Enable strict mode for this route */
|
|
97
|
-
strictMode?: boolean;
|
|
98
|
-
|
|
99
|
-
/** Route metadata */
|
|
100
|
-
meta?: {
|
|
101
|
-
title?: string;
|
|
102
|
-
description?: string;
|
|
103
|
-
requiresAuth?: boolean;
|
|
104
|
-
hidden?: boolean;
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export interface RouteAccessRecord {
|
|
109
|
-
route: string;
|
|
110
|
-
permissions: Permission[];
|
|
111
|
-
userId: UUID;
|
|
112
|
-
scope: Scope;
|
|
113
|
-
allowed: boolean;
|
|
114
|
-
timestamp: string;
|
|
115
|
-
pageId?: string;
|
|
116
|
-
roles?: string[];
|
|
117
|
-
accessLevel?: AccessLevel;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export interface RoleBasedRouterContextType {
|
|
121
|
-
/** Get all accessible routes for current user */
|
|
122
|
-
getAccessibleRoutes: () => RouteConfig[];
|
|
123
|
-
|
|
124
|
-
/** Check if user can access a specific route */
|
|
125
|
-
canAccessRoute: (path: string) => boolean;
|
|
126
|
-
|
|
127
|
-
/** Get route configuration for a path */
|
|
128
|
-
getRouteConfig: (path: string) => RouteConfig | null;
|
|
129
|
-
|
|
130
|
-
/** Get route access history */
|
|
131
|
-
getRouteAccessHistory: () => RouteAccessRecord[];
|
|
132
|
-
|
|
133
|
-
/** Clear route access history */
|
|
134
|
-
clearRouteAccessHistory: () => void;
|
|
135
|
-
|
|
136
|
-
/** Check if strict mode is enabled */
|
|
137
|
-
isStrictMode: boolean;
|
|
138
|
-
|
|
139
|
-
/** Check if audit logging is enabled */
|
|
140
|
-
isAuditLogEnabled: boolean;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export interface RoleBasedRouterProps {
|
|
144
|
-
/** Route configuration */
|
|
145
|
-
routes: RouteConfig[];
|
|
146
|
-
|
|
147
|
-
/** Fallback route for unauthorized access */
|
|
148
|
-
fallbackRoute?: string;
|
|
149
|
-
|
|
150
|
-
/** Child components */
|
|
151
|
-
children: React.ReactNode;
|
|
152
|
-
|
|
153
|
-
/** Enable strict mode to prevent bypassing (default: true) */
|
|
154
|
-
strictMode?: boolean;
|
|
155
|
-
|
|
156
|
-
/** Enable audit logging (default: true) */
|
|
157
|
-
auditLog?: boolean;
|
|
158
|
-
|
|
159
|
-
/** Callback when route access is attempted */
|
|
160
|
-
onRouteAccess?: (route: string, allowed: boolean, record: RouteAccessRecord) => void;
|
|
161
|
-
|
|
162
|
-
/** Callback when strict mode violation occurs */
|
|
163
|
-
onStrictModeViolation?: (route: string, record: RouteAccessRecord) => void;
|
|
164
|
-
|
|
165
|
-
/** Maximum number of access records to keep in history */
|
|
166
|
-
maxHistorySize?: number;
|
|
167
|
-
|
|
168
|
-
/** Custom unauthorized component */
|
|
169
|
-
unauthorizedComponent?: React.ComponentType<{ route: string; reason: string }>;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const RoleBasedRouterContext = createContext<RoleBasedRouterContextType | null>(null);
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* RoleBasedRouter - Centralized routing control with role-based protection
|
|
176
|
-
*
|
|
177
|
-
* This component ensures that all routes are properly protected and provides
|
|
178
|
-
* centralized routing control to prevent apps from bypassing route protection.
|
|
179
|
-
*
|
|
180
|
-
* @param props - Router props
|
|
181
|
-
* @returns React element with role-based routing
|
|
182
|
-
*/
|
|
183
|
-
export function RoleBasedRouter({
|
|
184
|
-
routes,
|
|
185
|
-
fallbackRoute = '/unauthorized',
|
|
186
|
-
children,
|
|
187
|
-
strictMode = true,
|
|
188
|
-
auditLog = true,
|
|
189
|
-
onRouteAccess,
|
|
190
|
-
onStrictModeViolation,
|
|
191
|
-
maxHistorySize = 1000,
|
|
192
|
-
unauthorizedComponent: UnauthorizedComponent = DefaultUnauthorizedComponent
|
|
193
|
-
}: RoleBasedRouterProps) {
|
|
194
|
-
const { user, selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();
|
|
195
|
-
const location = useLocation();
|
|
196
|
-
const navigate = useNavigate();
|
|
197
|
-
const [routeAccessHistory, setRouteAccessHistory] = useState<RouteAccessRecord[]>([]);
|
|
198
|
-
const [currentRoute, setCurrentRoute] = useState<string>('');
|
|
199
|
-
|
|
200
|
-
// Use useResolvedScope to get proper scope (org derived from event if needed)
|
|
201
|
-
const { resolvedScope } = useResolvedScope({
|
|
202
|
-
supabase,
|
|
203
|
-
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
204
|
-
selectedEventId: selectedEvent?.event_id || null
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// Get current scope from resolved scope
|
|
208
|
-
// For event-required apps: org is derived from event
|
|
209
|
-
// For org-required apps: org comes from selectedOrganisation
|
|
210
|
-
const currentScope = resolvedScope;
|
|
211
|
-
|
|
212
|
-
// Get route configuration for current path
|
|
213
|
-
const currentRouteConfig = useMemo((): RouteConfig | null => {
|
|
214
|
-
const currentPath = location.pathname;
|
|
215
|
-
return routes.find(route => route.path === currentPath) || null;
|
|
216
|
-
}, [routes, location.pathname]);
|
|
217
|
-
|
|
218
|
-
// Check if user can access a specific route
|
|
219
|
-
const canAccessRoute = useCallback((path: string): boolean => {
|
|
220
|
-
if (!user?.id || !currentScope) return false;
|
|
221
|
-
|
|
222
|
-
const routeConfig = routes.find(route => route.path === path);
|
|
223
|
-
if (!routeConfig) return false;
|
|
224
|
-
|
|
225
|
-
// Use the existing RBAC system to check route permissions
|
|
226
|
-
// This is a synchronous check for the context - actual permission checking
|
|
227
|
-
// happens in the individual route components using useCan hook
|
|
228
|
-
// For now, we'll return true and let the individual route components
|
|
229
|
-
// handle the actual permission checking asynchronously
|
|
230
|
-
return true;
|
|
231
|
-
}, [user?.id, currentScope, routes]);
|
|
232
|
-
|
|
233
|
-
// Use useCan hook for actual permission checking
|
|
234
|
-
// Pass null for super admin status (not checked yet - hook will check if needed)
|
|
235
|
-
const { can: canAccessCurrentRoute, isLoading: permissionLoading } = useCan(
|
|
236
|
-
user?.id || '',
|
|
237
|
-
currentScope || { organisationId: '', eventId: undefined, appId: undefined },
|
|
238
|
-
currentRouteConfig?.permissions?.[0] || 'read:page',
|
|
239
|
-
currentRouteConfig?.pageId,
|
|
240
|
-
true, // useCache
|
|
241
|
-
null, // precomputedSuperAdmin - not checked yet
|
|
242
|
-
undefined // appName
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
// Check if route is public
|
|
246
|
-
const isPublicRoute = currentRouteConfig?.public === true;
|
|
247
|
-
|
|
248
|
-
// If route has no permissions and is not public, deny access (secure by default)
|
|
249
|
-
const hasPermissions = currentRouteConfig?.permissions && currentRouteConfig.permissions.length > 0;
|
|
250
|
-
const finalCanAccess = isPublicRoute ? true : (hasPermissions ? canAccessCurrentRoute : false);
|
|
251
|
-
const finalLoading = isPublicRoute ? false : (hasPermissions ? permissionLoading : false);
|
|
252
|
-
|
|
253
|
-
// Get all accessible routes for current user
|
|
254
|
-
const getAccessibleRoutes = useCallback((): RouteConfig[] => {
|
|
255
|
-
if (!user?.id || !currentScope) return [];
|
|
256
|
-
|
|
257
|
-
return routes.filter(route => canAccessRoute(route.path));
|
|
258
|
-
}, [user?.id, currentScope, routes, canAccessRoute]);
|
|
259
|
-
|
|
260
|
-
// Get route configuration for a path
|
|
261
|
-
const getRouteConfig = useCallback((path: string): RouteConfig | null => {
|
|
262
|
-
return routes.find(route => route.path === path) || null;
|
|
263
|
-
}, [routes]);
|
|
264
|
-
|
|
265
|
-
// Get route access history
|
|
266
|
-
const getRouteAccessHistory = useCallback((): RouteAccessRecord[] => {
|
|
267
|
-
return [...routeAccessHistory];
|
|
268
|
-
}, [routeAccessHistory]);
|
|
269
|
-
|
|
270
|
-
// Clear route access history
|
|
271
|
-
const clearRouteAccessHistory = useCallback(() => {
|
|
272
|
-
setRouteAccessHistory([]);
|
|
273
|
-
}, []);
|
|
274
|
-
|
|
275
|
-
// Record route access attempt
|
|
276
|
-
const recordRouteAccess = useCallback((
|
|
277
|
-
route: string,
|
|
278
|
-
allowed: boolean,
|
|
279
|
-
routeConfig: RouteConfig
|
|
280
|
-
) => {
|
|
281
|
-
if (!auditLog || !user?.id || !currentScope) return;
|
|
282
|
-
|
|
283
|
-
const record: RouteAccessRecord = {
|
|
284
|
-
route,
|
|
285
|
-
permissions: routeConfig.permissions,
|
|
286
|
-
userId: user.id,
|
|
287
|
-
scope: currentScope,
|
|
288
|
-
allowed,
|
|
289
|
-
timestamp: new Date().toISOString(),
|
|
290
|
-
pageId: routeConfig.pageId,
|
|
291
|
-
roles: routeConfig.roles,
|
|
292
|
-
accessLevel: routeConfig.accessLevel
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
setRouteAccessHistory(prev => {
|
|
296
|
-
const newHistory = [record, ...prev];
|
|
297
|
-
return newHistory.slice(0, maxHistorySize);
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
if (onRouteAccess) {
|
|
301
|
-
onRouteAccess(route, allowed, record);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
if (strictMode && !allowed && onStrictModeViolation) {
|
|
305
|
-
onStrictModeViolation(route, record);
|
|
306
|
-
}
|
|
307
|
-
}, [auditLog, user?.id, currentScope, maxHistorySize, onRouteAccess, onStrictModeViolation, strictMode]);
|
|
308
|
-
|
|
309
|
-
// Check route access on location change
|
|
310
|
-
useEffect(() => {
|
|
311
|
-
const currentPath = location.pathname;
|
|
312
|
-
setCurrentRoute(currentPath);
|
|
313
|
-
|
|
314
|
-
if (!currentRouteConfig) {
|
|
315
|
-
// Route not found in configuration
|
|
316
|
-
if (strictMode) {
|
|
317
|
-
const logger = getRBACLogger();
|
|
318
|
-
logger.error(`STRICT MODE VIOLATION: Route not found in configuration`, {
|
|
319
|
-
route: currentPath,
|
|
320
|
-
userId: user?.id,
|
|
321
|
-
timestamp: new Date().toISOString()
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
if (onStrictModeViolation) {
|
|
325
|
-
onStrictModeViolation(currentPath, {
|
|
326
|
-
route: currentPath,
|
|
327
|
-
permissions: [],
|
|
328
|
-
userId: user?.id || '',
|
|
329
|
-
scope: currentScope || { organisationId: '' },
|
|
330
|
-
allowed: false,
|
|
331
|
-
timestamp: new Date().toISOString()
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Use the actual permission check result
|
|
339
|
-
const allowed = finalCanAccess;
|
|
340
|
-
// Log route access (including public routes for audit monitoring)
|
|
341
|
-
recordRouteAccess(currentPath, allowed, currentRouteConfig);
|
|
342
|
-
|
|
343
|
-
if (!allowed && !isPublicRoute) {
|
|
344
|
-
// Redirect to fallback route (skip for public routes)
|
|
345
|
-
navigate(fallbackRoute, { replace: true });
|
|
346
|
-
}
|
|
347
|
-
}, [location.pathname, currentRouteConfig, canAccessCurrentRoute, recordRouteAccess, strictMode, user?.id, currentScope, onStrictModeViolation, navigate, fallbackRoute, isPublicRoute]);
|
|
348
|
-
|
|
349
|
-
// Context value
|
|
350
|
-
const contextValue = useMemo((): RoleBasedRouterContextType => ({
|
|
351
|
-
getAccessibleRoutes,
|
|
352
|
-
canAccessRoute,
|
|
353
|
-
getRouteConfig,
|
|
354
|
-
getRouteAccessHistory,
|
|
355
|
-
clearRouteAccessHistory,
|
|
356
|
-
isStrictMode: strictMode,
|
|
357
|
-
isAuditLogEnabled: auditLog
|
|
358
|
-
}), [
|
|
359
|
-
getAccessibleRoutes,
|
|
360
|
-
canAccessRoute,
|
|
361
|
-
getRouteConfig,
|
|
362
|
-
getRouteAccessHistory,
|
|
363
|
-
clearRouteAccessHistory,
|
|
364
|
-
strictMode,
|
|
365
|
-
auditLog
|
|
366
|
-
]);
|
|
367
|
-
|
|
368
|
-
// Show loading state while checking permissions (skip for public routes)
|
|
369
|
-
if (finalLoading && !isPublicRoute) {
|
|
370
|
-
return (
|
|
371
|
-
<div className="flex items-center justify-center min-h-screen">
|
|
372
|
-
<div className="text-center">
|
|
373
|
-
<div className="animate-spin rounded-full size-8 border-b-2 border-main-600 mx-auto mb-4"></div>
|
|
374
|
-
<p className="text-sec-600">Checking permissions...</p>
|
|
375
|
-
</div>
|
|
376
|
-
</div>
|
|
377
|
-
);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// Show unauthorized component if user can't access current route
|
|
381
|
-
if (currentRouteConfig && !finalCanAccess && !isPublicRoute) {
|
|
382
|
-
return (
|
|
383
|
-
<UnauthorizedComponent
|
|
384
|
-
route={currentRoute}
|
|
385
|
-
reason="Insufficient permissions"
|
|
386
|
-
/>
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
return (
|
|
390
|
-
<RoleBasedRouterContext.Provider value={contextValue}>
|
|
391
|
-
{children}
|
|
392
|
-
<Outlet />
|
|
393
|
-
</RoleBasedRouterContext.Provider>
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Hook to use role-based router context
|
|
399
|
-
*
|
|
400
|
-
* @returns Role-based router context
|
|
401
|
-
* @throws Error if used outside of RoleBasedRouter
|
|
402
|
-
*/
|
|
403
|
-
export function useRoleBasedRouter(): RoleBasedRouterContextType {
|
|
404
|
-
const context = useContext(RoleBasedRouterContext);
|
|
405
|
-
|
|
406
|
-
if (!context) {
|
|
407
|
-
throw new Error('useRoleBasedRouter must be used within a RoleBasedRouter');
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
return context;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* Default unauthorized component
|
|
415
|
-
*/
|
|
416
|
-
function DefaultUnauthorizedComponent({ route, reason }: { route: string; reason: string }) {
|
|
417
|
-
return (
|
|
418
|
-
<div className="flex flex-col items-center justify-center min-h-screen p-8 text-center">
|
|
419
|
-
<div className="mb-4">
|
|
420
|
-
<svg className="w-16 h-16 text-acc-500 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
421
|
-
<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" />
|
|
422
|
-
</svg>
|
|
423
|
-
</div>
|
|
424
|
-
<h2 className="text-xl font-semibold text-sec-900 mb-2">Access Denied</h2>
|
|
425
|
-
<p className="text-sec-600 mb-4">
|
|
426
|
-
You don't have permission to access <code className="bg-sec-100 px-2 py-1 rounded">{route}</code>
|
|
427
|
-
</p>
|
|
428
|
-
<p className="text-sm text-sec-500 mb-4">Reason: {reason}</p>
|
|
429
|
-
<button
|
|
430
|
-
onClick={() => window.history.back()}
|
|
431
|
-
className="px-4 py-2 bg-main-600 text-main-50 rounded-md hover:bg-main-700 transition-colors"
|
|
432
|
-
>
|
|
433
|
-
Go Back
|
|
434
|
-
</button>
|
|
435
|
-
</div>
|
|
436
|
-
);
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
export default RoleBasedRouter;
|
|
440
|
-
|