@jmruthers/pace-core 0.6.5 → 0.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +104 -0
- package/README.md +5 -403
- package/audit-tool/00-dependencies.cjs +394 -0
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +255 -0
- package/audit-tool/audits/03-architecture.cjs +196 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +544 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +291 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +241 -0
- package/core-usage-manifest.json +93 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/01-pace-core-compliance.mdc +586 -0
- package/cursor-rules/02-project-structure.mdc +42 -4
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
- package/cursor-rules/06-security-rbac.mdc +518 -0
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/DataTable-7PMH7XN7.js +15 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
- package/dist/chunk-6F3IILHI.js +62 -0
- package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
- package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
- package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
- package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
- package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/chunk-GHYHJTYV.js +994 -0
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
- package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
- package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
- package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
- package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
- package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
- package/dist/components.d.ts +7 -5
- package/dist/components.js +46 -257
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +35 -0
- package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
- package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/eslint-rules/utils/helpers.cjs +42 -0
- package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/dist/hooks.d.ts +6 -6
- package/dist/hooks.js +62 -172
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +12 -11
- package/dist/index.js +67 -660
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +8 -35
- package/dist/rbac/eslint-rules.d.ts +46 -44
- package/dist/rbac/eslint-rules.js +7 -4
- package/dist/rbac/index.d.ts +109 -586
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- package/dist/theming/runtime.d.ts +14 -1
- package/dist/theming/runtime.js +3 -19
- package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
- package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +17 -7
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +301 -871
- package/docs/api-reference/components.md +21 -21
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/rpc-functions.md +78 -3
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/installation-guide.md +20 -7
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/getting-started/quick-start.md +23 -12
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +126 -33
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +5 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +17 -8
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/edge-functions-guide.md +376 -0
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -35
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/1-pace-core-compliance-standards.md +986 -0
- package/docs/standards/2-project-structure-standards.md +949 -0
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/5-styling-standards.md +348 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +185 -57
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +33 -6
- package/package.json +35 -23
- package/scripts/install-cursor-rules.cjs +25 -6
- package/scripts/install-eslint-config.cjs +284 -0
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +106 -119
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +12 -9
- package/src/components/DataTable/components/EmptyState.tsx +10 -9
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/RowComponent.tsx +12 -0
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
- package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
- package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
- package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
- package/src/components/DataTable/types.ts +5 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +10 -9
- package/src/components/Dialog/Dialog.test.tsx +128 -104
- package/src/components/Dialog/Dialog.tsx +742 -24
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
- package/src/components/FileDisplay/FileDisplay.tsx +23 -17
- package/src/components/FileUpload/FileUpload.test.tsx +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- package/src/components/Form/Form.test.tsx +6 -8
- package/src/components/Form/Form.tsx +365 -4
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +109 -98
- package/src/components/Select/types.ts +4 -1
- package/src/components/UserMenu/UserMenu.tsx +9 -6
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
- package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
- package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
- package/src/hooks/public/usePublicEvent.ts +67 -195
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +24 -14
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +5 -5
- package/src/hooks/useAppConfig.ts +28 -26
- package/src/hooks/useEventTheme.test.ts +217 -239
- package/src/hooks/useEventTheme.ts +16 -28
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useOrganisationPermissions.ts +5 -7
- package/src/hooks/useQueryCache.ts +0 -1
- package/src/hooks/useSessionDraft.ts +380 -0
- package/src/hooks/useSessionRestoration.ts +3 -1
- package/src/icons/index.ts +27 -0
- package/src/index.ts +5 -0
- package/src/providers/OrganisationProvider.tsx +23 -14
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
- package/src/rbac/adapters.tsx +7 -295
- package/src/rbac/api.test.ts +44 -56
- package/src/rbac/api.ts +10 -17
- package/src/rbac/cache-invalidation.ts +0 -1
- package/src/rbac/compliance/index.ts +10 -0
- package/src/rbac/compliance/pattern-detector.ts +553 -0
- package/src/rbac/compliance/runtime-compliance.ts +22 -0
- package/src/rbac/components/AccessDenied.tsx +150 -0
- package/src/rbac/components/NavigationGuard.tsx +12 -20
- package/src/rbac/components/PagePermissionGuard.tsx +4 -24
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
- package/src/rbac/components/index.ts +3 -41
- package/src/rbac/eslint-rules.js +1 -1
- package/src/rbac/hooks/index.ts +0 -3
- package/src/rbac/hooks/permissions/index.ts +0 -3
- package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
- package/src/rbac/hooks/usePermissions.ts +0 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
- package/src/rbac/hooks/useResolvedScope.ts +58 -140
- package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
- package/src/rbac/hooks/useResourcePermissions.ts +139 -48
- package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
- package/src/rbac/hooks/useRoleManagement.ts +147 -19
- package/src/rbac/hooks/useSecureSupabase.ts +4 -8
- package/src/rbac/index.ts +7 -9
- package/src/rbac/utils/contextValidator.ts +9 -7
- package/src/services/AuthService.ts +130 -18
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +16 -0
- package/src/services/OrganisationService.ts +7 -44
- package/src/services/__tests__/OrganisationService.test.ts +26 -8
- package/src/services/base/BaseService.ts +0 -3
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +9 -3
- package/src/theming/parseEventColours.ts +22 -10
- package/src/types/database.generated.ts +4733 -3809
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
- package/src/utils/context/organisationContext.test.ts +13 -28
- package/src/utils/context/organisationContext.ts +21 -52
- package/src/utils/dynamic/dynamicUtils.ts +1 -1
- package/src/utils/file-reference/index.ts +39 -15
- package/src/utils/formatting/formatDateTime.test.ts +3 -2
- package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
- package/src/utils/index.ts +4 -1
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
- package/src/utils/persistence/keyDerivation.ts +304 -0
- package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
- package/src/utils/security/secureStorage.ts +5 -5
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/helpers.ts +3 -3
- package/src/utils/supabase/createBaseClient.ts +147 -0
- package/src/utils/timezone/timezone.test.ts +1 -2
- package/src/utils/timezone/timezone.ts +1 -1
- package/src/utils/validation/csrf.ts +4 -4
- package/cursor-rules/00-pace-core-compliance.mdc +0 -331
- package/cursor-rules/01-standards-compliance.mdc +0 -244
- package/cursor-rules/04-testing-standards.mdc +0 -268
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
- package/cursor-rules/06-code-quality.mdc +0 -309
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
- package/cursor-rules/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-AOVNCPTX.js +0 -175
- package/dist/DataTable-AOVNCPTX.js.map +0 -1
- package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
- package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
- package/dist/api-O6HTBX5Y.js +0 -52
- package/dist/api-O6HTBX5Y.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6COVEUS7.js.map +0 -1
- package/dist/chunk-AFVQODI2.js +0 -263
- package/dist/chunk-AFVQODI2.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.js.map +0 -1
- package/dist/chunk-EFN2EIMK.js.map +0 -1
- package/dist/chunk-FFQEQTNW.js.map +0 -1
- package/dist/chunk-FMUCXFII.js.map +0 -1
- package/dist/chunk-G37KK66H.js.map +0 -1
- package/dist/chunk-G7QEZTYQ.js +0 -2053
- package/dist/chunk-G7QEZTYQ.js.map +0 -1
- package/dist/chunk-HU2C6SSC.js.map +0 -1
- package/dist/chunk-IHB5DR3H.js.map +0 -1
- package/dist/chunk-IVOFDYWT.js.map +0 -1
- package/dist/chunk-J36DSWQK.js.map +0 -1
- package/dist/chunk-JGRYX5UX.js.map +0 -1
- package/dist/chunk-KQCRWDSA.js +0 -1
- package/dist/chunk-KQCRWDSA.js.map +0 -1
- package/dist/chunk-L4OXEN46.js.map +0 -1
- package/dist/chunk-LMC26NLJ.js +0 -84
- package/dist/chunk-LMC26NLJ.js.map +0 -1
- package/dist/chunk-M43Y4SSO.js.map +0 -1
- package/dist/chunk-M7MPQISP.js.map +0 -1
- package/dist/chunk-NTM7ZSB6.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-RGAWHO7N.js.map +0 -1
- package/dist/chunk-UPPMRMYG.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-5OGXSPKS.js +0 -9
- package/dist/contextValidator-5OGXSPKS.js.map +0 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
- package/dist/hooks.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers.js.map +0 -1
- package/dist/rbac/eslint-rules.js.map +0 -1
- package/dist/rbac/index.js.map +0 -1
- package/dist/styles/index.js.map +0 -1
- package/dist/theming/runtime.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -601
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- package/docs/standards/01-architecture-standard.md +0 -44
- package/docs/standards/02-api-and-rpc-standard.md +0 -39
- package/docs/standards/03-component-standard.md +0 -32
- package/docs/standards/04-code-style-standard.md +0 -32
- package/docs/standards/05-security-standard.md +0 -44
- package/docs/standards/06-testing-and-docs-standard.md +0 -29
- package/docs/standards/pace-core-compliance.md +0 -432
- package/scripts/audit/core/checks/accessibility.cjs +0 -197
- package/scripts/audit/core/checks/api-usage.cjs +0 -191
- package/scripts/audit/core/checks/bundle.cjs +0 -142
- package/scripts/audit/core/checks/compliance.cjs +0 -2706
- package/scripts/audit/core/checks/config.cjs +0 -54
- package/scripts/audit/core/checks/coverage.cjs +0 -84
- package/scripts/audit/core/checks/dependencies.cjs +0 -994
- package/scripts/audit/core/checks/documentation.cjs +0 -268
- package/scripts/audit/core/checks/environment.cjs +0 -116
- package/scripts/audit/core/checks/error-handling.cjs +0 -340
- package/scripts/audit/core/checks/forms.cjs +0 -172
- package/scripts/audit/core/checks/heuristics.cjs +0 -68
- package/scripts/audit/core/checks/hooks.cjs +0 -334
- package/scripts/audit/core/checks/imports.cjs +0 -244
- package/scripts/audit/core/checks/performance.cjs +0 -325
- package/scripts/audit/core/checks/routes.cjs +0 -117
- package/scripts/audit/core/checks/state.cjs +0 -130
- package/scripts/audit/core/checks/structure.cjs +0 -65
- package/scripts/audit/core/checks/style.cjs +0 -584
- package/scripts/audit/core/checks/testing.cjs +0 -122
- package/scripts/audit/core/checks/typescript.cjs +0 -61
- package/scripts/audit/core/scanner.cjs +0 -199
- package/scripts/audit/core/utils.cjs +0 -137
- package/scripts/audit/index.cjs +0 -223
- package/scripts/audit/reporters/console.cjs +0 -151
- package/scripts/audit/reporters/json.cjs +0 -54
- package/scripts/audit/reporters/markdown.cjs +0 -124
- package/scripts/audit-consuming-app.cjs +0 -86
- package/src/components/DataTable/components/DataTableBody.tsx +0 -454
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- package/src/eslint-rules/pace-core-compliance.js +0 -638
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
- package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
- package/src/rbac/components/NavigationProvider.test.tsx +0 -481
- package/src/rbac/components/NavigationProvider.tsx +0 -345
- package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
- package/src/rbac/components/PagePermissionProvider.tsx +0 -279
- package/src/rbac/components/PermissionEnforcer.tsx +0 -312
- package/src/rbac/components/RoleBasedRouter.tsx +0 -440
- package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
- package/src/rbac/components/SecureDataProvider.tsx +0 -339
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# Security Standard
|
|
2
|
-
|
|
3
|
-
## Threat Model
|
|
4
|
-
- Multi-tenant SaaS
|
|
5
|
-
- Untrusted browser environment
|
|
6
|
-
- Supabase backend
|
|
7
|
-
- Risks: RLS gaps, injection, unsafe logging, leaking PII
|
|
8
|
-
|
|
9
|
-
## Security Rules
|
|
10
|
-
- Never bypass RLS
|
|
11
|
-
- Validate all inputs
|
|
12
|
-
- Sanitize logs
|
|
13
|
-
- Never store secrets in code
|
|
14
|
-
- Use safe error messaging
|
|
15
|
-
|
|
16
|
-
## RLS Policy Performance Rules
|
|
17
|
-
- **NEVER use subqueries in RLS policies** - They execute for every row check and cause severe performance degradation
|
|
18
|
-
- **ALWAYS use helper functions** - Create STABLE SECURITY DEFINER functions for lookups (e.g., `get_app_id()`, `get_form_event_id()`)
|
|
19
|
-
- **Helper functions must be**:
|
|
20
|
-
- `STABLE` - Results are consistent within a transaction
|
|
21
|
-
- `SECURITY DEFINER` - Bypass RLS to avoid recursion
|
|
22
|
-
- `SET search_path TO 'public'` - Prevent search path injection
|
|
23
|
-
- **Test RLS policies** - Verify they don't cause query timeouts or N+1 query patterns
|
|
24
|
-
- **Monitor performance** - Watch for slow queries after RLS policy changes
|
|
25
|
-
|
|
26
|
-
**See [RBAC and RLS Standard](./07-rbac-and-rls-standard.md) for detailed RLS policy patterns and helper function documentation.**
|
|
27
|
-
|
|
28
|
-
## Logging Rules
|
|
29
|
-
Allowed:
|
|
30
|
-
- IDs
|
|
31
|
-
- Non-PII metadata
|
|
32
|
-
|
|
33
|
-
Forbidden:
|
|
34
|
-
- Passwords
|
|
35
|
-
- Tokens
|
|
36
|
-
- Sensitive data
|
|
37
|
-
|
|
38
|
-
## Cursor Checklist
|
|
39
|
-
- Confirm RLS is enforced
|
|
40
|
-
- Ensure no sensitive logs
|
|
41
|
-
- Replace raw errors with ApiError
|
|
42
|
-
- Validate input shapes
|
|
43
|
-
- **RLS policies use helper functions, not subqueries**
|
|
44
|
-
- **Helper functions are STABLE and SECURITY DEFINER**
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Testing & Documentation Standard
|
|
2
|
-
|
|
3
|
-
## Testing Strategy
|
|
4
|
-
- Unit tests for utils & hooks
|
|
5
|
-
- Integration tests for components
|
|
6
|
-
- Few meaningful E2E tests (in consuming apps)
|
|
7
|
-
- Coverage: ≥90% utils, ≥70% components
|
|
8
|
-
|
|
9
|
-
## Test Structure
|
|
10
|
-
- Colocated tests (*.test.ts/tsx)
|
|
11
|
-
- Use RTL + userEvent
|
|
12
|
-
- Avoid unnecessary mocks
|
|
13
|
-
|
|
14
|
-
## Documentation Requirements
|
|
15
|
-
- Component READMEs
|
|
16
|
-
- API docs
|
|
17
|
-
- Standards directory
|
|
18
|
-
|
|
19
|
-
## Required Sections
|
|
20
|
-
- Overview
|
|
21
|
-
- API/Props
|
|
22
|
-
- Examples
|
|
23
|
-
- A11y notes
|
|
24
|
-
- Edge cases
|
|
25
|
-
|
|
26
|
-
## Cursor Checklist
|
|
27
|
-
- Update docs after API changes
|
|
28
|
-
- Ensure tests cover critical paths
|
|
29
|
-
- Use RTL patterns only
|
|
@@ -1,432 +0,0 @@
|
|
|
1
|
-
# pace-core Compliance Enforcement
|
|
2
|
-
|
|
3
|
-
This guide explains how to enforce pace-core usage patterns in consuming apps to ensure consistent design, reduce duplication, and maintain high code quality.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
pace-core provides a comprehensive enforcement system that includes:
|
|
8
|
-
|
|
9
|
-
1. **ESLint Rules** - Real-time linting during development
|
|
10
|
-
2. **Static Analysis Script** - Comprehensive codebase scanning
|
|
11
|
-
3. **ESLint Config Preset** - Easy setup for consuming apps
|
|
12
|
-
|
|
13
|
-
## Quick Start
|
|
14
|
-
|
|
15
|
-
### Option 1: ESLint Config Preset (Recommended)
|
|
16
|
-
|
|
17
|
-
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:
|
|
18
|
-
|
|
19
|
-
**For ES Module ESLint Config (eslint.config.js):**
|
|
20
|
-
```javascript
|
|
21
|
-
// eslint.config.js (ES modules)
|
|
22
|
-
import paceCoreConfig from '@jmruthers/pace-core/eslint-config';
|
|
23
|
-
|
|
24
|
-
export default [
|
|
25
|
-
...paceCoreConfig,
|
|
26
|
-
// your other config
|
|
27
|
-
];
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
**For CommonJS ESLint Config (.eslintrc.js or eslint.config.cjs):**
|
|
31
|
-
```javascript
|
|
32
|
-
// eslint.config.cjs (CommonJS)
|
|
33
|
-
const paceCoreConfig = require('@jmruthers/pace-core/eslint-config');
|
|
34
|
-
|
|
35
|
-
module.exports = [
|
|
36
|
-
...paceCoreConfig,
|
|
37
|
-
// your other config
|
|
38
|
-
];
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Option 2: Manual ESLint Rules Setup
|
|
42
|
-
|
|
43
|
-
If you prefer more control, you can import the rules directly. Note: The rules are CommonJS, so use `createRequire` in ES modules:
|
|
44
|
-
|
|
45
|
-
**For ES Module ESLint Config:**
|
|
46
|
-
```javascript
|
|
47
|
-
// eslint.config.js
|
|
48
|
-
import { createRequire } from 'module';
|
|
49
|
-
const require = createRequire(import.meta.url);
|
|
50
|
-
const paceCoreRules = require('@jmruthers/pace-core/eslint-rules').rules;
|
|
51
|
-
|
|
52
|
-
export default [
|
|
53
|
-
{
|
|
54
|
-
plugins: {
|
|
55
|
-
'pace-core-compliance': {
|
|
56
|
-
rules: paceCoreRules
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
rules: {
|
|
60
|
-
'pace-core-compliance/no-restricted-imports': 'error',
|
|
61
|
-
'pace-core-compliance/prefer-pace-core-components': 'warn',
|
|
62
|
-
'pace-core-compliance/prefer-pace-core-hooks': 'warn',
|
|
63
|
-
'pace-core-compliance/prefer-pace-core-utils': 'warn',
|
|
64
|
-
'pace-core-compliance/no-local-component-duplication': 'error'
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
];
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
**For CommonJS ESLint Config:**
|
|
71
|
-
```javascript
|
|
72
|
-
// eslint.config.cjs
|
|
73
|
-
const paceCoreRules = require('@jmruthers/pace-core/eslint-rules').rules;
|
|
74
|
-
|
|
75
|
-
module.exports = [
|
|
76
|
-
{
|
|
77
|
-
plugins: {
|
|
78
|
-
'pace-core-compliance': {
|
|
79
|
-
rules: paceCoreRules
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
rules: {
|
|
83
|
-
'pace-core-compliance/no-restricted-imports': 'error',
|
|
84
|
-
'pace-core-compliance/prefer-pace-core-components': 'warn',
|
|
85
|
-
'pace-core-compliance/prefer-pace-core-hooks': 'warn',
|
|
86
|
-
'pace-core-compliance/prefer-pace-core-utils': 'warn',
|
|
87
|
-
'pace-core-compliance/no-local-component-duplication': 'error'
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
];
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## ESLint Rules
|
|
94
|
-
|
|
95
|
-
### no-restricted-imports
|
|
96
|
-
|
|
97
|
-
**Severity**: Error
|
|
98
|
-
|
|
99
|
-
Blocks direct imports of libraries that pace-core wraps and standardizes.
|
|
100
|
-
|
|
101
|
-
**Restricted Libraries**:
|
|
102
|
-
- `@radix-ui/*` - All Radix UI packages (use pace-core components instead)
|
|
103
|
-
- `lucide-react` - Icons (use pace-core components that include icons)
|
|
104
|
-
- `react-day-picker` - Use `Calendar` from pace-core
|
|
105
|
-
- `@tanstack/react-table` - Use `DataTable` from pace-core
|
|
106
|
-
- `react-hook-form` - Use `Form` and `useZodForm` from pace-core
|
|
107
|
-
- `zod` - Use validation utilities from pace-core
|
|
108
|
-
|
|
109
|
-
**Example Violation**:
|
|
110
|
-
```typescript
|
|
111
|
-
// ❌ Bad
|
|
112
|
-
import { Dialog } from '@radix-ui/react-dialog';
|
|
113
|
-
import { Button } from 'lucide-react';
|
|
114
|
-
|
|
115
|
-
// ✅ Good
|
|
116
|
-
import { Dialog } from '@jmruthers/pace-core';
|
|
117
|
-
import { Button } from '@jmruthers/pace-core';
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### prefer-pace-core-components
|
|
121
|
-
|
|
122
|
-
**Severity**: Warning
|
|
123
|
-
|
|
124
|
-
Suggests using pace-core components instead of native HTML elements.
|
|
125
|
-
|
|
126
|
-
**Detected Patterns**:
|
|
127
|
-
- `<button>` → Use `Button` from pace-core
|
|
128
|
-
- `<input>` → Use `Input` from pace-core
|
|
129
|
-
- `<textarea>` → Use `Textarea` from pace-core
|
|
130
|
-
- `<label>` → Use `Label` from pace-core
|
|
131
|
-
|
|
132
|
-
**Example**:
|
|
133
|
-
```tsx
|
|
134
|
-
// ⚠️ Warning
|
|
135
|
-
<button onClick={handleClick}>Click me</button>
|
|
136
|
-
|
|
137
|
-
// ✅ Recommended
|
|
138
|
-
import { Button } from '@jmruthers/pace-core';
|
|
139
|
-
<Button onClick={handleClick}>Click me</Button>
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### prefer-pace-core-hooks
|
|
143
|
-
|
|
144
|
-
**Severity**: Warning
|
|
145
|
-
|
|
146
|
-
Detects custom hooks that duplicate pace-core functionality.
|
|
147
|
-
|
|
148
|
-
**Common Patterns Detected**:
|
|
149
|
-
- `useToast`, `useNotification` → Use `useToast` from pace-core
|
|
150
|
-
- `useDebounce`, `useDebounced` → Use `useDebounce` from pace-core
|
|
151
|
-
- `useAuth`, `useAuthentication` → Use `useUnifiedAuth` from pace-core
|
|
152
|
-
- `useForm`, `useZodForm` → Use `useZodForm` from pace-core
|
|
153
|
-
|
|
154
|
-
**Example**:
|
|
155
|
-
```typescript
|
|
156
|
-
// ⚠️ Warning
|
|
157
|
-
function useToast() {
|
|
158
|
-
// custom implementation
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// ✅ Recommended
|
|
162
|
-
import { useToast } from '@jmruthers/pace-core';
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### prefer-pace-core-utils
|
|
166
|
-
|
|
167
|
-
**Severity**: Warning
|
|
168
|
-
|
|
169
|
-
Detects utility functions that duplicate pace-core functionality.
|
|
170
|
-
|
|
171
|
-
**Common Patterns Detected**:
|
|
172
|
-
- `formatDate`, `dateFormat` → Use `formatDate` from pace-core
|
|
173
|
-
- `formatCurrency`, `formatMoney` → Use `formatCurrency` from pace-core
|
|
174
|
-
- `cn`, `classNames`, `clsx` → Use `cn` from pace-core
|
|
175
|
-
- `validate`, `validateInput` → Use `validateUserInput` from pace-core
|
|
176
|
-
|
|
177
|
-
**Example**:
|
|
178
|
-
```typescript
|
|
179
|
-
// ⚠️ Warning
|
|
180
|
-
function formatDate(date: Date): string {
|
|
181
|
-
// custom implementation
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// ✅ Recommended
|
|
185
|
-
import { formatDate } from '@jmruthers/pace-core';
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### no-local-component-duplication
|
|
189
|
-
|
|
190
|
-
**Severity**: Error
|
|
191
|
-
|
|
192
|
-
Prevents creating local components with names matching pace-core components.
|
|
193
|
-
|
|
194
|
-
**Example Violation**:
|
|
195
|
-
```
|
|
196
|
-
// ❌ Error: components/Button.tsx
|
|
197
|
-
export function Button() { ... }
|
|
198
|
-
|
|
199
|
-
// pace-core already provides Button component
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
**Fix**: Remove the local component and import from pace-core:
|
|
203
|
-
```typescript
|
|
204
|
-
import { Button } from '@jmruthers/pace-core';
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
## Static Analysis Script
|
|
208
|
-
|
|
209
|
-
The static analysis script provides a comprehensive scan of your codebase and generates a detailed compliance report.
|
|
210
|
-
|
|
211
|
-
### Running the Script
|
|
212
|
-
|
|
213
|
-
```bash
|
|
214
|
-
# From your consuming app root
|
|
215
|
-
node node_modules/@jmruthers/pace-core/scripts/check-pace-core-compliance.cjs
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
Or add it to your `package.json`:
|
|
219
|
-
|
|
220
|
-
```json
|
|
221
|
-
{
|
|
222
|
-
"scripts": {
|
|
223
|
-
"check:pace-core": "node node_modules/@jmruthers/pace-core/scripts/check-pace-core-compliance.cjs"
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
### What It Checks
|
|
229
|
-
|
|
230
|
-
1. **Restricted Imports** - Scans for direct imports of wrapped libraries
|
|
231
|
-
2. **Duplicate Components** - Finds local components matching pace-core names
|
|
232
|
-
3. **Duplicate Hooks** - Finds local hooks matching pace-core hooks
|
|
233
|
-
4. **Duplicate Utils** - Finds local utils matching pace-core utils
|
|
234
|
-
5. **Suggestions** - Recommends pace-core alternatives for native HTML elements
|
|
235
|
-
|
|
236
|
-
### Report Output
|
|
237
|
-
|
|
238
|
-
The script generates a color-coded terminal report showing:
|
|
239
|
-
|
|
240
|
-
- ❌ **Errors** - Critical violations that must be fixed
|
|
241
|
-
- ⚠️ **Warnings** - Issues that should be addressed
|
|
242
|
-
- 💡 **Suggestions** - Recommendations for improvement
|
|
243
|
-
- ✅ **Summary** - Overall compliance status
|
|
244
|
-
|
|
245
|
-
Example output:
|
|
246
|
-
```
|
|
247
|
-
═══════════════════════════════════════════════════════════
|
|
248
|
-
pace-core Compliance Report
|
|
249
|
-
═══════════════════════════════════════════════════════════
|
|
250
|
-
|
|
251
|
-
❌ Restricted Imports Found: 3
|
|
252
|
-
|
|
253
|
-
• src/components/CustomDialog.tsx:5
|
|
254
|
-
Import: @radix-ui/react-dialog
|
|
255
|
-
Reason: Use Dialog component from pace-core instead
|
|
256
|
-
|
|
257
|
-
Summary:
|
|
258
|
-
Total Issues: 3
|
|
259
|
-
- Restricted Imports: 3
|
|
260
|
-
- Duplicate Components/Hooks/Utils: 0
|
|
261
|
-
- Suggestions: 0
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
## Best Practices
|
|
265
|
-
|
|
266
|
-
### 1. Always Import from pace-core
|
|
267
|
-
|
|
268
|
-
```typescript
|
|
269
|
-
// ✅ Good
|
|
270
|
-
import { Button, Card, Dialog } from '@jmruthers/pace-core';
|
|
271
|
-
import { useToast, useDebounce } from '@jmruthers/pace-core';
|
|
272
|
-
import { formatDate, formatCurrency } from '@jmruthers/pace-core';
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
### 2. Use pace-core Components for UI
|
|
276
|
-
|
|
277
|
-
Avoid native HTML elements when pace-core provides a component:
|
|
278
|
-
|
|
279
|
-
```tsx
|
|
280
|
-
// ❌ Avoid
|
|
281
|
-
<button className="btn">Click</button>
|
|
282
|
-
|
|
283
|
-
// ✅ Use pace-core
|
|
284
|
-
<Button>Click</Button>
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
### 3. Leverage pace-core Hooks
|
|
288
|
-
|
|
289
|
-
Don't recreate hooks that pace-core already provides:
|
|
290
|
-
|
|
291
|
-
```typescript
|
|
292
|
-
// ❌ Avoid
|
|
293
|
-
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
294
|
-
useEffect(() => {
|
|
295
|
-
const timer = setTimeout(() => setDebouncedValue(value), 500);
|
|
296
|
-
return () => clearTimeout(timer);
|
|
297
|
-
}, [value]);
|
|
298
|
-
|
|
299
|
-
// ✅ Use pace-core
|
|
300
|
-
import { useDebounce } from '@jmruthers/pace-core';
|
|
301
|
-
const debouncedValue = useDebounce(value, 500);
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
### 4. Use pace-core Utilities
|
|
305
|
-
|
|
306
|
-
Leverage formatting, validation, and other utilities from pace-core:
|
|
307
|
-
|
|
308
|
-
```typescript
|
|
309
|
-
// ❌ Avoid
|
|
310
|
-
const formatted = new Intl.DateTimeFormat('en-US').format(date);
|
|
311
|
-
|
|
312
|
-
// ✅ Use pace-core
|
|
313
|
-
import { formatDate } from '@jmruthers/pace-core';
|
|
314
|
-
const formatted = formatDate(date);
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
### 5. Check Before Creating New Components
|
|
318
|
-
|
|
319
|
-
Before creating a new component, check if pace-core already provides it:
|
|
320
|
-
|
|
321
|
-
1. Review the [pace-core documentation](https://github.com/your-org/pace-core)
|
|
322
|
-
2. Check `core-usage-manifest.json` for available components
|
|
323
|
-
3. Search pace-core exports
|
|
324
|
-
|
|
325
|
-
## Troubleshooting
|
|
326
|
-
|
|
327
|
-
### ESLint Rules Not Working
|
|
328
|
-
|
|
329
|
-
1. **Verify plugin is loaded**: Check that the config is imported correctly:
|
|
330
|
-
```javascript
|
|
331
|
-
// In your eslint.config.js, add temporarily:
|
|
332
|
-
import paceCoreConfig from '@jmruthers/pace-core/eslint-config';
|
|
333
|
-
console.log('Config:', paceCoreConfig);
|
|
334
|
-
console.log('Has plugins:', paceCoreConfig[0]?.plugins);
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
2. **Check rule names**: Rules must be prefixed with `pace-core-compliance/`
|
|
338
|
-
|
|
339
|
-
3. **Verify manifest exists**: Rules load from `core-usage-manifest.json` in the pace-core package
|
|
340
|
-
|
|
341
|
-
4. **CommonJS/ES Module issues**: If you're using ES modules and rules aren't loading:
|
|
342
|
-
- Ensure you're using the config preset (Option 1) which handles this automatically
|
|
343
|
-
- Or use `createRequire` when importing rules directly (Option 2)
|
|
344
|
-
|
|
345
|
-
5. **Verify rules are available**: Check that the rules file exists:
|
|
346
|
-
```bash
|
|
347
|
-
ls node_modules/@jmruthers/pace-core/dist/eslint-rules/pace-core-compliance.cjs
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
### Static Analysis Script Errors
|
|
351
|
-
|
|
352
|
-
1. **Manifest not found**: Ensure `core-usage-manifest.json` exists in pace-core package
|
|
353
|
-
2. **No files scanned**: Check that you're running from the project root
|
|
354
|
-
3. **Permission errors**: Ensure script has read access to source files
|
|
355
|
-
|
|
356
|
-
### False Positives
|
|
357
|
-
|
|
358
|
-
If you encounter false positives:
|
|
359
|
-
|
|
360
|
-
1. **Component name conflicts**: If you have a legitimate reason to create a local component with a pace-core name, consider:
|
|
361
|
-
- Renaming your component
|
|
362
|
-
- Using a namespace/prefix
|
|
363
|
-
- Documenting why pace-core doesn't meet your needs
|
|
364
|
-
|
|
365
|
-
2. **Hook/Util patterns**: The pattern matching may flag similar names. Review the suggestion and decide if migration makes sense.
|
|
366
|
-
|
|
367
|
-
## Integration with CI/CD
|
|
368
|
-
|
|
369
|
-
While CI/CD integration is not included in the initial release, you can easily add it:
|
|
370
|
-
|
|
371
|
-
```yaml
|
|
372
|
-
# .github/workflows/pace-core-compliance.yml
|
|
373
|
-
name: pace-core Compliance
|
|
374
|
-
|
|
375
|
-
on: [push, pull_request]
|
|
376
|
-
|
|
377
|
-
jobs:
|
|
378
|
-
compliance:
|
|
379
|
-
runs-on: ubuntu-latest
|
|
380
|
-
steps:
|
|
381
|
-
- uses: actions/checkout@v3
|
|
382
|
-
- uses: actions/setup-node@v3
|
|
383
|
-
- run: npm ci
|
|
384
|
-
- run: npm run check:pace-core
|
|
385
|
-
- run: npm run lint
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
## Verification
|
|
389
|
-
|
|
390
|
-
After setting up the ESLint config, verify it's working:
|
|
391
|
-
|
|
392
|
-
1. **Check ESLint can load the config**:
|
|
393
|
-
```bash
|
|
394
|
-
npx eslint --print-config src/App.tsx
|
|
395
|
-
```
|
|
396
|
-
Look for `pace-core-compliance` in the plugins section.
|
|
397
|
-
|
|
398
|
-
2. **Test with a violation**: Create a test file that imports a restricted library:
|
|
399
|
-
```typescript
|
|
400
|
-
// test-violation.ts
|
|
401
|
-
import { Dialog } from '@radix-ui/react-dialog'; // Should trigger error
|
|
402
|
-
```
|
|
403
|
-
Run ESLint and verify it reports the violation.
|
|
404
|
-
|
|
405
|
-
3. **Run static analysis**: Use the compliance script to get a full report:
|
|
406
|
-
```bash
|
|
407
|
-
npm run check:pace-core
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
## Getting Help
|
|
411
|
-
|
|
412
|
-
- **Documentation**: See [pace-core docs](../README.md)
|
|
413
|
-
- **Issues**: Report false positives or rule issues
|
|
414
|
-
- **Manifest**: Check `core-usage-manifest.json` for available exports
|
|
415
|
-
- **ESLint Config**: The config file is at `@jmruthers/pace-core/eslint-config` (CommonJS)
|
|
416
|
-
- **ESLint Rules**: The rules are at `@jmruthers/pace-core/eslint-rules` (CommonJS)
|
|
417
|
-
|
|
418
|
-
## File Locations
|
|
419
|
-
|
|
420
|
-
When installed in a consuming app, the compliance tools are available at:
|
|
421
|
-
|
|
422
|
-
- **ESLint Config**: `node_modules/@jmruthers/pace-core/eslint-config-pace-core.cjs`
|
|
423
|
-
- **ESLint Rules**: `node_modules/@jmruthers/pace-core/dist/eslint-rules/pace-core-compliance.cjs`
|
|
424
|
-
- **Static Analysis Script**: `node_modules/@jmruthers/pace-core/scripts/check-pace-core-compliance.cjs`
|
|
425
|
-
- **Manifest**: `node_modules/@jmruthers/pace-core/core-usage-manifest.json`
|
|
426
|
-
|
|
427
|
-
## Related Documentation
|
|
428
|
-
|
|
429
|
-
- [Component Standards](./03-component-standard.md)
|
|
430
|
-
- [API & RPC Standards](./02-api-and-rpc-standard.md)
|
|
431
|
-
- [Getting Started Guide](../getting-started/README.md)
|
|
432
|
-
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Accessibility Check Module
|
|
5
|
-
* @package @jmruthers/pace-core
|
|
6
|
-
* @module Audit/Checks/Accessibility
|
|
7
|
-
*
|
|
8
|
-
* Checks for:
|
|
9
|
-
* - Missing aria-* attributes
|
|
10
|
-
* - Missing keyboard navigation
|
|
11
|
-
* - Missing focus management
|
|
12
|
-
* - Missing alt text on images
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const fs = require('fs');
|
|
16
|
-
const { getRelativePath, getLineNumber } = require('../utils.cjs');
|
|
17
|
-
|
|
18
|
-
const accessibilityCheck = {
|
|
19
|
-
name: 'accessibility',
|
|
20
|
-
description: 'Accessibility checks (aria attributes, keyboard navigation, alt text)',
|
|
21
|
-
severity: 'warning',
|
|
22
|
-
|
|
23
|
-
async run(context) {
|
|
24
|
-
const { projectRoot, files } = context;
|
|
25
|
-
const issues = [];
|
|
26
|
-
const warnings = [];
|
|
27
|
-
const suggestions = [];
|
|
28
|
-
|
|
29
|
-
if (!files || files.length === 0) {
|
|
30
|
-
return { issues, warnings, suggestions };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
for (const filePath of files) {
|
|
34
|
-
try {
|
|
35
|
-
// Only check React component files
|
|
36
|
-
if (!filePath.match(/\.(tsx|jsx)$/)) {
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
41
|
-
const relativePath = getRelativePath(filePath, projectRoot);
|
|
42
|
-
const normalizedPath = relativePath.replace(/\\/g, '/');
|
|
43
|
-
|
|
44
|
-
// Skip root-level src directory - in pace-core repository, this is a demo/showcase app
|
|
45
|
-
// Note: We DO check packages/core/ files because accessibility issues (missing alt attributes, missing form labels) are real issues that should be fixed
|
|
46
|
-
const isRootSrc = normalizedPath.startsWith('src/') && !normalizedPath.includes('packages/');
|
|
47
|
-
if (isRootSrc) {
|
|
48
|
-
continue; // Skip demo app files
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Skip scripts directory - utility scripts don't need accessibility validation
|
|
52
|
-
const isScript = normalizedPath.startsWith('scripts/') || normalizedPath.includes('/scripts/');
|
|
53
|
-
if (isScript) {
|
|
54
|
-
continue; // Skip script files
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Skip pace-core library components and examples - these are designed to accept accessibility props
|
|
58
|
-
// Library components accept id, aria-label, etc. via props spread
|
|
59
|
-
// Examples are demonstration code, not production code
|
|
60
|
-
const isPaceCorePackage = normalizedPath.includes('packages/core/') || normalizedPath.startsWith('packages/core/');
|
|
61
|
-
const isExample = normalizedPath.includes('/examples/');
|
|
62
|
-
const isLibraryComponent = isPaceCorePackage && !isExample;
|
|
63
|
-
|
|
64
|
-
// Check for images without alt text
|
|
65
|
-
// Skip library components - they accept alt as a prop
|
|
66
|
-
if (!isLibraryComponent) {
|
|
67
|
-
const imgPattern = /<img[^>]*>/g;
|
|
68
|
-
let imgMatch;
|
|
69
|
-
while ((imgMatch = imgPattern.exec(content)) !== null) {
|
|
70
|
-
const imgTag = imgMatch[0];
|
|
71
|
-
// Check for alt attribute, including React props (alt=, alt =, alt={)
|
|
72
|
-
const hasAlt = imgTag.includes('alt=') || imgTag.includes('alt =') || imgTag.includes('alt={');
|
|
73
|
-
if (!hasAlt) {
|
|
74
|
-
warnings.push({
|
|
75
|
-
type: 'missing-alt-text',
|
|
76
|
-
file: relativePath,
|
|
77
|
-
line: getLineNumber(content, imgMatch.index),
|
|
78
|
-
message: 'Image element missing alt attribute',
|
|
79
|
-
recommendation: 'Add alt text to all images for accessibility: <img alt="description" ... />'
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Check for buttons/clickable elements without aria-label or accessible text
|
|
86
|
-
const buttonPattern = /<(button|a|div)\s+[^>]*(onClick|role=["']button["'])[^>]*>/g;
|
|
87
|
-
let buttonMatch;
|
|
88
|
-
while ((buttonMatch = buttonPattern.exec(content)) !== null) {
|
|
89
|
-
const buttonTag = buttonMatch[0];
|
|
90
|
-
const hasAriaLabel = buttonTag.includes('aria-label=') || buttonTag.includes('ariaLabel=');
|
|
91
|
-
const hasAccessibleText = buttonTag.includes('>') && content.substring(buttonMatch.index).match(/<[^>]*>([^<]+)</);
|
|
92
|
-
|
|
93
|
-
if (!hasAriaLabel && !hasAccessibleText) {
|
|
94
|
-
warnings.push({
|
|
95
|
-
type: 'missing-aria-label',
|
|
96
|
-
file: relativePath,
|
|
97
|
-
line: getLineNumber(content, buttonMatch.index),
|
|
98
|
-
message: 'Interactive element missing accessible label',
|
|
99
|
-
recommendation: 'Add aria-label or ensure element contains accessible text content'
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Check for form inputs without labels
|
|
105
|
-
// Skip library components - they accept id, aria-label, etc. via props spread
|
|
106
|
-
// Skip examples - they're demonstration code
|
|
107
|
-
if (!isLibraryComponent && !isExample) {
|
|
108
|
-
const inputPattern = /<input[^>]*>/g;
|
|
109
|
-
let inputMatch;
|
|
110
|
-
while ((inputMatch = inputPattern.exec(content)) !== null) {
|
|
111
|
-
// Get the full input tag including multi-line attributes
|
|
112
|
-
const inputStart = inputMatch.index;
|
|
113
|
-
const afterInput = content.substring(inputStart, Math.min(content.length, inputStart + 500));
|
|
114
|
-
const inputTagEnd = afterInput.indexOf('>');
|
|
115
|
-
const fullInputTag = inputTagEnd !== -1 ? afterInput.substring(0, inputTagEnd + 1) : inputMatch[0];
|
|
116
|
-
|
|
117
|
-
// Check for id (including React props)
|
|
118
|
-
const hasId = /id=["']([^"']+)["']|id=\{/.test(fullInputTag);
|
|
119
|
-
// Check for aria-label (including React props)
|
|
120
|
-
const hasAriaLabel = /aria-label=["']|ariaLabel=|aria-label=\{/.test(fullInputTag);
|
|
121
|
-
|
|
122
|
-
if (hasId) {
|
|
123
|
-
const idMatch = fullInputTag.match(/id=["']([^"']+)["']/);
|
|
124
|
-
if (idMatch) {
|
|
125
|
-
const id = idMatch[1];
|
|
126
|
-
// Check if there's a corresponding label
|
|
127
|
-
const beforeInput = content.substring(Math.max(0, inputMatch.index - 200), inputMatch.index);
|
|
128
|
-
const hasLabel = new RegExp(`<label[^>]*for=["']${id}["']`, 'i').test(beforeInput);
|
|
129
|
-
|
|
130
|
-
if (!hasLabel && !hasAriaLabel) {
|
|
131
|
-
warnings.push({
|
|
132
|
-
type: 'missing-input-label',
|
|
133
|
-
file: relativePath,
|
|
134
|
-
line: getLineNumber(content, inputMatch.index),
|
|
135
|
-
message: 'Form input missing associated label',
|
|
136
|
-
recommendation: 'Add a <label> element with for attribute matching input id, or use aria-label'
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
} else if (!hasAriaLabel) {
|
|
141
|
-
warnings.push({
|
|
142
|
-
type: 'missing-input-label',
|
|
143
|
-
file: relativePath,
|
|
144
|
-
line: getLineNumber(content, inputMatch.index),
|
|
145
|
-
message: 'Form input missing id and label',
|
|
146
|
-
recommendation: 'Add id to input and corresponding label, or use aria-label'
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Check for missing focus management in modals/dialogs
|
|
153
|
-
const dialogPattern = /<Dialog|<dialog/gi;
|
|
154
|
-
if (dialogPattern.test(content)) {
|
|
155
|
-
// Skip Dialog.tsx itself - it IS the Dialog component
|
|
156
|
-
if (normalizedPath.includes('/Dialog/Dialog.tsx') || normalizedPath.includes('/Dialog/Dialog.jsx')) {
|
|
157
|
-
continue; // Skip the Dialog component file itself
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Check if Dialog from pace-core is used (which handles focus automatically)
|
|
161
|
-
// Check for both published package import and relative imports (within pace-core repo)
|
|
162
|
-
const usesPaceCoreDialog = content.includes('from \'@jmruthers/pace-core\'') ||
|
|
163
|
-
content.includes('from "@jmruthers/pace-core"') ||
|
|
164
|
-
content.includes('from \'../Dialog') ||
|
|
165
|
-
content.includes('from "../Dialog') ||
|
|
166
|
-
content.includes('from \'../../Dialog') ||
|
|
167
|
-
content.includes('from "../../Dialog') ||
|
|
168
|
-
content.includes('from \'../../../Dialog') ||
|
|
169
|
-
content.includes('from "../../../Dialog') ||
|
|
170
|
-
content.includes('from \'./Dialog') ||
|
|
171
|
-
content.includes('from "./Dialog');
|
|
172
|
-
|
|
173
|
-
if (!usesPaceCoreDialog) {
|
|
174
|
-
suggestions.push({
|
|
175
|
-
type: 'dialog-focus-management',
|
|
176
|
-
file: relativePath,
|
|
177
|
-
message: 'Custom dialog implementation detected',
|
|
178
|
-
recommendation: 'Use Dialog component from @jmruthers/pace-core which handles focus management automatically'
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Check for color contrast issues (heuristic - check for color props without sufficient contrast)
|
|
184
|
-
const colorPattern = /(?:color|bg-|text-)=["']([^"']+)["']/g;
|
|
185
|
-
// This is a simplified check - full implementation would need color contrast calculation
|
|
186
|
-
// For now, just suggest using pace-core components which handle contrast
|
|
187
|
-
|
|
188
|
-
} catch (error) {
|
|
189
|
-
// Skip files with errors
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return { issues, warnings, suggestions };
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
module.exports = accessibilityCheck;
|