@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
|
@@ -0,0 +1,986 @@
|
|
|
1
|
+
# pace-core Compliance Standards
|
|
2
|
+
|
|
3
|
+
**🤖 Cursor Rule**: See [01-pace-core-compliance.mdc](../../cursor-rules/01-pace-core-compliance.mdc) for AI-optimized directives that automatically enforce these standards.
|
|
4
|
+
|
|
5
|
+
This guide explains how to enforce pace-core usage patterns in consuming apps to ensure consistent design, reduce duplication, and maintain high code quality.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
pace-core provides a comprehensive enforcement system that includes:
|
|
10
|
+
|
|
11
|
+
1. **ESLint Rules** - Real-time linting during development (organized by standards: 01, 04, 05, 06, 07, 08)
|
|
12
|
+
2. **Audit Tool** - Comprehensive system-level analysis organized by standards (01-09)
|
|
13
|
+
3. **ESLint Config Preset** - Easy setup for consuming apps
|
|
14
|
+
4. **Cursor Rules Integration** - AI-assisted enforcement via Cursor IDE
|
|
15
|
+
|
|
16
|
+
### ESLint vs Audit Scripts
|
|
17
|
+
|
|
18
|
+
**ESLint Rules** (Real-time, AST-based):
|
|
19
|
+
- ✅ Run automatically in your IDE
|
|
20
|
+
- ✅ Provide immediate feedback during development
|
|
21
|
+
- ✅ Check single files using AST analysis
|
|
22
|
+
- ✅ Can be auto-fixed in many cases
|
|
23
|
+
- ✅ Integrated with your development workflow
|
|
24
|
+
|
|
25
|
+
**Audit Scripts** (Comprehensive, file-system based):
|
|
26
|
+
- ✅ Scan entire codebase
|
|
27
|
+
- ✅ Check file structure and configuration
|
|
28
|
+
- ✅ Cross-file analysis (e.g., provider nesting)
|
|
29
|
+
- ✅ Generate detailed reports
|
|
30
|
+
- ✅ Check setup files (main.tsx, app.css, etc.)
|
|
31
|
+
|
|
32
|
+
**What's in ESLint vs Audit Scripts**:
|
|
33
|
+
|
|
34
|
+
| Check | ESLint | Audit Script |
|
|
35
|
+
|-------|--------|--------------|
|
|
36
|
+
| Restricted imports | ✅ | ✅ (reference) |
|
|
37
|
+
| Native HTML elements | ✅ | ✅ (reference) |
|
|
38
|
+
| Custom hooks/utils | ✅ | ✅ (reference) |
|
|
39
|
+
| Inline styles | ✅ | ✅ (reference) |
|
|
40
|
+
| Plain form tags | ✅ | ✅ (reference) |
|
|
41
|
+
| Direct Supabase client | ✅ | ✅ (file location) |
|
|
42
|
+
| RBAC permission loading | ✅ | ✅ (reference) |
|
|
43
|
+
| Direct RBAC RPC/table | ✅ | ✅ (reference) |
|
|
44
|
+
| Hardcoded role checks | ✅ | ✅ (reference) |
|
|
45
|
+
| RESOURCE_NAMES constants | ✅ | ✅ (reference) |
|
|
46
|
+
| RBAC wrapper components | ✅ | ✅ (reference) |
|
|
47
|
+
| RBAC wrapper functions | ✅ | ✅ (reference) |
|
|
48
|
+
| RBAC setup (main.tsx) | ❌ | ✅ |
|
|
49
|
+
| Provider nesting | ❌ | ✅ |
|
|
50
|
+
| Core styles import chain | ❌ | ✅ |
|
|
51
|
+
| PagePermissionGuard coverage | ❌ | ✅ |
|
|
52
|
+
| Edge Functions RBAC | ❌ | ✅ |
|
|
53
|
+
|
|
54
|
+
**Note**: Many checks have been migrated from audit scripts to ESLint for real-time feedback. The audit scripts now focus on file-system and configuration checks that require cross-file analysis.
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
### Step 1: Install pace-core
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install @jmruthers/pace-core
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Step 2: Setup ESLint (Recommended)
|
|
65
|
+
|
|
66
|
+
**Automated Setup (Easiest)**
|
|
67
|
+
|
|
68
|
+
Use the installation script to set up ESLint:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm run setup:eslint
|
|
72
|
+
# or
|
|
73
|
+
node node_modules/@jmruthers/pace-core/scripts/install-eslint-config.cjs
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This script will:
|
|
77
|
+
- ✅ Configure ESLint to use pace-core rules
|
|
78
|
+
- ✅ Create `eslint.config.js` if it doesn't exist
|
|
79
|
+
- ✅ Add pace-core config to existing ESLint config
|
|
80
|
+
- ✅ Create backups before modifying files
|
|
81
|
+
|
|
82
|
+
**Options:**
|
|
83
|
+
- `--force` - Force update even if already configured
|
|
84
|
+
|
|
85
|
+
**Option B: Manual Setup**
|
|
86
|
+
|
|
87
|
+
The easiest way to enable compliance checking is to use the shareable ESLint config. The config is CommonJS but works with both ES module and CommonJS ESLint configs:
|
|
88
|
+
|
|
89
|
+
**For ES Module ESLint Config (eslint.config.js):**
|
|
90
|
+
```javascript
|
|
91
|
+
// eslint.config.js (ES modules)
|
|
92
|
+
import paceCoreConfig from '@jmruthers/pace-core/eslint-config';
|
|
93
|
+
|
|
94
|
+
export default [
|
|
95
|
+
...paceCoreConfig,
|
|
96
|
+
// your other config
|
|
97
|
+
];
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**For CommonJS ESLint Config (.eslintrc.js or eslint.config.cjs):**
|
|
101
|
+
```javascript
|
|
102
|
+
// eslint.config.cjs (CommonJS)
|
|
103
|
+
const paceCoreConfig = require('@jmruthers/pace-core/eslint-config');
|
|
104
|
+
|
|
105
|
+
module.exports = [
|
|
106
|
+
...paceCoreConfig,
|
|
107
|
+
// your other config
|
|
108
|
+
];
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Complete Example (ESLint 9 flat config):**
|
|
112
|
+
```javascript
|
|
113
|
+
// eslint.config.js
|
|
114
|
+
import js from '@eslint/js';
|
|
115
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
116
|
+
import paceCoreConfig from '@jmruthers/pace-core/eslint-config';
|
|
117
|
+
|
|
118
|
+
export default [
|
|
119
|
+
js.configs.recommended,
|
|
120
|
+
...paceCoreConfig, // pace-core rules
|
|
121
|
+
{
|
|
122
|
+
files: ['**/*.{ts,tsx}'],
|
|
123
|
+
plugins: {
|
|
124
|
+
'react-hooks': reactHooks,
|
|
125
|
+
},
|
|
126
|
+
rules: {
|
|
127
|
+
...reactHooks.configs.recommended.rules,
|
|
128
|
+
// Your other rules
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
];
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Step 3: Setup Cursor Rules (Optional but Recommended)
|
|
135
|
+
|
|
136
|
+
**Automated Setup (Easiest)**
|
|
137
|
+
|
|
138
|
+
Use the installation script to set up Cursor rules:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
npm run setup:cursor-rules
|
|
142
|
+
# or
|
|
143
|
+
node node_modules/@jmruthers/pace-core/scripts/install-cursor-rules.cjs
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
This script will:
|
|
147
|
+
- ✅ Install Cursor rules to `.cursor/rules/`
|
|
148
|
+
- ✅ Create backups before updating existing rules
|
|
149
|
+
- ✅ Automatically update pace-core rules when they change
|
|
150
|
+
|
|
151
|
+
**Options:**
|
|
152
|
+
- `--force` - Force update even if already configured
|
|
153
|
+
|
|
154
|
+
**Manual Setup (Alternative)**
|
|
155
|
+
|
|
156
|
+
To manually enable AI-assisted enforcement in Cursor IDE, copy the pace-core cursor rules to your project:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Create .cursor/rules directory if it doesn't exist
|
|
160
|
+
mkdir -p .cursor/rules
|
|
161
|
+
|
|
162
|
+
# Copy pace-core cursor rules
|
|
163
|
+
cp node_modules/@jmruthers/pace-core/cursor-rules/*.mdc .cursor/rules/
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Or manually create `.cursor/rules/01-pace-core-compliance.mdc` and reference the pace-core rules:
|
|
167
|
+
|
|
168
|
+
```markdown
|
|
169
|
+
---
|
|
170
|
+
description: Enforce pace-core usage patterns
|
|
171
|
+
globs: ["src/**/*.{ts,tsx,js,jsx}"]
|
|
172
|
+
alwaysApply: false
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
# pace-core Compliance
|
|
176
|
+
|
|
177
|
+
**📚 Full Documentation**: See [pace-core compliance docs](node_modules/@jmruthers/pace-core/docs/standards/1-pace-core-compliance-standards.md)
|
|
178
|
+
|
|
179
|
+
**🔧 ESLint Setup**: Ensure ESLint is configured with `@jmruthers/pace-core/eslint-config`
|
|
180
|
+
|
|
181
|
+
This rule enforces pace-core usage patterns. ESLint provides real-time feedback, while this Cursor rule provides AI-assisted guidance.
|
|
182
|
+
|
|
183
|
+
## Key Requirements
|
|
184
|
+
|
|
185
|
+
- Use pace-core components instead of native HTML or custom implementations
|
|
186
|
+
- Use pace-core hooks instead of custom hooks
|
|
187
|
+
- Use pace-core utilities instead of custom utilities
|
|
188
|
+
- Use `useSecureSupabase()` instead of direct Supabase client creation
|
|
189
|
+
- Follow RBAC patterns from pace-core
|
|
190
|
+
- Use RESOURCE_NAMES constants instead of string literals
|
|
191
|
+
|
|
192
|
+
See the full documentation for complete rules and examples.
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Benefits of Cursor Rules Integration**:
|
|
196
|
+
- AI assistant (like me!) will automatically suggest pace-core alternatives
|
|
197
|
+
- Context-aware suggestions during code writing
|
|
198
|
+
- Works alongside ESLint for comprehensive enforcement
|
|
199
|
+
- Provides explanations and examples in real-time
|
|
200
|
+
|
|
201
|
+
## ESLint Rules
|
|
202
|
+
|
|
203
|
+
pace-core provides ESLint rules organized by standards (01, 04, 05, 06, 07, 08). Rules are organized to match the 10-file standards structure:
|
|
204
|
+
|
|
205
|
+
- **Standard 1 (pace-core Compliance)**: 6 rules
|
|
206
|
+
- **Standard 4 (Code Quality)**: 3 rules
|
|
207
|
+
- **Standard 5 (Styling)**: 1 rule
|
|
208
|
+
- **Standard 6 (Security & RBAC)**: 8 rules
|
|
209
|
+
- **Standard 7 (API & Tech Stack)**: 3 rules
|
|
210
|
+
- **Standard 8 (Testing)**: 1 rule
|
|
211
|
+
|
|
212
|
+
**Total: 22 rules** organized across 6 standards files.
|
|
213
|
+
|
|
214
|
+
### Rule Organization
|
|
215
|
+
|
|
216
|
+
Rules are organized in `packages/core/eslint-rules/rules/`:
|
|
217
|
+
- `01-pace-core-compliance.cjs` - pace-core usage patterns
|
|
218
|
+
- `04-code-quality.cjs` - Naming conventions, component/type naming
|
|
219
|
+
- `05-styling.cjs` - Inline styles
|
|
220
|
+
- `06-security-rbac.cjs` - Security and RBAC patterns
|
|
221
|
+
- `07-api-tech-stack.cjs` - RPC naming, React 19+, import.meta.env
|
|
222
|
+
- `08-testing.cjs` - Test file naming
|
|
223
|
+
|
|
224
|
+
### Detailed Rule Descriptions
|
|
225
|
+
|
|
226
|
+
#### Import Rules
|
|
227
|
+
|
|
228
|
+
#### no-restricted-imports
|
|
229
|
+
|
|
230
|
+
**Severity**: Error
|
|
231
|
+
|
|
232
|
+
Blocks direct imports of libraries that pace-core wraps and standardizes.
|
|
233
|
+
|
|
234
|
+
**Restricted Libraries**:
|
|
235
|
+
- `@radix-ui/*` - All Radix UI packages (use pace-core components instead)
|
|
236
|
+
- `lucide-react` - Icons (import from `@jmruthers/pace-core/icons` instead)
|
|
237
|
+
- `react-day-picker` - Use `Calendar` from pace-core
|
|
238
|
+
- `@tanstack/react-table` - Use `DataTable` from pace-core
|
|
239
|
+
- `react-hook-form` - Use `Form` and `useZodForm` from pace-core
|
|
240
|
+
- `zod` - Use validation utilities from pace-core
|
|
241
|
+
|
|
242
|
+
**Example Violation**:
|
|
243
|
+
```typescript
|
|
244
|
+
// ❌ Bad
|
|
245
|
+
import { Dialog } from '@radix-ui/react-dialog';
|
|
246
|
+
import { ChevronDown, Edit, Trash } from 'lucide-react';
|
|
247
|
+
|
|
248
|
+
// ✅ Good
|
|
249
|
+
import { Dialog } from '@jmruthers/pace-core';
|
|
250
|
+
import { ChevronDown, Edit, Trash } from '@jmruthers/pace-core/icons';
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Compliance Rules
|
|
254
|
+
|
|
255
|
+
#### prefer-pace-core-components
|
|
256
|
+
|
|
257
|
+
**Severity**: Warning
|
|
258
|
+
|
|
259
|
+
Suggests using pace-core components instead of native HTML elements.
|
|
260
|
+
|
|
261
|
+
**Detected Patterns**:
|
|
262
|
+
- `<button>` → Use `Button` from pace-core
|
|
263
|
+
- `<input>` → Use `Input` from pace-core
|
|
264
|
+
- `<textarea>` → Use `Textarea` from pace-core
|
|
265
|
+
- `<label>` → Use `Label` from pace-core
|
|
266
|
+
|
|
267
|
+
**Example**:
|
|
268
|
+
```tsx
|
|
269
|
+
// ⚠️ Warning
|
|
270
|
+
<button onClick={handleClick}>Click me</button>
|
|
271
|
+
|
|
272
|
+
// ✅ Recommended
|
|
273
|
+
import { Button } from '@jmruthers/pace-core';
|
|
274
|
+
<Button onClick={handleClick}>Click me</Button>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
#### prefer-pace-core-hooks
|
|
278
|
+
|
|
279
|
+
**Severity**: Warning
|
|
280
|
+
|
|
281
|
+
Detects custom hooks that duplicate pace-core functionality.
|
|
282
|
+
|
|
283
|
+
**Common Patterns Detected**:
|
|
284
|
+
- `useToast`, `useNotification` → Use `useToast` from pace-core
|
|
285
|
+
- `useDebounce`, `useDebounced` → Use `useDebounce` from pace-core
|
|
286
|
+
- `useAuth`, `useAuthentication` → Use `useUnifiedAuth` from pace-core
|
|
287
|
+
- `useForm`, `useZodForm` → Use `useZodForm` from pace-core
|
|
288
|
+
|
|
289
|
+
**Example**:
|
|
290
|
+
```typescript
|
|
291
|
+
// ⚠️ Warning
|
|
292
|
+
function useToast() {
|
|
293
|
+
// custom implementation
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// ✅ Recommended
|
|
297
|
+
import { useToast } from '@jmruthers/pace-core';
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
#### prefer-pace-core-utils
|
|
301
|
+
|
|
302
|
+
**Severity**: Warning
|
|
303
|
+
|
|
304
|
+
Detects utility functions that duplicate pace-core functionality.
|
|
305
|
+
|
|
306
|
+
**Common Patterns Detected**:
|
|
307
|
+
- `formatDate`, `dateFormat` → Use `formatDate` from pace-core
|
|
308
|
+
- `formatCurrency`, `formatMoney` → Use `formatCurrency` from pace-core
|
|
309
|
+
- `cn`, `classNames`, `clsx` → Use `cn` from pace-core
|
|
310
|
+
- `validate`, `validateInput` → Use `validateUserInput` from pace-core
|
|
311
|
+
|
|
312
|
+
**Example**:
|
|
313
|
+
```typescript
|
|
314
|
+
// ⚠️ Warning
|
|
315
|
+
function formatDate(date: Date): string {
|
|
316
|
+
// custom implementation
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// ✅ Recommended
|
|
320
|
+
import { formatDate } from '@jmruthers/pace-core';
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
#### no-local-component-duplication
|
|
324
|
+
|
|
325
|
+
**Severity**: Error
|
|
326
|
+
|
|
327
|
+
Prevents creating local components with names matching pace-core components.
|
|
328
|
+
|
|
329
|
+
**Example Violation**:
|
|
330
|
+
```
|
|
331
|
+
// ❌ Error: components/Button.tsx
|
|
332
|
+
export function Button() { ... }
|
|
333
|
+
|
|
334
|
+
// pace-core already provides Button component
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Fix**: Remove the local component and import from pace-core:
|
|
338
|
+
```typescript
|
|
339
|
+
import { Button } from '@jmruthers/pace-core';
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
#### no-inline-styles
|
|
343
|
+
|
|
344
|
+
**Severity**: Error
|
|
345
|
+
|
|
346
|
+
Disallows inline styles. Use pace-core components or Tailwind classes instead.
|
|
347
|
+
|
|
348
|
+
**Example Violation**:
|
|
349
|
+
```tsx
|
|
350
|
+
// ❌ Error
|
|
351
|
+
<div style={{ color: 'red', padding: '10px' }}>Content</div>
|
|
352
|
+
|
|
353
|
+
// ✅ Good
|
|
354
|
+
<div className="text-acc-500 p-4">Content</div>
|
|
355
|
+
// Or use pace-core components with built-in styling
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Component Rules
|
|
359
|
+
|
|
360
|
+
#### prefer-pace-core-form
|
|
361
|
+
|
|
362
|
+
**Severity**: Error
|
|
363
|
+
|
|
364
|
+
Disallows plain `<form>` tags and direct `react-hook-form` imports. Use pace-core `Form` component instead.
|
|
365
|
+
|
|
366
|
+
**Detected Patterns**:
|
|
367
|
+
- Plain `<form>` tags
|
|
368
|
+
- Direct imports from `react-hook-form` (except `useFormContext` when using pace-core `Form`)
|
|
369
|
+
|
|
370
|
+
**Example Violation**:
|
|
371
|
+
```tsx
|
|
372
|
+
// ❌ Error
|
|
373
|
+
import { useForm, FormProvider } from 'react-hook-form';
|
|
374
|
+
<form onSubmit={handleSubmit}>...</form>
|
|
375
|
+
|
|
376
|
+
// ✅ Good
|
|
377
|
+
import { Form, useZodForm } from '@jmruthers/pace-core';
|
|
378
|
+
<Form form={form} onSubmit={handleSubmit}>...</Form>
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**Exception**: `useFormContext` is allowed when `Form` is imported from pace-core:
|
|
382
|
+
```tsx
|
|
383
|
+
// ✅ Allowed
|
|
384
|
+
import { Form } from '@jmruthers/pace-core';
|
|
385
|
+
import { useFormContext } from 'react-hook-form'; // OK when using pace-core Form
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### RBAC Rules
|
|
389
|
+
|
|
390
|
+
#### no-direct-supabase-client
|
|
391
|
+
|
|
392
|
+
**Severity**: Error
|
|
393
|
+
|
|
394
|
+
Disallows direct `createClient()` calls from `@supabase/supabase-js`. Use `useSecureSupabase()` from pace-core instead.
|
|
395
|
+
|
|
396
|
+
**Why**: Direct client creation bypasses organisation context and RLS policies, leading to security vulnerabilities.
|
|
397
|
+
|
|
398
|
+
**Example Violation**:
|
|
399
|
+
```typescript
|
|
400
|
+
// ❌ Error
|
|
401
|
+
import { createClient } from '@supabase/supabase-js';
|
|
402
|
+
const supabase = createClient(url, key);
|
|
403
|
+
|
|
404
|
+
// ✅ Good
|
|
405
|
+
import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
|
|
406
|
+
const secureSupabase = useSecureSupabase();
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
**Exception**: Creating the base client for `UnifiedAuthProvider` in `main.tsx` or `App.tsx` is allowed.
|
|
410
|
+
|
|
411
|
+
#### rbac-permission-loading
|
|
412
|
+
|
|
413
|
+
**Severity**: Error
|
|
414
|
+
|
|
415
|
+
Requires `isLoading` extraction from `useResourcePermissions` and checking it before permission calls in mutations.
|
|
416
|
+
|
|
417
|
+
**Why**: Permission checks may fail if scope resolution is still in progress.
|
|
418
|
+
|
|
419
|
+
**Example Violation**:
|
|
420
|
+
```typescript
|
|
421
|
+
// ❌ Error
|
|
422
|
+
const { canCreate, canUpdate } = useResourcePermissions(RESOURCE_NAMES.EVENTS);
|
|
423
|
+
// Missing isLoading extraction
|
|
424
|
+
|
|
425
|
+
// In mutation:
|
|
426
|
+
if (canCreate(event)) { ... } // May fail if permissions still loading
|
|
427
|
+
|
|
428
|
+
// ✅ Good
|
|
429
|
+
const { canCreate, canUpdate, isLoading: permissionsLoading } = useResourcePermissions(RESOURCE_NAMES.EVENTS);
|
|
430
|
+
|
|
431
|
+
// In mutation:
|
|
432
|
+
if (permissionsLoading) {
|
|
433
|
+
throw new Error('Permission check in progress. Please wait...');
|
|
434
|
+
}
|
|
435
|
+
if (!canCreate(event)) {
|
|
436
|
+
throw new Error('Insufficient permissions');
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
#### no-direct-rbac-rpc
|
|
441
|
+
|
|
442
|
+
**Severity**: Error
|
|
443
|
+
|
|
444
|
+
Disallows direct RPC calls to RBAC functions (e.g., `rbac_check_permission_simplified`). Use pace-core RBAC hooks instead.
|
|
445
|
+
|
|
446
|
+
**Example Violation**:
|
|
447
|
+
```typescript
|
|
448
|
+
// ❌ Error
|
|
449
|
+
const { data } = await supabase.rpc('rbac_check_permission_simplified', {...});
|
|
450
|
+
|
|
451
|
+
// ✅ Good
|
|
452
|
+
import { isPermitted } from '@jmruthers/pace-core/rbac';
|
|
453
|
+
const hasPermission = await isPermitted({...});
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
#### no-direct-rbac-table
|
|
457
|
+
|
|
458
|
+
**Severity**: Error
|
|
459
|
+
|
|
460
|
+
Disallows direct queries to RBAC tables. Use `useSecureSupabase()` hook or pace-core RBAC API functions instead.
|
|
461
|
+
|
|
462
|
+
**RBAC Tables**:
|
|
463
|
+
- `rbac_organisation_roles`
|
|
464
|
+
- `rbac_event_app_roles`
|
|
465
|
+
- `rbac_global_roles`
|
|
466
|
+
- `rbac_apps`
|
|
467
|
+
- `rbac_app_pages`
|
|
468
|
+
- `rbac_page_permissions`
|
|
469
|
+
- `rbac_user_profiles`
|
|
470
|
+
|
|
471
|
+
**Example Violation**:
|
|
472
|
+
```typescript
|
|
473
|
+
// ❌ Error
|
|
474
|
+
const { data } = await supabase.from('rbac_organisation_roles').select('*');
|
|
475
|
+
|
|
476
|
+
// ✅ Good
|
|
477
|
+
import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
|
|
478
|
+
const secureSupabase = useSecureSupabase();
|
|
479
|
+
const { data } = await secureSupabase.from('rbac_organisation_roles').select('*');
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
#### no-hardcoded-role-checks
|
|
483
|
+
|
|
484
|
+
**Severity**: Error
|
|
485
|
+
|
|
486
|
+
Disallows hardcoded role checks. Use `useAccessLevel` hook or `getRoleContext` API from pace-core instead.
|
|
487
|
+
|
|
488
|
+
**Example Violation**:
|
|
489
|
+
```typescript
|
|
490
|
+
// ❌ Error
|
|
491
|
+
if (user.role === 'admin') { ... }
|
|
492
|
+
if (currentRole === 'org_admin') { ... }
|
|
493
|
+
|
|
494
|
+
// ✅ Good
|
|
495
|
+
import { useAccessLevel } from '@jmruthers/pace-core/rbac';
|
|
496
|
+
const { accessLevel } = useAccessLevel();
|
|
497
|
+
if (accessLevel === 'admin') { ... }
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
#### rbac-use-resource-names-constants
|
|
501
|
+
|
|
502
|
+
**Severity**: Error
|
|
503
|
+
|
|
504
|
+
Requires `RESOURCE_NAMES` constants instead of string literals in `useResourcePermissions` calls.
|
|
505
|
+
|
|
506
|
+
**Example Violation**:
|
|
507
|
+
```typescript
|
|
508
|
+
// ❌ Error
|
|
509
|
+
const permissions = useResourcePermissions('organisations');
|
|
510
|
+
|
|
511
|
+
// ✅ Good
|
|
512
|
+
import { RESOURCE_NAMES } from '@/config/resource-names';
|
|
513
|
+
const permissions = useResourcePermissions(RESOURCE_NAMES.ORGANISATIONS);
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
#### no-rbac-wrapper-components
|
|
517
|
+
|
|
518
|
+
**Severity**: Error
|
|
519
|
+
|
|
520
|
+
Disallows wrapper components around `PagePermissionGuard`. Use `PagePermissionGuard` directly.
|
|
521
|
+
|
|
522
|
+
**Example Violation**:
|
|
523
|
+
```tsx
|
|
524
|
+
// ❌ Error
|
|
525
|
+
function ProtectedPage({ pageName, children }) {
|
|
526
|
+
return <PagePermissionGuard pageName={pageName}>{children}</PagePermissionGuard>;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// ✅ Good
|
|
530
|
+
<PagePermissionGuard pageName="events" operation="read">
|
|
531
|
+
<YourPageContent />
|
|
532
|
+
</PagePermissionGuard>
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
#### no-rbac-wrapper-functions
|
|
536
|
+
|
|
537
|
+
**Severity**: Error
|
|
538
|
+
|
|
539
|
+
Disallows wrapper functions around pace-core permission hooks. Use hooks directly in components.
|
|
540
|
+
|
|
541
|
+
**Example Violation**:
|
|
542
|
+
```typescript
|
|
543
|
+
// ❌ Error
|
|
544
|
+
function canEditEvent(eventId: string) {
|
|
545
|
+
const { canUpdate } = useResourcePermissions(RESOURCE_NAMES.EVENTS);
|
|
546
|
+
return canUpdate(eventId) && someOtherCondition;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// ✅ Good
|
|
550
|
+
function YourComponent() {
|
|
551
|
+
const { canUpdate } = useResourcePermissions(RESOURCE_NAMES.EVENTS);
|
|
552
|
+
// Use canUpdate directly in component logic
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
## Static Analysis Script
|
|
557
|
+
|
|
558
|
+
The static analysis script provides a comprehensive scan of your codebase and generates a detailed compliance report.
|
|
559
|
+
|
|
560
|
+
### Running the Script
|
|
561
|
+
|
|
562
|
+
```bash
|
|
563
|
+
# From your consuming app root
|
|
564
|
+
node node_modules/@jmruthers/pace-core/scripts/check-pace-core-compliance.cjs
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
Or add it to your `package.json`:
|
|
568
|
+
|
|
569
|
+
```json
|
|
570
|
+
{
|
|
571
|
+
"scripts": {
|
|
572
|
+
"check:pace-core": "node node_modules/@jmruthers/pace-core/scripts/check-pace-core-compliance.cjs"
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
### What It Checks
|
|
578
|
+
|
|
579
|
+
1. **Restricted Imports** - Scans for direct imports of wrapped libraries
|
|
580
|
+
2. **Duplicate Components** - Finds local components matching pace-core names
|
|
581
|
+
3. **Duplicate Hooks** - Finds local hooks matching pace-core hooks
|
|
582
|
+
4. **Duplicate Utils** - Finds local utils matching pace-core utils
|
|
583
|
+
5. **Suggestions** - Recommends pace-core alternatives for native HTML elements
|
|
584
|
+
|
|
585
|
+
### Report Output
|
|
586
|
+
|
|
587
|
+
The script generates a color-coded terminal report showing:
|
|
588
|
+
|
|
589
|
+
- ❌ **Errors** - Critical violations that must be fixed
|
|
590
|
+
- ⚠️ **Warnings** - Issues that should be addressed
|
|
591
|
+
- 💡 **Suggestions** - Recommendations for improvement
|
|
592
|
+
- ✅ **Summary** - Overall compliance status
|
|
593
|
+
|
|
594
|
+
## Best Practices
|
|
595
|
+
|
|
596
|
+
### 1. Always Import from pace-core
|
|
597
|
+
|
|
598
|
+
```typescript
|
|
599
|
+
// ✅ Good
|
|
600
|
+
import { Button, Card, Dialog } from '@jmruthers/pace-core';
|
|
601
|
+
import { useToast, useDebounce } from '@jmruthers/pace-core';
|
|
602
|
+
import { formatDate, formatCurrency } from '@jmruthers/pace-core';
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
### 2. Use pace-core Components for UI
|
|
606
|
+
|
|
607
|
+
Avoid native HTML elements when pace-core provides a component:
|
|
608
|
+
|
|
609
|
+
```tsx
|
|
610
|
+
// ❌ Avoid
|
|
611
|
+
<button className="btn">Click</button>
|
|
612
|
+
|
|
613
|
+
// ✅ Use pace-core
|
|
614
|
+
<Button>Click</Button>
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### 3. Leverage pace-core Hooks
|
|
618
|
+
|
|
619
|
+
Don't recreate hooks that pace-core already provides:
|
|
620
|
+
|
|
621
|
+
```typescript
|
|
622
|
+
// ❌ Avoid
|
|
623
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
624
|
+
useEffect(() => {
|
|
625
|
+
const timer = setTimeout(() => setDebouncedValue(value), 500);
|
|
626
|
+
return () => clearTimeout(timer);
|
|
627
|
+
}, [value]);
|
|
628
|
+
|
|
629
|
+
// ✅ Use pace-core
|
|
630
|
+
import { useDebounce } from '@jmruthers/pace-core';
|
|
631
|
+
const debouncedValue = useDebounce(value, 500);
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### 4. Use pace-core Utilities
|
|
635
|
+
|
|
636
|
+
Leverage formatting, validation, and other utilities from pace-core:
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
// ❌ Avoid
|
|
640
|
+
const formatted = new Intl.DateTimeFormat('en-US').format(date);
|
|
641
|
+
|
|
642
|
+
// ✅ Use pace-core
|
|
643
|
+
import { formatDate } from '@jmruthers/pace-core';
|
|
644
|
+
const formatted = formatDate(date);
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### 5. Check Before Creating New Components
|
|
648
|
+
|
|
649
|
+
Before creating a new component, check if pace-core already provides it:
|
|
650
|
+
|
|
651
|
+
1. Review the [pace-core documentation](https://github.com/your-org/pace-core)
|
|
652
|
+
2. Check `core-usage-manifest.json` for available components
|
|
653
|
+
3. Search pace-core exports
|
|
654
|
+
|
|
655
|
+
## MUST: Provider Nesting Order
|
|
656
|
+
|
|
657
|
+
**⚠️ CRITICAL: Provider nesting order matters!** Incorrect nesting causes React context errors.
|
|
658
|
+
|
|
659
|
+
**MUST** nest providers in this exact order (outermost to innermost):
|
|
660
|
+
|
|
661
|
+
1. `QueryClientProvider` (outermost)
|
|
662
|
+
2. `BrowserRouter`
|
|
663
|
+
3. `UnifiedAuthProvider`
|
|
664
|
+
4. `OrganisationProvider`
|
|
665
|
+
5. `App` (innermost)
|
|
666
|
+
|
|
667
|
+
```tsx
|
|
668
|
+
// ✅ CORRECT: main.tsx
|
|
669
|
+
import { BrowserRouter } from 'react-router-dom';
|
|
670
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
671
|
+
import { UnifiedAuthProvider, OrganisationProvider } from '@jmruthers/pace-core';
|
|
672
|
+
import { createClient } from '@supabase/supabase-js';
|
|
673
|
+
|
|
674
|
+
const queryClient = new QueryClient();
|
|
675
|
+
const supabase = createClient(
|
|
676
|
+
import.meta.env.VITE_SUPABASE_URL,
|
|
677
|
+
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
|
|
678
|
+
);
|
|
679
|
+
|
|
680
|
+
createRoot(document.getElementById("root")!).render(
|
|
681
|
+
<QueryClientProvider client={queryClient}>
|
|
682
|
+
<BrowserRouter>
|
|
683
|
+
<UnifiedAuthProvider supabaseClient={supabase} appName="YourApp">
|
|
684
|
+
<OrganisationProvider>
|
|
685
|
+
<App />
|
|
686
|
+
</OrganisationProvider>
|
|
687
|
+
</UnifiedAuthProvider>
|
|
688
|
+
</BrowserRouter>
|
|
689
|
+
</QueryClientProvider>
|
|
690
|
+
);
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
**Common mistakes to avoid:**
|
|
694
|
+
- ❌ `BrowserRouter` inside `UnifiedAuthProvider` (causes Router context errors)
|
|
695
|
+
- ❌ `UnifiedAuthProvider` wrapping `BrowserRouter` (causes context errors)
|
|
696
|
+
- ❌ Missing `BrowserRouter` (causes `useNavigate` errors)
|
|
697
|
+
|
|
698
|
+
## MUST: Vite Configuration
|
|
699
|
+
|
|
700
|
+
**⚠️ CRITICAL: Vite configuration prevents React context mismatches!**
|
|
701
|
+
|
|
702
|
+
**MUST** configure Vite to exclude `@jmruthers/pace-core` and `react-router-dom` from pre-bundling:
|
|
703
|
+
|
|
704
|
+
```typescript
|
|
705
|
+
// vite.config.ts
|
|
706
|
+
import { defineConfig } from 'vite';
|
|
707
|
+
import react from '@vitejs/plugin-react';
|
|
708
|
+
import path from 'path';
|
|
709
|
+
|
|
710
|
+
export default defineConfig({
|
|
711
|
+
plugins: [react()],
|
|
712
|
+
resolve: {
|
|
713
|
+
alias: {
|
|
714
|
+
'@': path.resolve(__dirname, './src'),
|
|
715
|
+
},
|
|
716
|
+
// CRITICAL: Dedupe React dependencies
|
|
717
|
+
dedupe: ['react', 'react-dom', 'react-router-dom'],
|
|
718
|
+
},
|
|
719
|
+
optimizeDeps: {
|
|
720
|
+
include: [
|
|
721
|
+
'react',
|
|
722
|
+
'react-dom',
|
|
723
|
+
'react/jsx-runtime',
|
|
724
|
+
],
|
|
725
|
+
// CRITICAL: Exclude pace-core to prevent React context mismatches
|
|
726
|
+
exclude: ['@jmruthers/pace-core', 'react-router-dom'],
|
|
727
|
+
},
|
|
728
|
+
});
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
**Why this matters:**
|
|
732
|
+
- Pre-bundling `@jmruthers/pace-core` creates separate React instances
|
|
733
|
+
- This causes "useUnifiedAuth must be used within a UnifiedAuthProvider" errors
|
|
734
|
+
- Excluding it ensures pace-core uses the same React instance as your app
|
|
735
|
+
- `react-router-dom` must also be excluded and deduped to prevent Router context errors
|
|
736
|
+
|
|
737
|
+
**If you encounter context errors:**
|
|
738
|
+
1. Verify `@jmruthers/pace-core` is in `optimizeDeps.exclude`
|
|
739
|
+
2. Verify `react-router-dom` is in both `resolve.dedupe` and `optimizeDeps.exclude`
|
|
740
|
+
3. Clear Vite cache: `rm -rf node_modules/.vite`
|
|
741
|
+
4. Restart dev server
|
|
742
|
+
|
|
743
|
+
## MUST: Use Secure Supabase Client
|
|
744
|
+
|
|
745
|
+
**All database operations MUST use `useSecureSupabase()` (or the contract-approved pace-core secure client wrapper).**
|
|
746
|
+
Consuming apps **MUST NOT** use the base Supabase client directly for queries.
|
|
747
|
+
|
|
748
|
+
### Hard Requirements
|
|
749
|
+
|
|
750
|
+
- **MUST NOT** import or call `createClient()` from `@supabase/supabase-js` in consuming app code **except** for creating the base client passed to `UnifiedAuthProvider`.
|
|
751
|
+
- **MUST NOT** export, pass, or store an insecure Supabase client instance for general use.
|
|
752
|
+
- **MUST** perform all `.from(...)`, `.rpc(...)`, `.auth.*`, and storage operations via the secure client returned by `useSecureSupabase()` (or the approved pace-core equivalent).
|
|
753
|
+
- **MUST** create the base Supabase client ONCE and pass it to `UnifiedAuthProvider` as `supabaseClient` prop.
|
|
754
|
+
- **MUST** call `useSecureSupabase()` without parameters - it automatically uses the base client from `useUnifiedAuth()` provider layer.
|
|
755
|
+
- **MUST NOT** pass a base client directly to `useSecureSupabase()` - the hook gets it from the provider automatically.
|
|
756
|
+
|
|
757
|
+
### Why this is critical
|
|
758
|
+
|
|
759
|
+
Using `createClient()` directly for queries can bypass organisation context enforcement and RLS policies, leading to:
|
|
760
|
+
- Cross-organisation data access
|
|
761
|
+
- Security vulnerabilities
|
|
762
|
+
- Data leakage between organisations
|
|
763
|
+
|
|
764
|
+
### Correct Pattern
|
|
765
|
+
|
|
766
|
+
```tsx
|
|
767
|
+
// ✅ CORRECT: Create base client ONCE for UnifiedAuthProvider
|
|
768
|
+
// main.tsx or App.tsx
|
|
769
|
+
import { createClient } from '@supabase/supabase-js';
|
|
770
|
+
import { UnifiedAuthProvider } from '@jmruthers/pace-core';
|
|
771
|
+
|
|
772
|
+
const supabase = createClient(
|
|
773
|
+
import.meta.env.VITE_SUPABASE_URL,
|
|
774
|
+
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
|
|
775
|
+
);
|
|
776
|
+
|
|
777
|
+
function App() {
|
|
778
|
+
return (
|
|
779
|
+
<UnifiedAuthProvider
|
|
780
|
+
supabaseClient={supabase} // Pass base client to provider
|
|
781
|
+
appName="YourApp"
|
|
782
|
+
// ... other props
|
|
783
|
+
>
|
|
784
|
+
<YourApp />
|
|
785
|
+
</UnifiedAuthProvider>
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// ✅ CORRECT: Use secure client in components (no parameters needed)
|
|
790
|
+
// YourComponent.tsx
|
|
791
|
+
import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
|
|
792
|
+
|
|
793
|
+
function YourComponent() {
|
|
794
|
+
const secureSupabase = useSecureSupabase(); // Gets client from provider automatically
|
|
795
|
+
|
|
796
|
+
if (!secureSupabase) {
|
|
797
|
+
return <div>Loading...</div>;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// Use secureSupabase for all queries
|
|
801
|
+
const { data } = await secureSupabase.from('users').select('*');
|
|
802
|
+
}
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
### Incorrect Patterns
|
|
806
|
+
|
|
807
|
+
```tsx
|
|
808
|
+
// ❌ FORBIDDEN: Creating client in component or service
|
|
809
|
+
import { createClient } from '@supabase/supabase-js';
|
|
810
|
+
const supabase = createClient(url, key); // Don't do this for queries
|
|
811
|
+
|
|
812
|
+
// ❌ FORBIDDEN: Passing base client to useSecureSupabase
|
|
813
|
+
import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
|
|
814
|
+
import { supabase } from './supabase'; // Don't export base client
|
|
815
|
+
const secureSupabase = useSecureSupabase(supabase); // Don't pass it
|
|
816
|
+
|
|
817
|
+
// ❌ FORBIDDEN: Using base client directly for queries
|
|
818
|
+
const { data } = await supabase.from('users').select('*'); // Bypasses RLS
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
### Hook Signature
|
|
822
|
+
|
|
823
|
+
The `useSecureSupabase()` hook signature is:
|
|
824
|
+
|
|
825
|
+
```typescript
|
|
826
|
+
function useSecureSupabase(
|
|
827
|
+
baseClient?: SupabaseClient<Database> | null
|
|
828
|
+
): SupabaseClient<Database> | null
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
**Important**: The `baseClient` parameter is **optional**. The hook automatically gets the base client from `useUnifiedAuth()` provider layer. You should **NOT** pass a base client parameter - call `useSecureSupabase()` without arguments.
|
|
832
|
+
|
|
833
|
+
### Acceptable Exceptions
|
|
834
|
+
|
|
835
|
+
**The ONLY acceptable use of `createClient()` in consuming app code is:**
|
|
836
|
+
|
|
837
|
+
1. **Creating the base client for `UnifiedAuthProvider`** - This MUST be in one of these files:
|
|
838
|
+
- `src/main.tsx` (or `main.jsx`)
|
|
839
|
+
- `src/App.tsx` (or `App.jsx`)
|
|
840
|
+
- `src/lib/supabase.ts` (or `supabase.js`) - ONLY if this file is ONLY used to create the base client for the provider
|
|
841
|
+
|
|
842
|
+
**The file containing the base client creation MUST:**
|
|
843
|
+
- Be clearly named (e.g., `supabase.ts`, `main.tsx`)
|
|
844
|
+
- Only create the client once
|
|
845
|
+
- Pass it directly to `UnifiedAuthProvider` (not export it for general use)
|
|
846
|
+
- Include a comment explaining it's the base client for the provider:
|
|
847
|
+
```tsx
|
|
848
|
+
// Base Supabase client for UnifiedAuthProvider only
|
|
849
|
+
// DO NOT use this client directly - use useSecureSupabase() instead
|
|
850
|
+
const supabase = createClient(...);
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
**NO OTHER EXCEPTIONS ARE PERMITTED** - All other uses of `createClient()` are security violations and MUST be fixed.
|
|
854
|
+
|
|
855
|
+
### Detection / Audit Tool
|
|
856
|
+
|
|
857
|
+
The audit tool (`npm run audit:pace-core`) performs comprehensive system-level analysis organized by standards:
|
|
858
|
+
|
|
859
|
+
- **Standard 1 (pace-core Compliance)**: Provider nesting, core styles import, RBAC setup, Vite aliases, secure Supabase client location, Cursor rules, ESLint config
|
|
860
|
+
- **Standard 2 (Project Structure)**: Directory structure, config files, import paths, test colocation, Supabase structure
|
|
861
|
+
- **Standard 3 (Architecture)**: Component boundaries, ApiResult usage
|
|
862
|
+
- **Standard 4 (Code Quality)**: TypeScript config, test coverage config
|
|
863
|
+
- **Standard 5 (Styling)**: app.css structure, Tailwind v4 config
|
|
864
|
+
- **Standard 6 (Security & RBAC)**: RLS policies, PagePermissionGuard coverage, Edge Functions RBAC
|
|
865
|
+
- **Standard 7 (API & Tech Stack)**: RPC naming in SQL, tech stack versions, Vite config
|
|
866
|
+
- **Standard 8 (Testing & Documentation)**: Test timeout config, testing tools, test structure
|
|
867
|
+
- **Standard 9 (Operations)**: Error handling patterns, CI/CD config, error boundaries
|
|
868
|
+
|
|
869
|
+
**Reference**: See [packages/core/audit-tool/](../../audit-tool/) for audit tool implementation.
|
|
870
|
+
|
|
871
|
+
### Detection / Audit (Legacy)
|
|
872
|
+
|
|
873
|
+
- `rg "createClient\(" src` must return **exactly ONE match** in the file that creates the base client for `UnifiedAuthProvider`.
|
|
874
|
+
- That file MUST be one of: `main.tsx`, `App.tsx`, or `lib/supabase.ts` (or `.jsx`/`.js` equivalents).
|
|
875
|
+
- No `.from(` / `.rpc(` calls may be performed on an insecure client reference.
|
|
876
|
+
- All `useSecureSupabase()` calls should be without parameters.
|
|
877
|
+
|
|
878
|
+
## Compliance Exceptions
|
|
879
|
+
|
|
880
|
+
**In general, pace-core compliance rules do NOT allow exceptions.** The rules are designed to ensure security, consistency, and maintainability across the PACE suite.
|
|
881
|
+
|
|
882
|
+
### When Exceptions Are NOT Allowed
|
|
883
|
+
|
|
884
|
+
- **Security rules** (e.g., `createClient()` usage) - NO exceptions except the one documented above
|
|
885
|
+
- **RBAC rules** - NO exceptions
|
|
886
|
+
- **Component usage** - NO exceptions (use pace-core components)
|
|
887
|
+
- **Hook usage** - NO exceptions (use pace-core hooks)
|
|
888
|
+
|
|
889
|
+
### Documenting Legitimate Edge Cases
|
|
890
|
+
|
|
891
|
+
If you encounter a situation where a rule seems to conflict with a legitimate requirement:
|
|
892
|
+
|
|
893
|
+
1. **First**: Verify that pace-core doesn't provide a solution
|
|
894
|
+
2. **Second**: Check if the requirement should be added to pace-core
|
|
895
|
+
3. **Third**: If truly unavoidable, document the case clearly:
|
|
896
|
+
- Add a comment explaining why the exception is necessary
|
|
897
|
+
- Include a reference to this standard
|
|
898
|
+
- Consider opening an issue to add the missing functionality to pace-core
|
|
899
|
+
|
|
900
|
+
**Example of proper documentation:**
|
|
901
|
+
```tsx
|
|
902
|
+
// @pace-core-compliance-exception: Legacy integration requires direct Supabase client
|
|
903
|
+
// Reason: Third-party service requires unauthenticated client for initial handshake
|
|
904
|
+
// Migration plan: Migrate to useSecureSupabase() when legacy system is updated (Q2 2025)
|
|
905
|
+
// Tracking issue: https://github.com/your-org/pace-core/issues/123
|
|
906
|
+
// Expected removal date: Q2 2025
|
|
907
|
+
const legacyClient = createClient(...);
|
|
908
|
+
```
|
|
909
|
+
|
|
910
|
+
**Note**: Even with documentation, exceptions should be:
|
|
911
|
+
- Temporary (with a plan to remove them)
|
|
912
|
+
- Rare (only when absolutely necessary)
|
|
913
|
+
- Reviewed and approved by the team
|
|
914
|
+
- Tracked for eventual removal
|
|
915
|
+
|
|
916
|
+
### Audit Handling of Exceptions
|
|
917
|
+
|
|
918
|
+
During audits, documented exceptions will be:
|
|
919
|
+
- **Verified** - Confirmed that the exception is legitimate and properly documented
|
|
920
|
+
- **Categorized** - Marked as "Acceptable Exception" if valid, or flagged for remediation if not
|
|
921
|
+
- **Tracked** - Included in the audit report with a recommendation to remove when possible
|
|
922
|
+
|
|
923
|
+
**Invalid exceptions** (undocumented, unnecessary, or security-related) will be flagged as violations requiring remediation.
|
|
924
|
+
|
|
925
|
+
## Troubleshooting
|
|
926
|
+
|
|
927
|
+
### ESLint Rules Not Working
|
|
928
|
+
|
|
929
|
+
1. **Verify plugin is loaded**: Check that the config is imported correctly
|
|
930
|
+
2. **Check rule names**: Rules must be prefixed with `pace-core-compliance/`
|
|
931
|
+
3. **Verify manifest exists**: Rules load from `core-usage-manifest.json` in the pace-core package
|
|
932
|
+
4. **CommonJS/ES Module issues**: If you're using ES modules and rules aren't loading, ensure you're using the config preset which handles this automatically
|
|
933
|
+
5. **Verify rules are available**: Check that the rules file exists
|
|
934
|
+
6. **Check rule count**: Verify all 15 rules are loaded
|
|
935
|
+
|
|
936
|
+
### Static Analysis Script Errors
|
|
937
|
+
|
|
938
|
+
1. **Manifest not found**: Ensure `core-usage-manifest.json` exists in pace-core package
|
|
939
|
+
2. **No files scanned**: Check that you're running from the project root
|
|
940
|
+
3. **Permission errors**: Ensure script has read access to source files
|
|
941
|
+
|
|
942
|
+
### False Positives
|
|
943
|
+
|
|
944
|
+
If you encounter false positives:
|
|
945
|
+
|
|
946
|
+
1. **Component name conflicts**: If you have a legitimate reason to create a local component with a pace-core name, consider:
|
|
947
|
+
- Renaming your component
|
|
948
|
+
- Using a namespace/prefix
|
|
949
|
+
- Documenting why pace-core doesn't meet your needs
|
|
950
|
+
|
|
951
|
+
2. **Hook/Util patterns**: The pattern matching may flag similar names. Review the suggestion and decide if migration makes sense.
|
|
952
|
+
|
|
953
|
+
## Verification
|
|
954
|
+
|
|
955
|
+
After setting up the ESLint config, verify it's working:
|
|
956
|
+
|
|
957
|
+
1. **Check ESLint can load the config**:
|
|
958
|
+
```bash
|
|
959
|
+
npx eslint --print-config src/App.tsx
|
|
960
|
+
```
|
|
961
|
+
Look for `pace-core-compliance` in the plugins section.
|
|
962
|
+
|
|
963
|
+
2. **Test with a violation**: Create a test file that imports a restricted library:
|
|
964
|
+
```typescript
|
|
965
|
+
// test-violation.ts
|
|
966
|
+
import { Dialog } from '@radix-ui/react-dialog'; // Should trigger error
|
|
967
|
+
```
|
|
968
|
+
Run ESLint and verify it reports the violation.
|
|
969
|
+
|
|
970
|
+
3. **Run static analysis**: Use the compliance script to get a full report:
|
|
971
|
+
```bash
|
|
972
|
+
npm run check:pace-core
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
## Related Documentation
|
|
976
|
+
|
|
977
|
+
- [Standards Overview](./0-standards-overview.md) - Standards system overview
|
|
978
|
+
- [Project Structure](./2-project-structure-standards.md) - Project structure and organization
|
|
979
|
+
- [Security & RBAC](./6-security-rbac-standards.md) - RBAC and security standards
|
|
980
|
+
- [API & Tech Stack](./7-api-tech-stack-standards.md) - API and tech stack standards
|
|
981
|
+
|
|
982
|
+
---
|
|
983
|
+
|
|
984
|
+
**Last Updated:** 2025-01-28
|
|
985
|
+
**Version:** 2.0.0
|
|
986
|
+
**Applies to:** All consuming apps using `@jmruthers/pace-core`
|