@jmruthers/pace-core 0.6.1 → 0.6.3
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 +88 -10
- package/cursor-rules/00-pace-core-compliance.mdc +46 -87
- package/cursor-rules/01-standards-compliance.mdc +16 -47
- package/cursor-rules/02-project-structure.mdc +4 -4
- package/cursor-rules/03-solid-principles.mdc +45 -164
- package/cursor-rules/04-testing-standards.mdc +22 -69
- package/cursor-rules/05-bug-reports-and-features.mdc +2 -2
- package/cursor-rules/06-code-quality.mdc +42 -125
- package/cursor-rules/07-tech-stack-compliance.mdc +33 -128
- package/cursor-rules/08-markup-quality.mdc +452 -0
- package/cursor-rules/CHANGELOG.md +18 -0
- package/cursor-rules/README.md +2 -1
- package/dist/{AuthService-DjnJHDtC.d.ts → AuthService-Cb34EQs3.d.ts} +63 -1
- package/dist/{DataTable-CH1U5Tpy.d.ts → DataTable-BMRU8a1j.d.ts} +33 -1
- package/dist/{DataTable-DQ7RSOHE.js → DataTable-THFPBKTP.js} +12 -10
- package/dist/{PublicPageProvider-ce4xlHYA.d.ts → PublicPageProvider-DEMpysFR.d.ts} +394 -171
- package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CKvHP1MK.d.ts} +30 -8
- package/dist/{UnifiedAuthProvider-ATAP5UTR.js → UnifiedAuthProvider-KAGUYQ4J.js} +5 -4
- package/dist/{api-N774RPUA.js → api-IAGWF3ZG.js} +10 -10
- package/dist/{audit-B5P6FFIR.js → audit-V53FV5AG.js} +2 -2
- package/dist/{chunk-JBKQ3SAO.js → chunk-2T2IG7T7.js} +107 -57
- package/dist/chunk-2T2IG7T7.js.map +1 -0
- package/dist/{chunk-3QRJFVBR.js → chunk-6SOIHG6Z.js} +1 -1
- package/dist/chunk-6SOIHG6Z.js.map +1 -0
- package/dist/{chunk-3XTALGJF.js → chunk-6Z7LTB3D.js} +69 -240
- package/dist/chunk-6Z7LTB3D.js.map +1 -0
- package/dist/{chunk-4ZC4GX36.js → chunk-CNCQDFLN.js} +199 -46
- package/dist/chunk-CNCQDFLN.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/{chunk-BYFSK72L.js → chunk-DWUBLJJM.js} +361 -187
- package/dist/chunk-DWUBLJJM.js.map +1 -0
- package/dist/{chunk-LXQLPRQ2.js → chunk-FFQEQTNW.js} +6 -8
- package/dist/chunk-FFQEQTNW.js.map +1 -0
- package/dist/chunk-FMUCXFII.js +76 -0
- package/dist/chunk-FMUCXFII.js.map +1 -0
- package/dist/{chunk-4N5C5XZU.js → chunk-HFZBI76P.js} +4 -4
- package/dist/chunk-HFZBI76P.js.map +1 -0
- package/dist/{chunk-SQGMNID3.js → chunk-L4OXEN46.js} +4 -5
- package/dist/chunk-L4OXEN46.js.map +1 -0
- package/dist/{chunk-R77UEZ4E.js → chunk-M43Y4SSO.js} +1 -1
- package/dist/chunk-M43Y4SSO.js.map +1 -0
- package/dist/{chunk-I7PSE6JW.js → chunk-M7MPQISP.js} +3 -76
- package/dist/chunk-M7MPQISP.js.map +1 -0
- package/dist/chunk-PQBSKX33.js +7793 -0
- package/dist/chunk-PQBSKX33.js.map +1 -0
- package/dist/chunk-QRPVRXYT.js +226 -0
- package/dist/chunk-QRPVRXYT.js.map +1 -0
- package/dist/{chunk-KNC55RTG.js → chunk-RWEBCB47.js} +194 -416
- package/dist/chunk-RWEBCB47.js.map +1 -0
- package/dist/{chunk-XM25TVIE.js → chunk-YDQHOZNA.js} +843 -388
- package/dist/chunk-YDQHOZNA.js.map +1 -0
- package/dist/{chunk-GLK6VM3F.js → chunk-ZNIWI3UC.js} +739 -737
- package/dist/chunk-ZNIWI3UC.js.map +1 -0
- package/dist/components.d.ts +5 -5
- package/dist/components.js +18 -16
- package/dist/components.js.map +1 -1
- package/dist/contextValidator-3JNZKUTX.js +9 -0
- package/dist/contextValidator-3JNZKUTX.js.map +1 -0
- package/dist/eslint-rules/pace-core-compliance.cjs +106 -0
- package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
- package/dist/hooks.d.ts +55 -122
- package/dist/hooks.js +10 -13
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +60 -13
- package/dist/index.js +30 -25
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +21 -3
- package/dist/providers.js +4 -3
- package/dist/rbac/index.d.ts +210 -139
- package/dist/rbac/index.js +17 -13
- package/dist/styles/index.js +1 -1
- package/dist/theming/runtime.d.ts +1 -13
- package/dist/theming/runtime.js +2 -2
- package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
- package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
- package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- package/dist/{usePublicRouteParams-BJAlWfuJ.d.ts → usePublicRouteParams-i3qtoBgg.d.ts} +38 -17
- package/dist/utils.d.ts +4 -5
- package/dist/utils.js +17 -19
- package/dist/utils.js.map +1 -1
- package/docs/api/README.md +21 -17
- package/docs/api/modules.md +4191 -2967
- package/docs/architecture/database-schema-requirements.md +161 -0
- package/docs/components/context-selector.md +126 -0
- package/docs/core-concepts/rbac-system.md +3 -3
- package/docs/documentation-index.md +2 -4
- package/docs/getting-started/cursor-rules.md +2 -1
- package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
- package/docs/migration/MIGRATION_GUIDE.md +2 -24
- package/docs/migration/RBAC_SCOPE_MIGRATION.md +385 -0
- package/docs/migration/README.md +52 -6
- package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
- package/docs/migration/database-changes-december-2025.md +3 -3
- package/docs/pace-mint-fix-auto-selection.md +218 -0
- package/docs/pace-mint-rbac-setup.md +391 -0
- package/docs/rbac/event-based-apps.md +1 -1
- package/docs/rbac/getting-started.md +1 -1
- package/docs/rbac/quick-start.md +1 -1
- package/docs/rbac/secure-client-protection.md +330 -0
- package/docs/standards/README.md +1 -0
- package/package.json +4 -3
- package/scripts/audit/core/checks/accessibility.cjs +197 -0
- package/scripts/audit/core/checks/api-usage.cjs +191 -0
- package/scripts/audit/core/checks/bundle.cjs +142 -0
- package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +784 -685
- package/scripts/audit/core/checks/config.cjs +54 -0
- package/scripts/audit/core/checks/coverage.cjs +84 -0
- package/scripts/audit/core/checks/dependencies.cjs +985 -0
- package/scripts/audit/core/checks/documentation.cjs +268 -0
- package/scripts/audit/core/checks/environment.cjs +116 -0
- package/scripts/audit/core/checks/error-handling.cjs +340 -0
- package/scripts/audit/core/checks/forms.cjs +172 -0
- package/scripts/audit/core/checks/heuristics.cjs +68 -0
- package/scripts/audit/core/checks/hooks.cjs +334 -0
- package/scripts/audit/core/checks/imports.cjs +244 -0
- package/scripts/audit/core/checks/performance.cjs +325 -0
- package/scripts/audit/core/checks/routes.cjs +117 -0
- package/scripts/audit/core/checks/state.cjs +130 -0
- package/scripts/audit/core/checks/structure.cjs +65 -0
- package/scripts/audit/core/checks/style.cjs +584 -0
- package/scripts/audit/core/checks/testing.cjs +122 -0
- package/scripts/audit/core/checks/typescript.cjs +61 -0
- package/scripts/audit/core/scanner.cjs +199 -0
- package/scripts/audit/core/utils.cjs +137 -0
- package/scripts/audit/index.cjs +223 -0
- package/scripts/audit/reporters/console.cjs +151 -0
- package/scripts/audit/reporters/json.cjs +54 -0
- package/scripts/audit/reporters/markdown.cjs +124 -0
- package/scripts/audit-consuming-app.cjs +61 -936
- package/scripts/build-docs/build-decision.js +240 -0
- package/scripts/build-docs/cache-utils.js +105 -0
- package/scripts/build-docs/content-normalization.js +150 -0
- package/scripts/build-docs/file-utils.js +105 -0
- package/scripts/build-docs/git-utils.js +86 -0
- package/scripts/build-docs/hash-utils.js +116 -0
- package/scripts/build-docs/typedoc-runner.js +220 -0
- package/scripts/build-docs-incremental.js +77 -913
- package/scripts/utils/command-runner.js +16 -11
- package/scripts/validate-formats.js +61 -56
- package/scripts/validate-master.js +74 -69
- package/scripts/validate-pre-publish.js +70 -65
- package/src/__tests__/hooks/usePermissions.test.ts +2 -2
- package/src/components/Alert/Alert.test.tsx +12 -18
- package/src/components/Alert/Alert.tsx +5 -7
- package/src/components/Avatar/Avatar.test.tsx +4 -4
- package/src/components/Badge/Badge.tsx +14 -0
- package/src/components/Button/Button.tsx +22 -0
- package/src/components/Calendar/Calendar.tsx +8 -2
- package/src/components/Card/Card.tsx +4 -0
- package/src/components/Checkbox/Checkbox.test.tsx +12 -12
- package/src/components/Checkbox/Checkbox.tsx +2 -2
- package/src/components/ContextSelector/ContextSelector.tsx +384 -0
- package/src/components/ContextSelector/index.ts +3 -0
- package/src/components/DataTable/DataTable.tsx +38 -4
- package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +18 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
- package/src/components/DataTable/components/AccessDeniedPage.tsx +16 -25
- package/src/components/DataTable/components/ActionButtons.tsx +10 -7
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +1 -1
- package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
- package/src/components/DataTable/components/DataTableBody.tsx +8 -0
- package/src/components/DataTable/components/DataTableCore.tsx +196 -554
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
- package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
- package/src/components/DataTable/components/DataTableModals.tsx +8 -0
- package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
- package/src/components/DataTable/components/EditFields.tsx +307 -0
- package/src/components/DataTable/components/EditableRow.tsx +8 -0
- package/src/components/DataTable/components/EmptyState.tsx +10 -0
- package/src/components/DataTable/components/FilterRow.tsx +12 -0
- package/src/components/DataTable/components/GroupHeader.tsx +12 -0
- package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
- package/src/components/DataTable/components/ImportModal.tsx +7 -0
- package/src/components/DataTable/components/LoadingState.tsx +6 -0
- package/src/components/DataTable/components/PaginationControls.tsx +16 -1
- package/src/components/DataTable/components/RowComponent.tsx +391 -0
- package/src/components/DataTable/components/UnifiedTableBody.tsx +63 -851
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
- package/src/components/DataTable/components/cellValueUtils.ts +40 -0
- package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
- package/src/components/DataTable/context/DataTableContext.tsx +50 -0
- package/src/components/DataTable/core/ColumnFactory.ts +31 -0
- package/src/components/DataTable/core/DataTableContext.tsx +32 -1
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
- package/src/components/DataTable/hooks/useColumnReordering.ts +12 -0
- package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
- package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +127 -33
- package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
- package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
- package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
- package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
- package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
- package/src/components/DataTable/styles.ts +6 -6
- package/src/components/DataTable/types.ts +6 -10
- package/src/components/DataTable/utils/a11yUtils.ts +7 -0
- package/src/components/DataTable/utils/debugTools.ts +18 -113
- package/src/components/DataTable/utils/errorHandling.ts +12 -0
- package/src/components/DataTable/utils/exportUtils.ts +9 -0
- package/src/components/DataTable/utils/flexibleImport.ts +12 -48
- package/src/components/DataTable/utils/paginationUtils.ts +8 -0
- package/src/components/DataTable/utils/performanceUtils.ts +5 -1
- package/src/components/Dialog/Dialog.tsx +31 -3
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +45 -5
- package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
- package/src/components/ErrorBoundary/index.ts +27 -2
- package/src/components/FileDisplay/FileDisplay.tsx +74 -28
- package/src/components/FileUpload/FileUpload.tsx +22 -2
- package/src/components/Footer/Footer.test.tsx +16 -16
- package/src/components/Footer/Footer.tsx +14 -11
- package/src/components/Form/Form.tsx +1 -0
- package/src/components/Header/Header.test.tsx +43 -73
- package/src/components/Header/Header.tsx +59 -49
- package/src/components/Input/Input.test.tsx +2 -2
- package/src/components/Input/Input.tsx +8 -4
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
- package/src/components/LoginForm/LoginForm.tsx +4 -0
- package/src/components/NavigationMenu/NavigationMenu.tsx +14 -513
- package/src/components/NavigationMenu/types.ts +56 -0
- package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +10 -19
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +2 -2
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +5 -5
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +13 -11
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +167 -44
- package/src/components/PaceAppLayout/README.md +14 -17
- package/src/components/PaceAppLayout/test-setup.tsx +3 -4
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +3 -0
- package/src/components/PasswordChange/PasswordChangeForm.tsx +9 -0
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
- package/src/components/PublicLayout/PublicPageLayout.tsx +2 -5
- package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
- package/src/components/Select/Select.tsx +80 -434
- package/src/components/Select/context.ts +23 -0
- package/src/components/Select/hooks/useSelectEvents.ts +87 -0
- package/src/components/Select/hooks/useSelectSearch.ts +91 -0
- package/src/components/Select/hooks/useSelectState.ts +104 -0
- package/src/components/Select/index.ts +9 -1
- package/src/components/Select/types.ts +123 -0
- package/src/components/Select/utils/text.ts +26 -0
- package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +4 -5
- package/src/components/Switch/Switch.tsx +4 -4
- package/src/components/Tabs/Tabs.tsx +1 -1
- package/src/components/Toast/Toast.tsx +4 -0
- package/src/components/Tooltip/Tooltip.tsx +2 -2
- package/src/components/UserMenu/UserMenu.test.tsx +24 -11
- package/src/components/UserMenu/UserMenu.tsx +21 -18
- package/src/components/index.ts +7 -7
- package/src/eslint-rules/pace-core-compliance.cjs +106 -0
- package/src/hooks/__tests__/index.unit.test.ts +2 -5
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +4 -98
- package/src/hooks/index.ts +1 -2
- package/src/hooks/public/usePublicEvent.ts +4 -0
- package/src/hooks/public/usePublicEventLogo.ts +4 -0
- package/src/hooks/public/usePublicFileDisplay.ts +4 -0
- package/src/hooks/public/usePublicRouteParams.ts +4 -0
- package/src/hooks/services/useAuth.ts +32 -0
- package/src/hooks/services/useCurrentEvent.ts +6 -0
- package/src/hooks/services/useCurrentOrganisation.ts +6 -0
- package/src/hooks/useAppConfig.ts +15 -30
- package/src/hooks/useDebounce.ts +9 -0
- package/src/hooks/useEventTheme.ts +6 -0
- package/src/hooks/useFileDisplay.ts +81 -50
- package/src/hooks/useFileReference.ts +25 -7
- package/src/hooks/useFileUrl.ts +11 -1
- package/src/hooks/useFocusManagement.ts +14 -0
- package/src/hooks/useFocusTrap.ts +3 -0
- package/src/hooks/useInactivityTracker.ts +3 -0
- package/src/hooks/useKeyboardShortcuts.ts +4 -0
- package/src/hooks/useOrganisationPermissions.ts +4 -0
- package/src/hooks/useOrganisationSecurity.ts +4 -0
- package/src/hooks/usePerformanceMonitor.ts +4 -0
- package/src/hooks/usePermissionCache.ts +7 -0
- package/src/hooks/useQueryCache.ts +12 -1
- package/src/hooks/useSessionRestoration.ts +4 -0
- package/src/hooks/useStorage.ts +4 -0
- package/src/hooks/useToast.ts +1 -1
- package/src/index.ts +6 -6
- package/src/providers/__tests__/OrganisationProvider.test.tsx +92 -70
- package/src/providers/services/AuthServiceProvider.tsx +35 -7
- package/src/providers/services/EventServiceProvider.tsx +51 -5
- package/src/providers/services/InactivityServiceProvider.tsx +18 -0
- package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
- package/src/providers/services/UnifiedAuthProvider.tsx +126 -134
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +29 -13
- package/src/rbac/README.md +1 -1
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +1 -1
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
- package/src/rbac/adapters.tsx +12 -3
- package/src/rbac/api.test.ts +59 -51
- package/src/rbac/api.ts +246 -167
- package/src/rbac/components/NavigationProvider.tsx +4 -1
- package/src/rbac/components/PagePermissionGuard.tsx +185 -17
- package/src/rbac/components/RoleBasedRouter.tsx +5 -1
- package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
- package/src/rbac/components/SecureDataProvider.tsx +20 -5
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
- package/src/rbac/engine.ts +38 -14
- package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +32 -21
- package/src/rbac/hooks/permissions/index.ts +7 -0
- package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
- package/src/rbac/hooks/permissions/useCan.ts +377 -0
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
- package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
- package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
- package/src/rbac/hooks/useCan.test.ts +64 -66
- package/src/rbac/hooks/usePermissions.ts +14 -995
- package/src/rbac/hooks/useRBAC.test.ts +1 -5
- package/src/rbac/hooks/useRBAC.ts +36 -37
- package/src/rbac/hooks/useResolvedScope.test.ts +120 -35
- package/src/rbac/hooks/useResolvedScope.ts +35 -40
- package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
- package/src/rbac/hooks/useResourcePermissions.ts +14 -4
- package/src/rbac/hooks/useSecureSupabase.ts +27 -7
- package/src/rbac/index.ts +7 -0
- package/src/rbac/permissions.ts +0 -30
- package/src/rbac/secureClient.test.ts +22 -18
- package/src/rbac/secureClient.ts +294 -68
- package/src/rbac/security.ts +0 -17
- package/src/rbac/types.ts +9 -0
- package/src/rbac/utils/__tests__/contextValidator.test.ts +64 -86
- package/src/rbac/utils/clientSecurity.ts +93 -0
- package/src/rbac/utils/contextValidator.ts +77 -168
- package/src/services/AuthService.ts +39 -7
- package/src/services/EventService.ts +186 -54
- package/src/services/OrganisationService.ts +81 -14
- package/src/services/__tests__/EventService.test.ts +1 -2
- package/src/services/base/BaseService.ts +3 -0
- package/src/theming/__tests__/parseEventColours.test.ts +6 -9
- package/src/theming/parseEventColours.ts +5 -19
- package/src/types/vitest-globals.d.ts +51 -26
- package/src/utils/__mocks__/supabaseMock.ts +1 -3
- package/src/utils/__tests__/formatting.unit.test.ts +4 -4
- package/src/utils/__tests__/index.unit.test.ts +2 -2
- package/src/utils/audit/audit.ts +0 -3
- package/src/utils/core/cn.ts +1 -1
- package/src/utils/dynamic/dynamicUtils.ts +7 -4
- package/src/utils/file-reference/index.ts +53 -1
- package/src/utils/formatting/formatting.ts +8 -18
- package/src/utils/index.ts +0 -1
- package/dist/chunk-3QRJFVBR.js.map +0 -1
- package/dist/chunk-3XTALGJF.js.map +0 -1
- package/dist/chunk-4N5C5XZU.js.map +0 -1
- package/dist/chunk-4ZC4GX36.js.map +0 -1
- package/dist/chunk-7D4SUZUM.js +0 -38
- package/dist/chunk-BYFSK72L.js.map +0 -1
- package/dist/chunk-EXUD6RNJ.js +0 -451
- package/dist/chunk-EXUD6RNJ.js.map +0 -1
- package/dist/chunk-GLK6VM3F.js.map +0 -1
- package/dist/chunk-I7PSE6JW.js.map +0 -1
- package/dist/chunk-JBKQ3SAO.js.map +0 -1
- package/dist/chunk-KNC55RTG.js.map +0 -1
- package/dist/chunk-LXQLPRQ2.js.map +0 -1
- package/dist/chunk-R77UEZ4E.js.map +0 -1
- package/dist/chunk-SQGMNID3.js.map +0 -1
- package/dist/chunk-T33XF5ZC.js +0 -12922
- package/dist/chunk-T33XF5ZC.js.map +0 -1
- package/dist/chunk-XM25TVIE.js.map +0 -1
- package/docs/api/classes/ColumnFactory.md +0 -243
- package/docs/api/classes/ErrorBoundary.md +0 -144
- package/docs/api/classes/InvalidScopeError.md +0 -73
- package/docs/api/classes/Logger.md +0 -178
- package/docs/api/classes/MissingUserContextError.md +0 -66
- package/docs/api/classes/OrganisationContextRequiredError.md +0 -66
- package/docs/api/classes/PermissionDeniedError.md +0 -73
- package/docs/api/classes/RBACAuditManager.md +0 -297
- package/docs/api/classes/RBACCache.md +0 -322
- package/docs/api/classes/RBACEngine.md +0 -171
- package/docs/api/classes/RBACError.md +0 -76
- package/docs/api/classes/RBACNotInitializedError.md +0 -66
- package/docs/api/classes/SecureSupabaseClient.md +0 -160
- package/docs/api/classes/StorageUtils.md +0 -328
- package/docs/api/enums/FileCategory.md +0 -184
- package/docs/api/enums/LogLevel.md +0 -54
- package/docs/api/enums/RBACErrorCode.md +0 -228
- package/docs/api/enums/RPCFunction.md +0 -118
- package/docs/api/interfaces/AddressFieldProps.md +0 -241
- package/docs/api/interfaces/AddressFieldRef.md +0 -94
- package/docs/api/interfaces/AggregateConfig.md +0 -43
- package/docs/api/interfaces/AutocompleteOptions.md +0 -75
- package/docs/api/interfaces/AvatarProps.md +0 -128
- package/docs/api/interfaces/BadgeProps.md +0 -27
- package/docs/api/interfaces/ButtonProps.md +0 -53
- package/docs/api/interfaces/CalendarProps.md +0 -70
- package/docs/api/interfaces/CardProps.md +0 -66
- package/docs/api/interfaces/ColorPalette.md +0 -7
- package/docs/api/interfaces/ColorShade.md +0 -66
- package/docs/api/interfaces/ComplianceResult.md +0 -30
- package/docs/api/interfaces/DataAccessRecord.md +0 -96
- package/docs/api/interfaces/DataRecord.md +0 -11
- package/docs/api/interfaces/DataTableAction.md +0 -249
- package/docs/api/interfaces/DataTableColumn.md +0 -504
- package/docs/api/interfaces/DataTableProps.md +0 -625
- package/docs/api/interfaces/DataTableToolbarButton.md +0 -96
- package/docs/api/interfaces/DatabaseComplianceResult.md +0 -85
- package/docs/api/interfaces/DatabaseIssue.md +0 -41
- package/docs/api/interfaces/EmptyStateConfig.md +0 -61
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +0 -235
- package/docs/api/interfaces/EventAppRoleData.md +0 -71
- package/docs/api/interfaces/ExportColumn.md +0 -90
- package/docs/api/interfaces/ExportOptions.md +0 -126
- package/docs/api/interfaces/FileDisplayProps.md +0 -249
- package/docs/api/interfaces/FileMetadata.md +0 -129
- package/docs/api/interfaces/FileReference.md +0 -118
- package/docs/api/interfaces/FileSizeLimits.md +0 -7
- package/docs/api/interfaces/FileUploadOptions.md +0 -139
- package/docs/api/interfaces/FileUploadProps.md +0 -293
- package/docs/api/interfaces/FooterProps.md +0 -105
- package/docs/api/interfaces/FormFieldProps.md +0 -166
- package/docs/api/interfaces/FormProps.md +0 -113
- package/docs/api/interfaces/GrantEventAppRoleParams.md +0 -122
- package/docs/api/interfaces/InactivityWarningModalProps.md +0 -115
- package/docs/api/interfaces/InputProps.md +0 -53
- package/docs/api/interfaces/LabelProps.md +0 -107
- package/docs/api/interfaces/LoggerConfig.md +0 -62
- package/docs/api/interfaces/LoginFormProps.md +0 -184
- package/docs/api/interfaces/NavigationAccessRecord.md +0 -107
- package/docs/api/interfaces/NavigationContextType.md +0 -164
- package/docs/api/interfaces/NavigationGuardProps.md +0 -139
- package/docs/api/interfaces/NavigationItem.md +0 -120
- package/docs/api/interfaces/NavigationMenuProps.md +0 -221
- package/docs/api/interfaces/NavigationProviderProps.md +0 -117
- package/docs/api/interfaces/Organisation.md +0 -140
- package/docs/api/interfaces/OrganisationContextType.md +0 -388
- package/docs/api/interfaces/OrganisationMembership.md +0 -140
- package/docs/api/interfaces/OrganisationProviderProps.md +0 -76
- package/docs/api/interfaces/OrganisationSecurityError.md +0 -62
- package/docs/api/interfaces/PaceAppLayoutProps.md +0 -406
- package/docs/api/interfaces/PaceLoginPageProps.md +0 -47
- package/docs/api/interfaces/PageAccessRecord.md +0 -85
- package/docs/api/interfaces/PagePermissionContextType.md +0 -140
- package/docs/api/interfaces/PagePermissionGuardProps.md +0 -153
- package/docs/api/interfaces/PagePermissionProviderProps.md +0 -119
- package/docs/api/interfaces/PaletteData.md +0 -41
- package/docs/api/interfaces/ParsedAddress.md +0 -120
- package/docs/api/interfaces/PermissionEnforcerProps.md +0 -153
- package/docs/api/interfaces/ProgressProps.md +0 -42
- package/docs/api/interfaces/ProtectedRouteProps.md +0 -97
- package/docs/api/interfaces/PublicPageFooterProps.md +0 -112
- package/docs/api/interfaces/PublicPageHeaderProps.md +0 -125
- package/docs/api/interfaces/PublicPageLayoutProps.md +0 -198
- package/docs/api/interfaces/QuickFix.md +0 -52
- package/docs/api/interfaces/RBACAccessValidateParams.md +0 -52
- package/docs/api/interfaces/RBACAccessValidateResult.md +0 -41
- package/docs/api/interfaces/RBACAuditLogParams.md +0 -85
- package/docs/api/interfaces/RBACAuditLogResult.md +0 -52
- package/docs/api/interfaces/RBACConfig.md +0 -133
- package/docs/api/interfaces/RBACContext.md +0 -52
- package/docs/api/interfaces/RBACLogger.md +0 -112
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +0 -74
- package/docs/api/interfaces/RBACPerformanceMetrics.md +0 -138
- package/docs/api/interfaces/RBACPermissionCheckParams.md +0 -74
- package/docs/api/interfaces/RBACPermissionCheckResult.md +0 -52
- package/docs/api/interfaces/RBACPermissionsGetParams.md +0 -63
- package/docs/api/interfaces/RBACPermissionsGetResult.md +0 -63
- package/docs/api/interfaces/RBACResult.md +0 -58
- package/docs/api/interfaces/RBACRoleGrantParams.md +0 -63
- package/docs/api/interfaces/RBACRoleGrantResult.md +0 -52
- package/docs/api/interfaces/RBACRoleRevokeParams.md +0 -63
- package/docs/api/interfaces/RBACRoleRevokeResult.md +0 -52
- package/docs/api/interfaces/RBACRoleValidateParams.md +0 -52
- package/docs/api/interfaces/RBACRoleValidateResult.md +0 -63
- package/docs/api/interfaces/RBACRolesListParams.md +0 -52
- package/docs/api/interfaces/RBACRolesListResult.md +0 -74
- package/docs/api/interfaces/RBACSessionTrackParams.md +0 -74
- package/docs/api/interfaces/RBACSessionTrackResult.md +0 -52
- package/docs/api/interfaces/ResourcePermissions.md +0 -155
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +0 -100
- package/docs/api/interfaces/RoleBasedRouterContextType.md +0 -151
- package/docs/api/interfaces/RoleBasedRouterProps.md +0 -156
- package/docs/api/interfaces/RoleManagementResult.md +0 -52
- package/docs/api/interfaces/RouteAccessRecord.md +0 -107
- package/docs/api/interfaces/RouteConfig.md +0 -134
- package/docs/api/interfaces/RuntimeComplianceResult.md +0 -55
- package/docs/api/interfaces/SecureDataContextType.md +0 -168
- package/docs/api/interfaces/SecureDataProviderProps.md +0 -132
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +0 -34
- package/docs/api/interfaces/SetupIssue.md +0 -41
- package/docs/api/interfaces/StorageConfig.md +0 -41
- package/docs/api/interfaces/StorageFileInfo.md +0 -74
- package/docs/api/interfaces/StorageFileMetadata.md +0 -151
- package/docs/api/interfaces/StorageListOptions.md +0 -99
- package/docs/api/interfaces/StorageListResult.md +0 -41
- package/docs/api/interfaces/StorageUploadOptions.md +0 -101
- package/docs/api/interfaces/StorageUploadResult.md +0 -63
- package/docs/api/interfaces/StorageUrlOptions.md +0 -60
- package/docs/api/interfaces/StyleImport.md +0 -19
- package/docs/api/interfaces/SwitchProps.md +0 -34
- package/docs/api/interfaces/TabsContentProps.md +0 -9
- package/docs/api/interfaces/TabsListProps.md +0 -9
- package/docs/api/interfaces/TabsProps.md +0 -9
- package/docs/api/interfaces/TabsTriggerProps.md +0 -50
- package/docs/api/interfaces/TextareaProps.md +0 -53
- package/docs/api/interfaces/ToastActionElement.md +0 -9
- package/docs/api/interfaces/ToastProps.md +0 -9
- package/docs/api/interfaces/UnifiedAuthContextType.md +0 -820
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +0 -171
- package/docs/api/interfaces/UseFormDialogOptions.md +0 -62
- package/docs/api/interfaces/UseFormDialogReturn.md +0 -117
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +0 -136
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +0 -123
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +0 -87
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +0 -81
- package/docs/api/interfaces/UsePublicEventOptions.md +0 -34
- package/docs/api/interfaces/UsePublicEventReturn.md +0 -68
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +0 -47
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +0 -120
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +0 -94
- package/docs/api/interfaces/UseResolvedScopeOptions.md +0 -47
- package/docs/api/interfaces/UseResolvedScopeReturn.md +0 -47
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +0 -34
- package/docs/api/interfaces/UserEventAccess.md +0 -118
- package/docs/api/interfaces/UserMenuProps.md +0 -86
- package/docs/api/interfaces/UserProfile.md +0 -63
- package/docs/migration/quick-migration-guide.md +0 -356
- package/docs/migration/service-architecture.md +0 -281
- package/src/components/EventSelector/EventSelector.test.tsx +0 -720
- package/src/components/EventSelector/EventSelector.tsx +0 -420
- package/src/components/EventSelector/index.ts +0 -3
- package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +0 -784
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +0 -324
- package/src/components/OrganisationSelector/index.ts +0 -9
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
- package/src/hooks/useSecureDataAccess.test.ts +0 -559
- package/src/hooks/useSecureDataAccess.ts +0 -681
- /package/dist/{DataTable-DQ7RSOHE.js.map → DataTable-THFPBKTP.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-ATAP5UTR.js.map → UnifiedAuthProvider-KAGUYQ4J.js.map} +0 -0
- /package/dist/{api-N774RPUA.js.map → api-IAGWF3ZG.js.map} +0 -0
- /package/dist/{audit-B5P6FFIR.js.map → audit-V53FV5AG.js.map} +0 -0
- /package/dist/{chunk-7D4SUZUM.js.map → chunk-DGUM43GV.js.map} +0 -0
- /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
- /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
- /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
- /package/docs/migration/{REACT_19_MIGRATION.md → V0.6.0_REACT_19_MIGRATION.md} +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Enforce code quality standards including TypeScript, ESLint, formatting, performance, and accessibility
|
|
3
3
|
globs: ["src/**/*.{ts,tsx,js,jsx}"]
|
|
4
|
-
alwaysApply:
|
|
5
|
-
paceCoreVersion: "0.
|
|
6
|
-
rulesVersion: "2025-01-
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
paceCoreVersion: "0.6.x"
|
|
6
|
+
rulesVersion: "2025-01-28"
|
|
7
7
|
---
|
|
8
8
|
# Code Quality Guide
|
|
9
9
|
|
|
@@ -36,27 +36,17 @@ This guide enforces code quality standards to ensure maintainable, performant, a
|
|
|
36
36
|
**MUST NOT use `any` type. Use `unknown` if type is truly unknown:**
|
|
37
37
|
|
|
38
38
|
```tsx
|
|
39
|
-
// ❌ WRONG
|
|
40
|
-
function processData(data: any) {
|
|
41
|
-
return data.value;
|
|
42
|
-
}
|
|
39
|
+
// ❌ WRONG: Using any
|
|
40
|
+
function processData(data: any) { return data.value; }
|
|
43
41
|
|
|
44
|
-
// ✅ CORRECT
|
|
42
|
+
// ✅ CORRECT: Using unknown with type guard or proper types
|
|
45
43
|
function processData(data: unknown) {
|
|
46
44
|
if (typeof data === 'object' && data !== null && 'value' in data) {
|
|
47
45
|
return (data as { value: string }).value;
|
|
48
46
|
}
|
|
49
47
|
throw new Error('Invalid data');
|
|
50
48
|
}
|
|
51
|
-
|
|
52
|
-
// ✅ CORRECT - Using proper types
|
|
53
|
-
interface Data {
|
|
54
|
-
value: string;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function processData(data: Data) {
|
|
58
|
-
return data.value;
|
|
59
|
-
}
|
|
49
|
+
// Or: interface Data { value: string; } function processData(data: Data) { return data.value; }
|
|
60
50
|
```
|
|
61
51
|
|
|
62
52
|
### MUST: Use Discriminated Unions
|
|
@@ -64,18 +54,11 @@ function processData(data: Data) {
|
|
|
64
54
|
**MUST use discriminated unions instead of boolean flags:**
|
|
65
55
|
|
|
66
56
|
```tsx
|
|
67
|
-
// ❌ WRONG
|
|
68
|
-
interface User {
|
|
69
|
-
isAdmin: boolean;
|
|
70
|
-
isGuest: boolean;
|
|
71
|
-
// Confusing: what if both are true?
|
|
72
|
-
}
|
|
57
|
+
// ❌ WRONG: Boolean flags (confusing: what if both are true?)
|
|
58
|
+
interface User { isAdmin: boolean; isGuest: boolean; }
|
|
73
59
|
|
|
74
|
-
// ✅ CORRECT
|
|
75
|
-
type User =
|
|
76
|
-
| { type: 'admin'; permissions: Permission[] }
|
|
77
|
-
| { type: 'guest'; limitedAccess: boolean }
|
|
78
|
-
| { type: 'user'; role: UserRole };
|
|
60
|
+
// ✅ CORRECT: Discriminated union
|
|
61
|
+
type User = { type: 'admin'; permissions: Permission[] } | { type: 'guest'; limitedAccess: boolean } | { type: 'user'; role: UserRole };
|
|
79
62
|
```
|
|
80
63
|
|
|
81
64
|
### SHOULD: Use ReadonlyArray
|
|
@@ -148,20 +131,10 @@ npm run format
|
|
|
148
131
|
**SHOULD use React.memo, useMemo, useCallback appropriately:**
|
|
149
132
|
|
|
150
133
|
```tsx
|
|
151
|
-
// ✅ CORRECT
|
|
152
|
-
const expensiveValue = useMemo(() =>
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
// ✅ CORRECT - Memoize callbacks
|
|
157
|
-
const handleClick = useCallback(() => {
|
|
158
|
-
doSomething(id);
|
|
159
|
-
}, [id]);
|
|
160
|
-
|
|
161
|
-
// ✅ CORRECT - Memoize components
|
|
162
|
-
const ExpensiveComponent = React.memo(({ data }) => {
|
|
163
|
-
return <div>{/* ... */}</div>;
|
|
164
|
-
});
|
|
134
|
+
// ✅ CORRECT: Memoize expensive computations, callbacks, and components
|
|
135
|
+
const expensiveValue = useMemo(() => computeExpensiveValue(data), [data]);
|
|
136
|
+
const handleClick = useCallback(() => doSomething(id), [id]);
|
|
137
|
+
const ExpensiveComponent = React.memo(({ data }) => <div>{/* ... */}</div>);
|
|
165
138
|
```
|
|
166
139
|
|
|
167
140
|
### SHOULD: Avoid Unnecessary Re-renders
|
|
@@ -169,18 +142,12 @@ const ExpensiveComponent = React.memo(({ data }) => {
|
|
|
169
142
|
**SHOULD avoid causing unnecessary re-renders:**
|
|
170
143
|
|
|
171
144
|
```tsx
|
|
172
|
-
// ❌ WRONG
|
|
173
|
-
function Component({ items }) {
|
|
174
|
-
const config = { items, enabled: true }; // New object each render
|
|
175
|
-
return <Child config={config} />;
|
|
176
|
-
}
|
|
145
|
+
// ❌ WRONG: New object on every render (causes unnecessary re-renders)
|
|
146
|
+
function Component({ items }) { const config = { items, enabled: true }; return <Child config={config} />; }
|
|
177
147
|
|
|
178
|
-
// ✅ CORRECT
|
|
148
|
+
// ✅ CORRECT: Memoize object
|
|
179
149
|
function Component({ items }) {
|
|
180
|
-
const config = useMemo(
|
|
181
|
-
() => ({ items, enabled: true }),
|
|
182
|
-
[items]
|
|
183
|
-
);
|
|
150
|
+
const config = useMemo(() => ({ items, enabled: true }), [items]);
|
|
184
151
|
return <Child config={config} />;
|
|
185
152
|
}
|
|
186
153
|
```
|
|
@@ -190,17 +157,11 @@ function Component({ items }) {
|
|
|
190
157
|
**SHOULD lazy load heavy components:**
|
|
191
158
|
|
|
192
159
|
```tsx
|
|
193
|
-
// ✅ CORRECT
|
|
160
|
+
// ✅ CORRECT: Lazy load heavy components
|
|
194
161
|
import { lazy, Suspense } from 'react';
|
|
195
|
-
|
|
196
162
|
const HeavyComponent = lazy(() => import('./HeavyComponent'));
|
|
197
|
-
|
|
198
163
|
function App() {
|
|
199
|
-
return
|
|
200
|
-
<Suspense fallback={<Loading />}>
|
|
201
|
-
<HeavyComponent />
|
|
202
|
-
</Suspense>
|
|
203
|
-
);
|
|
164
|
+
return <Suspense fallback={<Loading />}><HeavyComponent /></Suspense>;
|
|
204
165
|
}
|
|
205
166
|
```
|
|
206
167
|
|
|
@@ -211,11 +172,8 @@ function App() {
|
|
|
211
172
|
**MUST use semantic HTML elements:**
|
|
212
173
|
|
|
213
174
|
```tsx
|
|
214
|
-
// ❌ WRONG
|
|
215
|
-
<
|
|
216
|
-
|
|
217
|
-
// ✅ CORRECT - Semantic
|
|
218
|
-
<button onClick={handleClick}>Click me</button>
|
|
175
|
+
// ❌ WRONG: Non-semantic (<div onClick={...}>)
|
|
176
|
+
// ✅ CORRECT: Semantic HTML (<button onClick={...}>)
|
|
219
177
|
```
|
|
220
178
|
|
|
221
179
|
### MUST: Provide ARIA Labels
|
|
@@ -223,7 +181,7 @@ function App() {
|
|
|
223
181
|
**MUST provide ARIA labels for interactive elements:**
|
|
224
182
|
|
|
225
183
|
```tsx
|
|
226
|
-
// ✅ CORRECT
|
|
184
|
+
// ✅ CORRECT: Provide ARIA labels for interactive elements
|
|
227
185
|
<button aria-label="Close dialog">×</button>
|
|
228
186
|
<input aria-label="Search" type="search" />
|
|
229
187
|
```
|
|
@@ -233,17 +191,8 @@ function App() {
|
|
|
233
191
|
**MUST ensure all interactive elements are keyboard accessible:**
|
|
234
192
|
|
|
235
193
|
```tsx
|
|
236
|
-
// ✅ CORRECT
|
|
237
|
-
<button
|
|
238
|
-
onClick={handleClick}
|
|
239
|
-
onKeyDown={(e) => {
|
|
240
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
241
|
-
handleClick();
|
|
242
|
-
}
|
|
243
|
-
}}
|
|
244
|
-
>
|
|
245
|
-
Click me
|
|
246
|
-
</button>
|
|
194
|
+
// ✅ CORRECT: Ensure keyboard navigation (Enter or Space key)
|
|
195
|
+
<button onClick={handleClick} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') handleClick(); }}>Click me</button>
|
|
247
196
|
```
|
|
248
197
|
|
|
249
198
|
### MUST: Provide Focus Indicators
|
|
@@ -251,10 +200,8 @@ function App() {
|
|
|
251
200
|
**MUST provide visible focus indicators:**
|
|
252
201
|
|
|
253
202
|
```tsx
|
|
254
|
-
// ✅ CORRECT
|
|
255
|
-
<button className="focus:outline-none focus:ring-2 focus:ring-main-500">
|
|
256
|
-
Click me
|
|
257
|
-
</button>
|
|
203
|
+
// ✅ CORRECT: Provide visible focus indicators
|
|
204
|
+
<button className="focus:outline-none focus:ring-2 focus:ring-main-500">Click me</button>
|
|
258
205
|
```
|
|
259
206
|
|
|
260
207
|
## Code Review Checklist
|
|
@@ -281,20 +228,12 @@ function App() {
|
|
|
281
228
|
**Functions SHOULD be small and focused:**
|
|
282
229
|
|
|
283
230
|
```tsx
|
|
284
|
-
// ❌ WRONG
|
|
285
|
-
function processUserData(user) {
|
|
286
|
-
// 100+ lines of logic
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// ✅ CORRECT - Small, focused functions
|
|
290
|
-
function validateUser(user: User): ValidationResult {
|
|
291
|
-
// Validation logic
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
function transformUser(user: User): TransformedUser {
|
|
295
|
-
// Transformation logic
|
|
296
|
-
}
|
|
231
|
+
// ❌ WRONG: Large function (100+ lines, multiple responsibilities)
|
|
232
|
+
function processUserData(user) { /* 100+ lines of logic */ }
|
|
297
233
|
|
|
234
|
+
// ✅ CORRECT: Small, focused functions
|
|
235
|
+
function validateUser(user: User): ValidationResult { /* Validation logic */ }
|
|
236
|
+
function transformUser(user: User): TransformedUser { /* Transformation logic */ }
|
|
298
237
|
function processUserData(user: User) {
|
|
299
238
|
const validation = validateUser(user);
|
|
300
239
|
if (!validation.valid) return validation;
|
|
@@ -307,24 +246,11 @@ function processUserData(user: User) {
|
|
|
307
246
|
**Functions SHOULD have low cyclomatic complexity (< 10):**
|
|
308
247
|
|
|
309
248
|
```tsx
|
|
310
|
-
// ❌ WRONG
|
|
311
|
-
function processData(data) {
|
|
312
|
-
if (condition1) {
|
|
313
|
-
if (condition2) {
|
|
314
|
-
if (condition3) {
|
|
315
|
-
// ... many nested conditions
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
249
|
+
// ❌ WRONG: High complexity (many nested conditions)
|
|
250
|
+
function processData(data) { if (condition1) { if (condition2) { if (condition3) { /* ... */ } } } }
|
|
320
251
|
|
|
321
|
-
// ✅ CORRECT
|
|
322
|
-
function processData(data) {
|
|
323
|
-
if (!condition1) return;
|
|
324
|
-
if (!condition2) return;
|
|
325
|
-
if (!condition3) return;
|
|
326
|
-
// Process
|
|
327
|
-
}
|
|
252
|
+
// ✅ CORRECT: Lower complexity (early returns)
|
|
253
|
+
function processData(data) { if (!condition1) return; if (!condition2) return; if (!condition3) return; /* Process */ }
|
|
328
254
|
```
|
|
329
255
|
|
|
330
256
|
## Error Handling
|
|
@@ -334,7 +260,7 @@ function processData(data) {
|
|
|
334
260
|
**MUST handle errors and provide user feedback:**
|
|
335
261
|
|
|
336
262
|
```tsx
|
|
337
|
-
// ✅ CORRECT
|
|
263
|
+
// ✅ CORRECT: Handle errors gracefully with user feedback
|
|
338
264
|
try {
|
|
339
265
|
const data = await fetchData();
|
|
340
266
|
setData(data);
|
|
@@ -349,24 +275,15 @@ try {
|
|
|
349
275
|
**MUST use type-safe error handling:**
|
|
350
276
|
|
|
351
277
|
```tsx
|
|
352
|
-
// ✅ CORRECT
|
|
278
|
+
// ✅ CORRECT: Type-safe error handling
|
|
353
279
|
function isApiError(error: unknown): error is ApiError {
|
|
354
|
-
return
|
|
355
|
-
typeof error === 'object' &&
|
|
356
|
-
error !== null &&
|
|
357
|
-
'code' in error &&
|
|
358
|
-
'message' in error
|
|
359
|
-
);
|
|
280
|
+
return typeof error === 'object' && error !== null && 'code' in error && 'message' in error;
|
|
360
281
|
}
|
|
361
|
-
|
|
362
282
|
try {
|
|
363
283
|
await apiCall();
|
|
364
284
|
} catch (error) {
|
|
365
|
-
if (isApiError(error))
|
|
366
|
-
|
|
367
|
-
} else {
|
|
368
|
-
handleUnknownError(error);
|
|
369
|
-
}
|
|
285
|
+
if (isApiError(error)) handleApiError(error);
|
|
286
|
+
else handleUnknownError(error);
|
|
370
287
|
}
|
|
371
288
|
```
|
|
372
289
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Enforce tech stack compliance including Tailwind v4, React 19+, Supabase, and other required technologies
|
|
3
3
|
globs: ["src/**/*.{ts,tsx,js,jsx,css}", "*.config.{ts,js}"]
|
|
4
|
-
alwaysApply:
|
|
4
|
+
alwaysApply: false
|
|
5
5
|
paceCoreVersion: "0.6.x"
|
|
6
6
|
rulesVersion: "2025-01-28"
|
|
7
7
|
---
|
|
@@ -16,19 +16,8 @@ This guide ensures consuming apps use the correct versions and patterns for all
|
|
|
16
16
|
**MUST use Tailwind v4 CSS-first syntax, NOT v3 patterns:**
|
|
17
17
|
|
|
18
18
|
```css
|
|
19
|
-
/* ✅ CORRECT
|
|
20
|
-
@
|
|
21
|
-
|
|
22
|
-
@theme {
|
|
23
|
-
--color-main-*: oklch(...);
|
|
24
|
-
--color-sec-*: oklch(...);
|
|
25
|
-
--color-acc-*: oklch(...);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/* ❌ WRONG - Tailwind v3 */
|
|
29
|
-
@tailwind base;
|
|
30
|
-
@tailwind components;
|
|
31
|
-
@tailwind utilities;
|
|
19
|
+
/* ✅ CORRECT: Tailwind v4 CSS-first (@import 'tailwindcss'; @theme { ... }) */
|
|
20
|
+
/* ❌ WRONG: Tailwind v3 (@tailwind base/components/utilities directives) */
|
|
32
21
|
```
|
|
33
22
|
|
|
34
23
|
### MUST NOT: Use Bracket Syntax
|
|
@@ -36,11 +25,8 @@ This guide ensures consuming apps use the correct versions and patterns for all
|
|
|
36
25
|
**MUST NOT use bracket syntax like `bg-[oklch(...)]`. Map everything through theme variables:**
|
|
37
26
|
|
|
38
27
|
```tsx
|
|
39
|
-
// ❌ WRONG
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// ✅ CORRECT - Theme variable
|
|
43
|
-
<div className="bg-main-500">
|
|
28
|
+
// ❌ WRONG: Bracket syntax (bg-[oklch(...)])
|
|
29
|
+
// ✅ CORRECT: Theme variable (bg-main-500)
|
|
44
30
|
```
|
|
45
31
|
|
|
46
32
|
### MUST: Use Custom Color Namespaces
|
|
@@ -51,11 +37,8 @@ This guide ensures consuming apps use the correct versions and patterns for all
|
|
|
51
37
|
- `acc-*` for accent colors (red, orange, amber, yellow, lime, pink, rose)
|
|
52
38
|
|
|
53
39
|
```tsx
|
|
54
|
-
// ✅ CORRECT
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
// ❌ WRONG - Standard Tailwind colors
|
|
58
|
-
<div className="bg-blue-500 text-gray-800 border-red-300">
|
|
40
|
+
// ✅ CORRECT: Custom namespaces (main-*, sec-*, acc-*)
|
|
41
|
+
// ❌ WRONG: Standard Tailwind colors (blue-*, gray-*, red-*)
|
|
59
42
|
```
|
|
60
43
|
|
|
61
44
|
### MUST: Use Semantic Classes
|
|
@@ -77,17 +60,11 @@ This guide ensures consuming apps use the correct versions and patterns for all
|
|
|
77
60
|
**MUST use React 19+ patterns:**
|
|
78
61
|
|
|
79
62
|
```tsx
|
|
80
|
-
// ✅ CORRECT
|
|
63
|
+
// ✅ CORRECT: React 19+ features (Suspense, useTransition, etc.)
|
|
81
64
|
import { Suspense, useTransition } from 'react';
|
|
82
|
-
|
|
83
65
|
function App() {
|
|
84
66
|
const [isPending, startTransition] = useTransition();
|
|
85
|
-
|
|
86
|
-
return (
|
|
87
|
-
<Suspense fallback={<Loading />}>
|
|
88
|
-
<Component />
|
|
89
|
-
</Suspense>
|
|
90
|
-
);
|
|
67
|
+
return <Suspense fallback={<Loading />}><Component /></Suspense>;
|
|
91
68
|
}
|
|
92
69
|
```
|
|
93
70
|
|
|
@@ -96,16 +73,10 @@ function App() {
|
|
|
96
73
|
**MUST use functional components with hooks exclusively:**
|
|
97
74
|
|
|
98
75
|
```tsx
|
|
99
|
-
// ✅ CORRECT
|
|
100
|
-
function MyComponent() {
|
|
101
|
-
const [state, setState] = useState();
|
|
102
|
-
return <div>...</div>;
|
|
103
|
-
}
|
|
76
|
+
// ✅ CORRECT: Functional components with hooks
|
|
77
|
+
function MyComponent() { const [state, setState] = useState(); return <div>...</div>; }
|
|
104
78
|
|
|
105
|
-
// ❌ WRONG
|
|
106
|
-
class MyComponent extends React.Component {
|
|
107
|
-
// ...
|
|
108
|
-
}
|
|
79
|
+
// ❌ WRONG: Class components
|
|
109
80
|
```
|
|
110
81
|
|
|
111
82
|
## Supabase
|
|
@@ -115,17 +86,8 @@ class MyComponent extends React.Component {
|
|
|
115
86
|
**MUST use `useSecureSupabase()` for all database operations:**
|
|
116
87
|
|
|
117
88
|
```tsx
|
|
118
|
-
// ✅ CORRECT
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
function Component() {
|
|
122
|
-
const secureSupabase = useSecureSupabase();
|
|
123
|
-
const { data } = await secureSupabase.from('table').select('*');
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// ❌ WRONG - Base client
|
|
127
|
-
import { createClient } from '@supabase/supabase-js';
|
|
128
|
-
const supabase = createClient(...);
|
|
89
|
+
// ✅ CORRECT: useSecureSupabase() from '@jmruthers/pace-core/rbac'
|
|
90
|
+
// ❌ WRONG: createClient() from '@supabase/supabase-js' (base client)
|
|
129
91
|
```
|
|
130
92
|
|
|
131
93
|
### MUST: Enforce RLS
|
|
@@ -137,17 +99,10 @@ const supabase = createClient(...);
|
|
|
137
99
|
**SHOULD use RPC functions for complex queries:**
|
|
138
100
|
|
|
139
101
|
```tsx
|
|
140
|
-
// ✅ CORRECT
|
|
141
|
-
const { data } = await secureSupabase.rpc('data_events_list', {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
// ❌ AVOID - Complex client-side queries
|
|
146
|
-
const { data } = await secureSupabase
|
|
147
|
-
.from('events')
|
|
148
|
-
.select('*, organisations(*), users(*)')
|
|
149
|
-
.eq('organisation_id', orgId)
|
|
150
|
-
// ... many joins
|
|
102
|
+
// ✅ CORRECT: RPC functions for complex queries
|
|
103
|
+
const { data } = await secureSupabase.rpc('data_events_list', { organisation_id: orgId });
|
|
104
|
+
|
|
105
|
+
// ❌ AVOID: Complex client-side queries with many joins
|
|
151
106
|
```
|
|
152
107
|
|
|
153
108
|
## TanStack Query
|
|
@@ -157,28 +112,11 @@ const { data } = await secureSupabase
|
|
|
157
112
|
**MUST use TanStack Query for all server state management:**
|
|
158
113
|
|
|
159
114
|
```tsx
|
|
160
|
-
// ✅ CORRECT
|
|
115
|
+
// ✅ CORRECT: TanStack Query for server state
|
|
161
116
|
import { useQuery, useMutation } from '@tanstack/react-query';
|
|
117
|
+
const { data, isLoading } = useQuery({ queryKey: ['events', orgId], queryFn: () => fetchEvents(orgId) });
|
|
162
118
|
|
|
163
|
-
|
|
164
|
-
const { data, isLoading } = useQuery({
|
|
165
|
-
queryKey: ['events', orgId],
|
|
166
|
-
queryFn: () => fetchEvents(orgId)
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
const mutation = useMutation({
|
|
170
|
-
mutationFn: createEvent,
|
|
171
|
-
onSuccess: () => {
|
|
172
|
-
queryClient.invalidateQueries({ queryKey: ['events'] });
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// ❌ WRONG - useState for server state
|
|
178
|
-
const [data, setData] = useState();
|
|
179
|
-
useEffect(() => {
|
|
180
|
-
fetchEvents().then(setData);
|
|
181
|
-
}, []);
|
|
119
|
+
// ❌ WRONG: useState + useEffect for server state
|
|
182
120
|
```
|
|
183
121
|
|
|
184
122
|
### SHOULD: Configure Query Client
|
|
@@ -186,16 +124,8 @@ useEffect(() => {
|
|
|
186
124
|
**SHOULD configure QueryClient with appropriate defaults:**
|
|
187
125
|
|
|
188
126
|
```tsx
|
|
189
|
-
// ✅ CORRECT
|
|
190
|
-
const queryClient = new QueryClient({
|
|
191
|
-
defaultOptions: {
|
|
192
|
-
queries: {
|
|
193
|
-
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
194
|
-
cacheTime: 10 * 60 * 1000, // 10 minutes
|
|
195
|
-
retry: 1,
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
});
|
|
127
|
+
// ✅ CORRECT: Configure QueryClient with appropriate defaults (staleTime, cacheTime, retry)
|
|
128
|
+
const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 5 * 60 * 1000, cacheTime: 10 * 60 * 1000, retry: 1 } } });
|
|
199
129
|
```
|
|
200
130
|
|
|
201
131
|
## React Hook Form + Zod
|
|
@@ -205,23 +135,12 @@ const queryClient = new QueryClient({
|
|
|
205
135
|
**MUST use React Hook Form with Zod for all forms:**
|
|
206
136
|
|
|
207
137
|
```tsx
|
|
208
|
-
// ✅ CORRECT
|
|
138
|
+
// ✅ CORRECT: React Hook Form + Zod (useZodForm from pace-core)
|
|
209
139
|
import { useZodForm } from '@jmruthers/pace-core';
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const schema = z.object({
|
|
213
|
-
email: z.string().email(),
|
|
214
|
-
name: z.string().min(1),
|
|
215
|
-
});
|
|
140
|
+
const schema = z.object({ email: z.string().email(), name: z.string().min(1) });
|
|
141
|
+
const form = useZodForm(schema);
|
|
216
142
|
|
|
217
|
-
|
|
218
|
-
const form = useZodForm(schema);
|
|
219
|
-
return <Form {...form}>...</Form>;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// ❌ WRONG - Manual form handling
|
|
223
|
-
const [email, setEmail] = useState('');
|
|
224
|
-
const [errors, setErrors] = useState({});
|
|
143
|
+
// ❌ WRONG: Manual form handling (useState for form state)
|
|
225
144
|
```
|
|
226
145
|
|
|
227
146
|
## Vite
|
|
@@ -231,14 +150,10 @@ const [errors, setErrors] = useState({});
|
|
|
231
150
|
**MUST use Vite for all build tooling:**
|
|
232
151
|
|
|
233
152
|
```typescript
|
|
234
|
-
//
|
|
153
|
+
// ✅ CORRECT: Vite for build tooling
|
|
235
154
|
import { defineConfig } from 'vite';
|
|
236
155
|
import react from '@vitejs/plugin-react';
|
|
237
|
-
|
|
238
|
-
export default defineConfig({
|
|
239
|
-
plugins: [react()],
|
|
240
|
-
// ...
|
|
241
|
-
});
|
|
156
|
+
export default defineConfig({ plugins: [react()] });
|
|
242
157
|
```
|
|
243
158
|
|
|
244
159
|
### MUST: Use Environment Variables Correctly
|
|
@@ -246,11 +161,8 @@ export default defineConfig({
|
|
|
246
161
|
**MUST use `import.meta.env` for environment variables:**
|
|
247
162
|
|
|
248
163
|
```tsx
|
|
249
|
-
// ✅ CORRECT
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
// ❌ WRONG - Node.js env vars
|
|
253
|
-
const apiUrl = process.env.VITE_API_URL;
|
|
164
|
+
// ✅ CORRECT: import.meta.env.VITE_API_URL (Vite env vars)
|
|
165
|
+
// ❌ WRONG: process.env.VITE_API_URL (Node.js env vars)
|
|
254
166
|
```
|
|
255
167
|
|
|
256
168
|
## TypeScript
|
|
@@ -260,15 +172,8 @@ const apiUrl = process.env.VITE_API_URL;
|
|
|
260
172
|
**MUST use TypeScript 5+ with strict mode:**
|
|
261
173
|
|
|
262
174
|
```json
|
|
263
|
-
//
|
|
264
|
-
{
|
|
265
|
-
"compilerOptions": {
|
|
266
|
-
"target": "ES2022",
|
|
267
|
-
"module": "ESNext",
|
|
268
|
-
"strict": true,
|
|
269
|
-
// ...
|
|
270
|
-
}
|
|
271
|
-
}
|
|
175
|
+
// ✅ CORRECT: TypeScript 5+ with strict mode
|
|
176
|
+
{ "compilerOptions": { "target": "ES2022", "module": "ESNext", "strict": true } }
|
|
272
177
|
```
|
|
273
178
|
|
|
274
179
|
## Version Requirements
|