@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
package/src/rbac/adapters.tsx
CHANGED
|
@@ -4,254 +4,17 @@
|
|
|
4
4
|
* @module RBAC/Adapters
|
|
5
5
|
* @since 1.0.0
|
|
6
6
|
*
|
|
7
|
-
* This module provides adapters for different frameworks and server runtimes.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import React, { ReactNode } from 'react';
|
|
11
|
-
import { UUID, Permission } from './types';
|
|
12
|
-
import { useCan } from './hooks';
|
|
13
|
-
import { rbacCache, RBACCache } from './cache';
|
|
14
|
-
import { getRBACLogger } from './config';
|
|
15
|
-
import { useUnifiedAuth } from '../providers/services/UnifiedAuthProvider';
|
|
16
|
-
|
|
17
|
-
// ============================================================================
|
|
18
|
-
// REACT COMPONENTS
|
|
19
|
-
// ============================================================================
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Permission Guard Component
|
|
23
|
-
*
|
|
24
|
-
* A React component that conditionally renders children based on permissions.
|
|
25
|
-
* Can auto-infer userId from context if not provided.
|
|
7
|
+
* This module provides server-side adapters for different frameworks and server runtimes.
|
|
26
8
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* <PermissionGuard
|
|
31
|
-
* userId="user-123"
|
|
32
|
-
* scope={{ organisationId: 'org-456' }}
|
|
33
|
-
* permission="update:events"
|
|
34
|
-
* pageId="page-789"
|
|
35
|
-
* fallback={<AccessDenied />}
|
|
36
|
-
* >
|
|
37
|
-
* <AdminPanel />
|
|
38
|
-
* </PermissionGuard>
|
|
9
|
+
* NOTE: React components (PermissionGuard, AccessLevelGuard) have been removed.
|
|
10
|
+
* Use PagePermissionGuard from @jmruthers/pace-core/rbac for all client-side permission enforcement.
|
|
11
|
+
* Use useAccessLevel hook + conditional rendering for access level checks.
|
|
39
12
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* permission="update:events"
|
|
43
|
-
* scope={{ organisationId: 'org-456' }}
|
|
44
|
-
* fallback={<AccessDenied />}
|
|
45
|
-
* >
|
|
46
|
-
* <AdminPanel />
|
|
47
|
-
* </PermissionGuard>
|
|
48
|
-
* ```
|
|
13
|
+
* Server adapters are provided for server-side route protection (Next.js, Express, etc.).
|
|
14
|
+
* These are optional utilities for server-side applications.
|
|
49
15
|
*/
|
|
50
|
-
export function PermissionGuard({
|
|
51
|
-
userId,
|
|
52
|
-
scope,
|
|
53
|
-
permission,
|
|
54
|
-
pageId,
|
|
55
|
-
children,
|
|
56
|
-
fallback = null,
|
|
57
|
-
onDenied,
|
|
58
|
-
loading = null,
|
|
59
|
-
// NEW: Phase 1 - Enhanced Security Features
|
|
60
|
-
strictMode = true,
|
|
61
|
-
auditLog = true,
|
|
62
|
-
enforceAudit = true,
|
|
63
|
-
}: {
|
|
64
|
-
userId?: UUID;
|
|
65
|
-
scope: { organisationId: UUID; eventId?: string; appId?: UUID };
|
|
66
|
-
permission: Permission;
|
|
67
|
-
pageId?: UUID;
|
|
68
|
-
children: ReactNode;
|
|
69
|
-
fallback?: ReactNode;
|
|
70
|
-
onDenied?: () => void;
|
|
71
|
-
loading?: ReactNode;
|
|
72
|
-
// NEW: Phase 1 - Enhanced Security Features
|
|
73
|
-
strictMode?: boolean;
|
|
74
|
-
auditLog?: boolean;
|
|
75
|
-
enforceAudit?: boolean;
|
|
76
|
-
}): React.ReactNode {
|
|
77
|
-
const logger = getRBACLogger();
|
|
78
|
-
|
|
79
|
-
let authContext: ReturnType<typeof useUnifiedAuth> | null = null;
|
|
80
|
-
try {
|
|
81
|
-
authContext = useUnifiedAuth();
|
|
82
|
-
} catch (error) {
|
|
83
|
-
if (error instanceof Error && error.message.includes('must be used within')) {
|
|
84
|
-
authContext = null;
|
|
85
|
-
} else {
|
|
86
|
-
throw error;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const effectiveUserId = userId ?? authContext?.user?.id ?? null;
|
|
91
|
-
|
|
92
|
-
// Always call useCan hook, but handle the case where userId might be undefined
|
|
93
|
-
// Pass null for super admin status (not checked yet - hook will check if needed)
|
|
94
|
-
const { can, isLoading, error } = useCan(
|
|
95
|
-
effectiveUserId || '',
|
|
96
|
-
scope,
|
|
97
|
-
permission,
|
|
98
|
-
pageId,
|
|
99
|
-
true, // useCache
|
|
100
|
-
null, // precomputedSuperAdmin - not checked yet
|
|
101
|
-
undefined // appName
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
// If still no userId, show helpful error
|
|
105
|
-
if (!effectiveUserId) {
|
|
106
|
-
logger.error('PermissionGuard: No userId provided and could not infer from context');
|
|
107
|
-
return fallback ?? null;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Handle loading state
|
|
111
|
-
if (isLoading) {
|
|
112
|
-
return loading || (
|
|
113
|
-
<div className="rbac-loading" role="status" aria-live="polite">
|
|
114
|
-
<span className="sr-only">Checking permissions...</span>
|
|
115
|
-
</div>
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Handle error state
|
|
120
|
-
if (error) {
|
|
121
|
-
logger.error('Permission check failed:', error);
|
|
122
|
-
// NEW: Phase 1 - Record failed permission check for audit
|
|
123
|
-
if (auditLog) {
|
|
124
|
-
// Permission check failed logged
|
|
125
|
-
}
|
|
126
|
-
return fallback;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Handle permission denied
|
|
130
|
-
if (!can) {
|
|
131
|
-
// NEW: Phase 1 - Record denied permission check for audit
|
|
132
|
-
if (auditLog) {
|
|
133
|
-
// Permission denied logged
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// NEW: Phase 1 - Handle strict mode violations
|
|
137
|
-
if (strictMode) {
|
|
138
|
-
logger.error(`[PermissionGuard] STRICT MODE VIOLATION: User attempted to access protected resource without permission`, {
|
|
139
|
-
userId: effectiveUserId,
|
|
140
|
-
scope,
|
|
141
|
-
permission,
|
|
142
|
-
pageId,
|
|
143
|
-
timestamp: new Date().toISOString()
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (onDenied) {
|
|
148
|
-
onDenied();
|
|
149
|
-
}
|
|
150
|
-
return <>{fallback}</>;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// NEW: Phase 1 - Record successful permission check for audit
|
|
154
|
-
if (auditLog) {
|
|
155
|
-
// Permission granted logged
|
|
156
|
-
}
|
|
157
16
|
|
|
158
|
-
|
|
159
|
-
return <>{children}</>;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Access Level Guard Component
|
|
164
|
-
*
|
|
165
|
-
* A React component that conditionally renders children based on access level.
|
|
166
|
-
* Can auto-infer userId from context if not provided.
|
|
167
|
-
*
|
|
168
|
-
* @example
|
|
169
|
-
* ```tsx
|
|
170
|
-
* // With explicit userId and scope
|
|
171
|
-
* <AccessLevelGuard
|
|
172
|
-
* userId="user-123"
|
|
173
|
-
* scope={{ organisationId: 'org-456' }}
|
|
174
|
-
* minLevel="admin"
|
|
175
|
-
* fallback={<AccessDenied />}
|
|
176
|
-
* >
|
|
177
|
-
* <AdminPanel />
|
|
178
|
-
* </AccessLevelGuard>
|
|
179
|
-
*
|
|
180
|
-
* // With context inference (requires auth context)
|
|
181
|
-
* <AccessLevelGuard
|
|
182
|
-
* minLevel="admin"
|
|
183
|
-
* scope={{ organisationId: 'org-456' }}
|
|
184
|
-
* fallback={<AccessDenied />}
|
|
185
|
-
* >
|
|
186
|
-
* <AdminPanel />
|
|
187
|
-
* </AccessLevelGuard>
|
|
188
|
-
* ```
|
|
189
|
-
*/
|
|
190
|
-
export function AccessLevelGuard({
|
|
191
|
-
userId,
|
|
192
|
-
scope,
|
|
193
|
-
minLevel,
|
|
194
|
-
children,
|
|
195
|
-
fallback = null,
|
|
196
|
-
loading = null,
|
|
197
|
-
}: {
|
|
198
|
-
userId?: UUID;
|
|
199
|
-
scope: { organisationId: UUID; eventId?: string; appId?: UUID };
|
|
200
|
-
minLevel: 'viewer' | 'participant' | 'planner' | 'admin' | 'super';
|
|
201
|
-
children: ReactNode;
|
|
202
|
-
fallback?: ReactNode;
|
|
203
|
-
loading?: ReactNode;
|
|
204
|
-
}): React.ReactNode {
|
|
205
|
-
const logger = getRBACLogger();
|
|
206
|
-
|
|
207
|
-
let authContext: ReturnType<typeof useUnifiedAuth> | null = null;
|
|
208
|
-
try {
|
|
209
|
-
authContext = useUnifiedAuth();
|
|
210
|
-
} catch (error) {
|
|
211
|
-
if (error instanceof Error && error.message.includes('must be used within')) {
|
|
212
|
-
authContext = null;
|
|
213
|
-
} else {
|
|
214
|
-
throw error;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const effectiveUserId = userId ?? authContext?.user?.id ?? null;
|
|
219
|
-
|
|
220
|
-
// Always call useAccessLevel hook, but handle the case where userId might be undefined
|
|
221
|
-
const { accessLevel, isLoading, error } = useAccessLevel(effectiveUserId || '', scope);
|
|
222
|
-
|
|
223
|
-
// If still no userId, show helpful error
|
|
224
|
-
if (!effectiveUserId) {
|
|
225
|
-
logger.error('AccessLevelGuard: No userId provided and could not infer from context');
|
|
226
|
-
return fallback ?? null;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Handle loading state
|
|
230
|
-
if (isLoading) {
|
|
231
|
-
return loading || (
|
|
232
|
-
<div className="rbac-loading" role="status" aria-live="polite">
|
|
233
|
-
<span className="sr-only">Checking access level...</span>
|
|
234
|
-
</div>
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Handle error state
|
|
239
|
-
if (error) {
|
|
240
|
-
logger.error('Access level check failed:', error);
|
|
241
|
-
return fallback;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Check access level
|
|
245
|
-
const levelHierarchy = ['viewer', 'participant', 'planner', 'admin', 'super'];
|
|
246
|
-
const userLevelIndex = accessLevel ? levelHierarchy.indexOf(accessLevel) : -1;
|
|
247
|
-
const requiredLevelIndex = levelHierarchy.indexOf(minLevel);
|
|
248
|
-
|
|
249
|
-
if (userLevelIndex < requiredLevelIndex) {
|
|
250
|
-
return <>{fallback}</>;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return <>{children}</>;
|
|
254
|
-
}
|
|
17
|
+
import { UUID, Permission } from './types';
|
|
255
18
|
|
|
256
19
|
// ============================================================================
|
|
257
20
|
// SERVER ADAPTERS
|
|
@@ -620,54 +383,3 @@ export function createRBACExpressMiddleware(config: {
|
|
|
620
383
|
};
|
|
621
384
|
}
|
|
622
385
|
|
|
623
|
-
// ============================================================================
|
|
624
|
-
// UTILITY FUNCTIONS
|
|
625
|
-
// ============================================================================
|
|
626
|
-
|
|
627
|
-
/**
|
|
628
|
-
* Check if a user has a permission (synchronous cache check only)
|
|
629
|
-
*
|
|
630
|
-
* @param userId - User ID
|
|
631
|
-
* @param scope - Permission scope
|
|
632
|
-
* @param permission - Permission to check
|
|
633
|
-
* @param pageId - Optional page ID
|
|
634
|
-
* @returns True if permission is cached and granted
|
|
635
|
-
*/
|
|
636
|
-
export function hasPermissionCached(
|
|
637
|
-
userId: UUID,
|
|
638
|
-
scope: { organisationId: UUID; eventId?: string; appId?: UUID },
|
|
639
|
-
_permission: Permission,
|
|
640
|
-
_pageId?: UUID
|
|
641
|
-
): boolean {
|
|
642
|
-
const cacheKey = RBACCache.generatePermissionKey({
|
|
643
|
-
userId,
|
|
644
|
-
organisationId: scope.organisationId,
|
|
645
|
-
eventId: scope.eventId,
|
|
646
|
-
appId: scope.appId,
|
|
647
|
-
});
|
|
648
|
-
|
|
649
|
-
return rbacCache.get<boolean>(cacheKey) || false;
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
/**
|
|
653
|
-
* Check if a user has any of the specified permissions (synchronous cache check only)
|
|
654
|
-
*
|
|
655
|
-
* @param userId - User ID
|
|
656
|
-
* @param scope - Permission scope
|
|
657
|
-
* @param permissions - Array of permissions to check
|
|
658
|
-
* @param pageId - Optional page ID
|
|
659
|
-
* @returns True if any permission is cached and granted
|
|
660
|
-
*/
|
|
661
|
-
export function hasAnyPermissionCached(
|
|
662
|
-
userId: UUID,
|
|
663
|
-
scope: { organisationId: UUID; eventId?: string; appId?: UUID },
|
|
664
|
-
permissions: Permission[],
|
|
665
|
-
pageId?: UUID
|
|
666
|
-
): boolean {
|
|
667
|
-
return permissions.some(permission =>
|
|
668
|
-
hasPermissionCached(userId, scope, permission, pageId)
|
|
669
|
-
);
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// Import useAccessLevel for AccessLevelGuard
|
|
673
|
-
import { useAccessLevel } from './hooks';
|
package/src/rbac/api.test.ts
CHANGED
|
@@ -471,38 +471,50 @@ describe('RBAC API', () => {
|
|
|
471
471
|
|
|
472
472
|
beforeEach(() => {
|
|
473
473
|
// Create a mock Supabase client that can handle getPageScopeType queries
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
};
|
|
474
|
+
// This needs to handle multiple query patterns:
|
|
475
|
+
// 1. from('rbac_apps').select('name').eq('id', ...).eq('is_active', true).single()
|
|
476
|
+
// 2. from('rbac_apps').select('id').eq('name', ...).eq('is_active', true).single()
|
|
477
|
+
// 3. from('rbac_app_pages').select('id').eq('app_id', ...).eq('page_name', ...).maybeSingle()
|
|
478
|
+
// 4. from('rbac_app_pages').select('scope_type').eq('id', ...).single()
|
|
479
|
+
|
|
480
|
+
const createQueryBuilder = (table: string, selectField?: string) => {
|
|
481
|
+
const builder: any = {
|
|
482
|
+
select: vi.fn().mockReturnThis(),
|
|
483
|
+
eq: vi.fn().mockReturnThis(),
|
|
484
|
+
maybeSingle: vi.fn().mockResolvedValue({ data: null, error: null }),
|
|
485
|
+
single: vi.fn().mockResolvedValue({ data: null, error: null })
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
// Handle different query patterns based on table and select field
|
|
489
|
+
if (table === 'rbac_apps') {
|
|
490
|
+
if (selectField === 'name') {
|
|
491
|
+
// Pattern: select('name').eq('id', ...).eq('is_active', true).single()
|
|
492
|
+
builder.single = vi.fn().mockResolvedValue({ data: { name: 'test-app' }, error: null });
|
|
493
|
+
} else if (selectField === 'id') {
|
|
494
|
+
// Pattern: select('id').eq('name', ...).eq('is_active', true).single()
|
|
495
|
+
builder.single = vi.fn().mockResolvedValue({ data: { id: 'app-123' }, error: null });
|
|
497
496
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
497
|
+
} else if (table === 'rbac_app_pages') {
|
|
498
|
+
if (selectField === 'id') {
|
|
499
|
+
// Pattern: select('id').eq('app_id', ...).eq('page_name', ...).maybeSingle()
|
|
500
|
+
builder.maybeSingle = vi.fn().mockResolvedValue({ data: { id: '123e4567-e89b-12d3-a456-426614174000' }, error: null });
|
|
501
|
+
} else if (selectField === 'scope_type') {
|
|
502
|
+
// Pattern: select('scope_type').eq('id', ...).single()
|
|
503
|
+
builder.single = vi.fn().mockResolvedValue({ data: { scope_type: 'organisation' }, error: null });
|
|
503
504
|
}
|
|
504
|
-
|
|
505
|
-
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Make select() return builder with the selectField tracked
|
|
508
|
+
builder.select = vi.fn((fields: string) => {
|
|
509
|
+
return createQueryBuilder(table, fields);
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
return builder;
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
const mockSupabaseForEngine = {
|
|
516
|
+
from: vi.fn((table: string) => createQueryBuilder(table)),
|
|
517
|
+
rpc: vi.fn().mockResolvedValue({ data: null, error: null }),
|
|
506
518
|
auth: mockSupabase.auth
|
|
507
519
|
};
|
|
508
520
|
|
|
@@ -736,32 +748,8 @@ describe('RBAC API', () => {
|
|
|
736
748
|
});
|
|
737
749
|
});
|
|
738
750
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
const { hasPermission } = await import('./api');
|
|
742
|
-
|
|
743
|
-
mockEngine.isPermitted.mockResolvedValue(true);
|
|
744
|
-
|
|
745
|
-
const result = await hasPermission({
|
|
746
|
-
userId: 'user-123',
|
|
747
|
-
scope: { organisationId: 'org-456' },
|
|
748
|
-
permission: 'read:users'
|
|
749
|
-
});
|
|
750
|
-
|
|
751
|
-
expect(result).toBe(true);
|
|
752
|
-
expect(mockEngine.isPermitted).toHaveBeenCalledWith(
|
|
753
|
-
{
|
|
754
|
-
userId: 'user-123',
|
|
755
|
-
scope: { organisationId: 'org-456' },
|
|
756
|
-
permission: 'read:users'
|
|
757
|
-
},
|
|
758
|
-
expect.objectContaining({
|
|
759
|
-
userId: 'user-123',
|
|
760
|
-
organisationId: 'org-456'
|
|
761
|
-
})
|
|
762
|
-
);
|
|
763
|
-
});
|
|
764
|
-
});
|
|
751
|
+
// hasPermission was removed - use isPermitted directly
|
|
752
|
+
// Tests for isPermitted are covered in the isPermitted describe block above
|
|
765
753
|
|
|
766
754
|
describe('hasAnyPermission', () => {
|
|
767
755
|
it('returns true if user has any permission', async () => {
|
package/src/rbac/api.ts
CHANGED
|
@@ -490,16 +490,6 @@ export async function isPermittedCached(
|
|
|
490
490
|
});
|
|
491
491
|
}
|
|
492
492
|
|
|
493
|
-
/**
|
|
494
|
-
* Check if a user has a specific permission (alias for isPermitted)
|
|
495
|
-
*
|
|
496
|
-
* @param input - Permission check parameters
|
|
497
|
-
* @returns Promise<boolean> - True if user has permission
|
|
498
|
-
*/
|
|
499
|
-
export async function hasPermission(input: PermissionCheck): Promise<boolean> {
|
|
500
|
-
return isPermitted(input);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
493
|
/**
|
|
504
494
|
* Check if user has any of the specified permissions
|
|
505
495
|
*
|
|
@@ -623,22 +613,25 @@ export async function getPageScopeType(
|
|
|
623
613
|
throw new Error(`Could not resolve pageId ${pageId} to a valid UUID`);
|
|
624
614
|
}
|
|
625
615
|
|
|
626
|
-
//
|
|
627
|
-
const { data, error } = await engine['supabase']
|
|
628
|
-
.
|
|
629
|
-
|
|
630
|
-
|
|
616
|
+
// Query scope type directly from rbac_app_pages (removed legacy RPC get_page_scope_type)
|
|
617
|
+
const { data: pageData, error } = await engine['supabase']
|
|
618
|
+
.from('rbac_app_pages')
|
|
619
|
+
.select('scope_type')
|
|
620
|
+
.eq('id', resolvedPageId)
|
|
621
|
+
.single();
|
|
631
622
|
|
|
632
623
|
if (error) {
|
|
633
624
|
log.error('Error fetching page scope type:', { pageId, appId, error });
|
|
634
625
|
throw new Error(`Failed to get page scope type: ${error.message}`);
|
|
635
626
|
}
|
|
636
627
|
|
|
637
|
-
if (!
|
|
628
|
+
if (!pageData || !pageData.scope_type) {
|
|
638
629
|
throw new Error(`Page ${resolvedPageId} does not have scope_type set`);
|
|
639
630
|
}
|
|
640
631
|
|
|
641
|
-
|
|
632
|
+
// Type assertion to narrow string to the specific union type
|
|
633
|
+
// The database constraint ensures it's one of these values
|
|
634
|
+
return pageData.scope_type as 'event' | 'organisation' | 'both';
|
|
642
635
|
} catch (err) {
|
|
643
636
|
log.error('Error fetching page scope type:', err);
|
|
644
637
|
throw err instanceof Error ? err : new Error(`Failed to get page scope type: ${String(err)}`);
|
|
@@ -357,7 +357,6 @@ let globalCacheInvalidationManager: RBACCacheInvalidationManager | null = null;
|
|
|
357
357
|
export function initializeCacheInvalidation(supabase: SupabaseClient<Database>): RBACCacheInvalidationManager {
|
|
358
358
|
// Clean up existing manager if it exists (e.g., when switching Supabase clients)
|
|
359
359
|
if (globalCacheInvalidationManager) {
|
|
360
|
-
log.debug('Cleaning up existing cache invalidation manager before creating new one');
|
|
361
360
|
globalCacheInvalidationManager.cleanup();
|
|
362
361
|
}
|
|
363
362
|
|
|
@@ -36,3 +36,13 @@ export {
|
|
|
36
36
|
type QuickFix,
|
|
37
37
|
} from './quick-fix-suggestions';
|
|
38
38
|
|
|
39
|
+
export {
|
|
40
|
+
detectDirectRpcCalls,
|
|
41
|
+
detectDirectTableQueries,
|
|
42
|
+
detectCustomAccessDeniedComponents,
|
|
43
|
+
detectPatternViolations,
|
|
44
|
+
logPatternViolations,
|
|
45
|
+
type PatternViolation,
|
|
46
|
+
type PatternDetectionResult,
|
|
47
|
+
} from './pattern-detector';
|
|
48
|
+
|