@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
|
@@ -378,6 +378,112 @@ module.exports = {
|
|
|
378
378
|
}
|
|
379
379
|
};
|
|
380
380
|
}
|
|
381
|
+
},
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Disallow direct Supabase client creation - must use useSecureSupabase
|
|
385
|
+
*/
|
|
386
|
+
'no-direct-supabase-client': {
|
|
387
|
+
meta: {
|
|
388
|
+
type: 'problem',
|
|
389
|
+
docs: {
|
|
390
|
+
description: 'Disallow direct createClient calls from @supabase/supabase-js. Use useSecureSupabase() from pace-core instead to ensure organisation context and RLS policies are enforced.',
|
|
391
|
+
category: 'Security',
|
|
392
|
+
recommended: true
|
|
393
|
+
},
|
|
394
|
+
messages: {
|
|
395
|
+
directClientCreation: "Direct Supabase client creation detected. You MUST use useSecureSupabase() from '@jmruthers/pace-core/rbac' instead to ensure organisation context and RLS policies are enforced. This prevents cross-organisation data access.",
|
|
396
|
+
directClientImport: "Direct import of createClient from @supabase/supabase-js is not allowed. Use useSecureSupabase() from '@jmruthers/pace-core/rbac' instead."
|
|
397
|
+
},
|
|
398
|
+
hasSuggestions: true
|
|
399
|
+
},
|
|
400
|
+
create(context) {
|
|
401
|
+
let hasSupabaseImport = false;
|
|
402
|
+
let createClientImported = false;
|
|
403
|
+
const filename = context.getFilename();
|
|
404
|
+
|
|
405
|
+
// Allow createClient in specific config files (supabaseClient.ts/js, etc.)
|
|
406
|
+
const isConfigFile = /(supabase|client)\.(ts|js|tsx|jsx)$/i.test(filename) &&
|
|
407
|
+
(filename.includes('supabase') || filename.includes('client'));
|
|
408
|
+
|
|
409
|
+
return {
|
|
410
|
+
ImportDeclaration(node) {
|
|
411
|
+
const importSource = node.source.value;
|
|
412
|
+
|
|
413
|
+
// Check for @supabase/supabase-js import
|
|
414
|
+
if (importSource === '@supabase/supabase-js') {
|
|
415
|
+
hasSupabaseImport = true;
|
|
416
|
+
|
|
417
|
+
// Check if createClient is imported
|
|
418
|
+
const hasCreateClient = node.specifiers.some(spec => {
|
|
419
|
+
if (spec.type === 'ImportSpecifier') {
|
|
420
|
+
return spec.imported.name === 'createClient';
|
|
421
|
+
}
|
|
422
|
+
if (spec.type === 'ImportNamespaceSpecifier') {
|
|
423
|
+
return true; // import * as supabase
|
|
424
|
+
}
|
|
425
|
+
return false;
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
if (hasCreateClient) {
|
|
429
|
+
createClientImported = true;
|
|
430
|
+
|
|
431
|
+
// Only report if not in a config file
|
|
432
|
+
if (!isConfigFile) {
|
|
433
|
+
context.report({
|
|
434
|
+
node: node.source,
|
|
435
|
+
messageId: 'directClientImport',
|
|
436
|
+
suggest: [{
|
|
437
|
+
desc: 'Replace with useSecureSupabase hook',
|
|
438
|
+
fix(fixer) {
|
|
439
|
+
// Remove the import
|
|
440
|
+
return fixer.remove(node);
|
|
441
|
+
}
|
|
442
|
+
}]
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
CallExpression(node) {
|
|
450
|
+
// Check for createClient() calls
|
|
451
|
+
if (node.callee.type === 'Identifier' && node.callee.name === 'createClient') {
|
|
452
|
+
// Only report if not in a config file
|
|
453
|
+
if (!isConfigFile) {
|
|
454
|
+
context.report({
|
|
455
|
+
node,
|
|
456
|
+
messageId: 'directClientCreation',
|
|
457
|
+
suggest: [{
|
|
458
|
+
desc: 'Use useSecureSupabase() hook instead',
|
|
459
|
+
fix(fixer) {
|
|
460
|
+
// This is complex to auto-fix, so we'll just report
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
}]
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Check for supabase.createClient() or similar patterns
|
|
469
|
+
if (node.callee.type === 'MemberExpression' &&
|
|
470
|
+
node.callee.property?.name === 'createClient') {
|
|
471
|
+
if (!isConfigFile) {
|
|
472
|
+
context.report({
|
|
473
|
+
node,
|
|
474
|
+
messageId: 'directClientCreation',
|
|
475
|
+
suggest: [{
|
|
476
|
+
desc: 'Use useSecureSupabase() hook instead',
|
|
477
|
+
fix(fixer) {
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
}]
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
}
|
|
381
487
|
}
|
|
382
488
|
}
|
|
383
489
|
};
|
|
@@ -64,10 +64,7 @@ describe('hooks index exports', () => {
|
|
|
64
64
|
expect(typeof Hooks.useOrganisationPermissions).toBe('function');
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
expect(Hooks).toHaveProperty('useSecureDataAccess');
|
|
69
|
-
expect(typeof Hooks.useSecureDataAccess).toBe('function');
|
|
70
|
-
});
|
|
67
|
+
// useSecureDataAccess has been removed - use useSecureSupabase from @jmruthers/pace-core/rbac instead
|
|
71
68
|
|
|
72
69
|
it('should export useOrganisationSecurity', () => {
|
|
73
70
|
expect(Hooks).toHaveProperty('useOrganisationSecurity');
|
|
@@ -190,7 +187,7 @@ describe('hooks index exports', () => {
|
|
|
190
187
|
'useDebounce',
|
|
191
188
|
'useDataTableState',
|
|
192
189
|
'useOrganisationPermissions',
|
|
193
|
-
'useSecureDataAccess',
|
|
190
|
+
// 'useSecureDataAccess', // Removed - use useSecureSupabase from @jmruthers/pace-core/rbac instead
|
|
194
191
|
'useOrganisationSecurity',
|
|
195
192
|
'useZodForm',
|
|
196
193
|
'useComponentPerformance',
|
|
@@ -99,7 +99,7 @@ describe('useAppConfig Hook', () => {
|
|
|
99
99
|
vi.restoreAllMocks();
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
describe('Public Page Context', () => {
|
|
103
103
|
beforeEach(() => {
|
|
104
104
|
mockUseIsPublicPage.mockReturnValue(true);
|
|
105
105
|
});
|
|
@@ -107,8 +107,6 @@ describe('useAppConfig Hook', () => {
|
|
|
107
107
|
it('should return public page configuration when in public context', () => {
|
|
108
108
|
const { result } = renderHook(() => useAppConfig());
|
|
109
109
|
|
|
110
|
-
expect(result.current.supportsDirectAccess).toBe(false);
|
|
111
|
-
expect(result.current.requiresEvent).toBe(true);
|
|
112
110
|
expect(result.current.isLoading).toBe(false);
|
|
113
111
|
// Note: If VITE_APP_NAME is set in .env (e.g., CORE), the hook will use it.
|
|
114
112
|
// Otherwise, it defaults to 'PACE'. This test verifies it returns a valid string.
|
|
@@ -122,8 +120,6 @@ describe('useAppConfig Hook', () => {
|
|
|
122
120
|
const { result } = renderHook(() => useAppConfig());
|
|
123
121
|
|
|
124
122
|
// Public pages should always have these characteristics
|
|
125
|
-
expect(result.current.supportsDirectAccess).toBe(false);
|
|
126
|
-
expect(result.current.requiresEvent).toBe(true);
|
|
127
123
|
expect(result.current.isLoading).toBe(false);
|
|
128
124
|
expect(typeof result.current.appName).toBe('string');
|
|
129
125
|
});
|
|
@@ -134,80 +130,23 @@ describe('useAppConfig Hook', () => {
|
|
|
134
130
|
mockUseIsPublicPage.mockReturnValue(false);
|
|
135
131
|
// Set default mock for useUnifiedAuth
|
|
136
132
|
mockUseUnifiedAuthFn.mockReturnValue({
|
|
137
|
-
appConfig: { requires_event: true },
|
|
138
133
|
appName: 'PACE',
|
|
139
134
|
} as any);
|
|
140
135
|
});
|
|
141
136
|
|
|
142
137
|
it('should return configuration from UnifiedAuthProvider when available', () => {
|
|
143
|
-
const mockAppConfig = {
|
|
144
|
-
requires_event: false,
|
|
145
|
-
};
|
|
146
138
|
const mockAppName = 'AuthApp';
|
|
147
139
|
|
|
148
140
|
mockUseUnifiedAuthFn.mockReturnValue({
|
|
149
|
-
appConfig: mockAppConfig,
|
|
150
141
|
appName: mockAppName,
|
|
151
142
|
} as any);
|
|
152
143
|
|
|
153
144
|
const { result } = renderHook(() => useAppConfig());
|
|
154
145
|
|
|
155
|
-
expect(result.current.supportsDirectAccess).toBe(true);
|
|
156
|
-
expect(result.current.requiresEvent).toBe(false);
|
|
157
146
|
expect(result.current.isLoading).toBe(false);
|
|
158
147
|
expect(result.current.appName).toBe('AuthApp');
|
|
159
148
|
});
|
|
160
149
|
|
|
161
|
-
it('should handle requires_event: true', () => {
|
|
162
|
-
const mockAppConfig = {
|
|
163
|
-
requires_event: true,
|
|
164
|
-
};
|
|
165
|
-
const mockAppName = 'EventApp';
|
|
166
|
-
|
|
167
|
-
mockUseUnifiedAuthFn.mockReturnValue({
|
|
168
|
-
appConfig: mockAppConfig,
|
|
169
|
-
appName: mockAppName,
|
|
170
|
-
} as any);
|
|
171
|
-
|
|
172
|
-
const { result } = renderHook(() => useAppConfig());
|
|
173
|
-
|
|
174
|
-
expect(result.current.supportsDirectAccess).toBe(false);
|
|
175
|
-
expect(result.current.requiresEvent).toBe(true);
|
|
176
|
-
expect(result.current.isLoading).toBe(false);
|
|
177
|
-
expect(result.current.appName).toBe('EventApp');
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('should handle null appConfig (loading state)', () => {
|
|
181
|
-
mockUseUnifiedAuthFn.mockReturnValue({
|
|
182
|
-
appConfig: null,
|
|
183
|
-
appName: 'LoadingApp',
|
|
184
|
-
} as any);
|
|
185
|
-
|
|
186
|
-
const { result } = renderHook(() => useAppConfig());
|
|
187
|
-
|
|
188
|
-
expect(result.current.supportsDirectAccess).toBe(false);
|
|
189
|
-
expect(result.current.requiresEvent).toBe(true);
|
|
190
|
-
expect(result.current.isLoading).toBe(true);
|
|
191
|
-
expect(result.current.appName).toBe('LoadingApp');
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('should handle undefined appConfig.requires_event', () => {
|
|
195
|
-
const mockAppConfig = {};
|
|
196
|
-
const mockAppName = 'DefaultApp';
|
|
197
|
-
|
|
198
|
-
mockUseUnifiedAuthFn.mockReturnValue({
|
|
199
|
-
appConfig: mockAppConfig,
|
|
200
|
-
appName: mockAppName,
|
|
201
|
-
} as any);
|
|
202
|
-
|
|
203
|
-
const { result } = renderHook(() => useAppConfig());
|
|
204
|
-
|
|
205
|
-
expect(result.current.supportsDirectAccess).toBe(false);
|
|
206
|
-
expect(result.current.requiresEvent).toBe(true);
|
|
207
|
-
expect(result.current.isLoading).toBe(false);
|
|
208
|
-
expect(result.current.appName).toBe('DefaultApp');
|
|
209
|
-
});
|
|
210
|
-
|
|
211
150
|
it('should handle UnifiedAuthProvider error and return fallback', () => {
|
|
212
151
|
mockUseUnifiedAuthFn.mockImplementation(() => {
|
|
213
152
|
throw new Error('Provider not available');
|
|
@@ -215,8 +154,6 @@ describe('useAppConfig Hook', () => {
|
|
|
215
154
|
|
|
216
155
|
const { result } = renderHook(() => useAppConfig());
|
|
217
156
|
|
|
218
|
-
expect(result.current.supportsDirectAccess).toBe(false);
|
|
219
|
-
expect(result.current.requiresEvent).toBe(true);
|
|
220
157
|
expect(result.current.isLoading).toBe(false);
|
|
221
158
|
expect(result.current.appName).toBe('PACE');
|
|
222
159
|
});
|
|
@@ -228,8 +165,6 @@ describe('useAppConfig Hook', () => {
|
|
|
228
165
|
|
|
229
166
|
const { result } = renderHook(() => useAppConfig());
|
|
230
167
|
|
|
231
|
-
expect(result.current.supportsDirectAccess).toBe(false);
|
|
232
|
-
expect(result.current.requiresEvent).toBe(true);
|
|
233
168
|
expect(result.current.isLoading).toBe(false);
|
|
234
169
|
expect(result.current.appName).toBe('PACE');
|
|
235
170
|
});
|
|
@@ -241,8 +176,6 @@ describe('useAppConfig Hook', () => {
|
|
|
241
176
|
|
|
242
177
|
const { result } = renderHook(() => useAppConfig());
|
|
243
178
|
|
|
244
|
-
expect(result.current.supportsDirectAccess).toBe(false);
|
|
245
|
-
expect(result.current.requiresEvent).toBe(true);
|
|
246
179
|
expect(result.current.isLoading).toBe(false);
|
|
247
180
|
expect(result.current.appName).toBe('PACE');
|
|
248
181
|
});
|
|
@@ -264,11 +197,9 @@ describe('useAppConfig Hook', () => {
|
|
|
264
197
|
it('should memoize authenticated configuration based on dependencies', () => {
|
|
265
198
|
mockUseIsPublicPage.mockReturnValue(false);
|
|
266
199
|
|
|
267
|
-
const mockAppConfig = { requires_event: false };
|
|
268
200
|
const mockAppName = 'TestApp';
|
|
269
201
|
|
|
270
202
|
mockUseUnifiedAuthFn.mockReturnValue({
|
|
271
|
-
appConfig: mockAppConfig,
|
|
272
203
|
appName: mockAppName,
|
|
273
204
|
} as any);
|
|
274
205
|
|
|
@@ -281,25 +212,21 @@ describe('useAppConfig Hook', () => {
|
|
|
281
212
|
|
|
282
213
|
expect(result.current).toBe(firstResult);
|
|
283
214
|
|
|
284
|
-
// Rerender with different
|
|
215
|
+
// Rerender with different appName
|
|
285
216
|
mockUseUnifiedAuthFn.mockReturnValue({
|
|
286
|
-
|
|
287
|
-
appName: mockAppName,
|
|
217
|
+
appName: 'DifferentApp',
|
|
288
218
|
} as any);
|
|
289
219
|
|
|
290
220
|
rerender();
|
|
291
221
|
|
|
292
222
|
expect(result.current).not.toBe(firstResult);
|
|
293
|
-
expect(result.current.
|
|
223
|
+
expect(result.current.appName).toBe('DifferentApp');
|
|
294
224
|
});
|
|
295
225
|
|
|
296
226
|
it('should memoize authenticated configuration based on appName changes', () => {
|
|
297
227
|
mockUseIsPublicPage.mockReturnValue(false);
|
|
298
228
|
|
|
299
|
-
const mockAppConfig = { requires_event: false };
|
|
300
|
-
|
|
301
229
|
mockUseUnifiedAuthFn.mockReturnValue({
|
|
302
|
-
appConfig: mockAppConfig,
|
|
303
230
|
appName: 'App1',
|
|
304
231
|
} as any);
|
|
305
232
|
|
|
@@ -309,7 +236,6 @@ describe('useAppConfig Hook', () => {
|
|
|
309
236
|
|
|
310
237
|
// Rerender with different appName
|
|
311
238
|
mockUseUnifiedAuthFn.mockReturnValue({
|
|
312
|
-
appConfig: mockAppConfig,
|
|
313
239
|
appName: 'App2',
|
|
314
240
|
} as any);
|
|
315
241
|
|
|
@@ -327,7 +253,6 @@ describe('useAppConfig Hook', () => {
|
|
|
327
253
|
|
|
328
254
|
const { result: publicResult } = renderHook(() => useAppConfig());
|
|
329
255
|
|
|
330
|
-
expect(publicResult.current.supportsDirectAccess).toBe(false);
|
|
331
256
|
// Note: App name depends on environment - may be 'PACE' (default) or 'CORE' (from .env)
|
|
332
257
|
expect(typeof publicResult.current.appName).toBe('string');
|
|
333
258
|
expect(['PACE', 'CORE']).toContain(publicResult.current.appName);
|
|
@@ -335,13 +260,11 @@ describe('useAppConfig Hook', () => {
|
|
|
335
260
|
// Test authenticated page context separately
|
|
336
261
|
mockUseIsPublicPage.mockReturnValue(false);
|
|
337
262
|
mockUseUnifiedAuthFn.mockReturnValue({
|
|
338
|
-
appConfig: { requires_event: false },
|
|
339
263
|
appName: 'AuthApp',
|
|
340
264
|
} as any);
|
|
341
265
|
|
|
342
266
|
const { result: authResult } = renderHook(() => useAppConfig());
|
|
343
267
|
|
|
344
|
-
expect(authResult.current.supportsDirectAccess).toBe(true);
|
|
345
268
|
expect(authResult.current.appName).toBe('AuthApp');
|
|
346
269
|
});
|
|
347
270
|
});
|
|
@@ -350,30 +273,13 @@ describe('useAppConfig Hook', () => {
|
|
|
350
273
|
it('should return correct types for all return values', () => {
|
|
351
274
|
mockUseIsPublicPage.mockReturnValue(false);
|
|
352
275
|
mockUseUnifiedAuthFn.mockReturnValue({
|
|
353
|
-
appConfig: { requires_event: false },
|
|
354
276
|
appName: 'TypeTestApp',
|
|
355
277
|
} as any);
|
|
356
278
|
|
|
357
279
|
const { result } = renderHook(() => useAppConfig());
|
|
358
280
|
|
|
359
|
-
expect(typeof result.current.supportsDirectAccess).toBe('boolean');
|
|
360
|
-
expect(typeof result.current.requiresEvent).toBe('boolean');
|
|
361
281
|
expect(typeof result.current.isLoading).toBe('boolean');
|
|
362
282
|
expect(typeof result.current.appName).toBe('string');
|
|
363
283
|
});
|
|
364
|
-
|
|
365
|
-
it('should handle malformed appConfig objects', () => {
|
|
366
|
-
mockUseIsPublicPage.mockReturnValue(false);
|
|
367
|
-
mockUseUnifiedAuthFn.mockReturnValue({
|
|
368
|
-
appConfig: { requires_event: 'not-a-boolean' },
|
|
369
|
-
appName: 'MalformedApp',
|
|
370
|
-
} as any);
|
|
371
|
-
|
|
372
|
-
const { result } = renderHook(() => useAppConfig());
|
|
373
|
-
|
|
374
|
-
// The hook uses the value directly, so it will be truthy
|
|
375
|
-
expect(result.current.requiresEvent).toBe('not-a-boolean');
|
|
376
|
-
expect(result.current.supportsDirectAccess).toBe(false);
|
|
377
|
-
});
|
|
378
284
|
});
|
|
379
285
|
});
|
package/src/hooks/index.ts
CHANGED
|
@@ -33,9 +33,8 @@ export type { UseAddressAutocompleteOptions, UseAddressAutocompleteReturn } from
|
|
|
33
33
|
|
|
34
34
|
// === ORGANISATION HOOKS ===
|
|
35
35
|
export { useOrganisationPermissions } from './useOrganisationPermissions';
|
|
36
|
-
|
|
36
|
+
// useSecureDataAccess has been removed - use useSecureSupabase from @jmruthers/pace-core/rbac instead
|
|
37
37
|
export type { UseOrganisationPermissionsReturn } from './useOrganisationPermissions';
|
|
38
|
-
export type { SecureDataAccessReturn } from './useSecureDataAccess';
|
|
39
38
|
export { useOrganisationSecurity } from './useOrganisationSecurity';
|
|
40
39
|
export type { OrganisationSecurityHook } from './useOrganisationSecurity';
|
|
41
40
|
|
|
@@ -70,6 +70,10 @@ import { logger } from '../../utils/core/logger';
|
|
|
70
70
|
// Simple in-memory cache for public data
|
|
71
71
|
const publicDataCache = new Map<string, { data: any; timestamp: number; ttl: number }>();
|
|
72
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Return value of the usePublicEvent hook.
|
|
75
|
+
* Provides event data, loading state, error, and refetch function.
|
|
76
|
+
*/
|
|
73
77
|
export interface UsePublicEventReturn {
|
|
74
78
|
/** The event data, null if not loaded or not found */
|
|
75
79
|
event: Event | null;
|
|
@@ -74,6 +74,10 @@ const log = createLogger('usePublicEventLogo');
|
|
|
74
74
|
// Simple in-memory cache for public data
|
|
75
75
|
const publicDataCache = new Map<string, { data: any; timestamp: number; ttl: number }>();
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Return value of the usePublicEventLogo hook.
|
|
79
|
+
* Provides logo URL, fallback text, loading state, error, and refetch function.
|
|
80
|
+
*/
|
|
77
81
|
export interface UsePublicEventLogoReturn {
|
|
78
82
|
/** The logo URL if available, null if not found or error */
|
|
79
83
|
logoUrl: string | null;
|
|
@@ -46,6 +46,10 @@ import { logger } from '../../utils/core/logger';
|
|
|
46
46
|
// Simple in-memory cache for public file data
|
|
47
47
|
const publicFileCache = new Map<string, { data: any; timestamp: number; ttl: number }>();
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Return value of the usePublicFileDisplay hook.
|
|
51
|
+
* Provides file URLs, references, loading state, error, and refetch function.
|
|
52
|
+
*/
|
|
49
53
|
export interface UsePublicFileDisplayReturn {
|
|
50
54
|
/** Single file URL if category is provided and file found, null otherwise */
|
|
51
55
|
fileUrl: string | null;
|
|
@@ -61,6 +61,10 @@ import { useParams, useLocation } from 'react-router-dom';
|
|
|
61
61
|
import type { Event } from '../../types/event';
|
|
62
62
|
import { usePublicEvent } from './usePublicEvent';
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Return value of the usePublicRouteParams hook.
|
|
66
|
+
* Provides event code, event ID, event data, loading state, error, and refetch function.
|
|
67
|
+
*/
|
|
64
68
|
export interface UsePublicRouteParamsReturn {
|
|
65
69
|
/** The event code from the URL */
|
|
66
70
|
eventCode: string | null;
|
|
@@ -11,23 +11,55 @@
|
|
|
11
11
|
import { useAuthService } from './useAuthService';
|
|
12
12
|
import { type User, type Session, type SupabaseClient, AuthError } from '@supabase/supabase-js';
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Authentication state and methods returned by the useAuth hook.
|
|
16
|
+
*/
|
|
14
17
|
export interface AuthState {
|
|
18
|
+
/** Current authenticated user, or null if not authenticated */
|
|
15
19
|
user: User | null;
|
|
20
|
+
/** Current session, or null if not authenticated */
|
|
16
21
|
session: Session | null;
|
|
22
|
+
/** Whether the user is currently authenticated */
|
|
17
23
|
isAuthenticated: boolean;
|
|
24
|
+
/** Whether authentication state is currently loading */
|
|
18
25
|
authLoading: boolean;
|
|
26
|
+
/** Any authentication error that occurred, or null */
|
|
19
27
|
authError: AuthError | null;
|
|
28
|
+
/** Supabase client instance, or null if not available */
|
|
20
29
|
supabase: SupabaseClient | null;
|
|
21
30
|
|
|
22
31
|
// Auth methods
|
|
32
|
+
/** Sign in with email and optional password */
|
|
23
33
|
signIn: (email: string, password?: string) => Promise<{ error: AuthError | null }>;
|
|
34
|
+
/** Sign up with email and password */
|
|
24
35
|
signUp: (email: string, password: string) => Promise<{ error: AuthError | null }>;
|
|
36
|
+
/** Sign out the current user */
|
|
25
37
|
signOut: () => Promise<{ error: AuthError | null }>;
|
|
38
|
+
/** Request a password reset email */
|
|
26
39
|
resetPassword: (email: string) => Promise<{ error: AuthError | null }>;
|
|
40
|
+
/** Update the current user's password */
|
|
27
41
|
updatePassword: (password: string) => Promise<{ error: AuthError | null }>;
|
|
42
|
+
/** Refresh the current session */
|
|
28
43
|
refreshSession: () => Promise<{ error: AuthError | null }>;
|
|
29
44
|
}
|
|
30
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Convenience hook for authentication.
|
|
48
|
+
* Returns the auth state and methods needed by components.
|
|
49
|
+
*
|
|
50
|
+
* @returns Authentication state and methods
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```tsx
|
|
54
|
+
* const { user, isAuthenticated, signIn, signOut } = useAuth();
|
|
55
|
+
*
|
|
56
|
+
* if (!isAuthenticated) {
|
|
57
|
+
* return <LoginForm onSignIn={signIn} />;
|
|
58
|
+
* }
|
|
59
|
+
*
|
|
60
|
+
* return <Dashboard user={user} onSignOut={signOut} />;
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
31
63
|
export function useAuth(): AuthState {
|
|
32
64
|
const authService = useAuthService();
|
|
33
65
|
|
|
@@ -22,6 +22,12 @@ export interface CurrentEventState {
|
|
|
22
22
|
refreshEvents: () => Promise<void>;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Convenience hook for accessing current event state.
|
|
27
|
+
* Returns event state and methods needed by components.
|
|
28
|
+
*
|
|
29
|
+
* @returns Current event state including events, selected event, loading state, and methods
|
|
30
|
+
*/
|
|
25
31
|
export function useCurrentEvent(): CurrentEventState {
|
|
26
32
|
const eventService = useEventService();
|
|
27
33
|
|
|
@@ -30,6 +30,12 @@ export interface CurrentOrganisationState {
|
|
|
30
30
|
getPrimaryOrganisation: () => Organisation | null;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Convenience hook for accessing current organisation state.
|
|
35
|
+
* Returns organisation state and methods needed by components.
|
|
36
|
+
*
|
|
37
|
+
* @returns Current organisation state including selected organisation, organisations, memberships, and methods
|
|
38
|
+
*/
|
|
33
39
|
export function useCurrentOrganisation(): CurrentOrganisationState {
|
|
34
40
|
const organisationService = useOrganisationService();
|
|
35
41
|
|
|
@@ -4,26 +4,19 @@
|
|
|
4
4
|
* @module Hooks/useAppConfig
|
|
5
5
|
* @since 0.4.0
|
|
6
6
|
*
|
|
7
|
-
* Hook for accessing app
|
|
8
|
-
*
|
|
7
|
+
* Hook for accessing app name and loading state.
|
|
8
|
+
*
|
|
9
|
+
* NOTE: Scope configuration (requires_event) is now page-level only (rbac_app_pages.scope_type).
|
|
10
|
+
* Use getPageScopeType() to determine if a specific page requires event or organisation context.
|
|
9
11
|
*
|
|
10
12
|
* @example
|
|
11
13
|
* ```tsx
|
|
12
14
|
* function MyComponent() {
|
|
13
|
-
* const {
|
|
15
|
+
* const { appName, isLoading } = useAppConfig();
|
|
14
16
|
*
|
|
15
17
|
* if (isLoading) return <div>Loading...</div>;
|
|
16
18
|
*
|
|
17
|
-
* return
|
|
18
|
-
* <div>
|
|
19
|
-
* {supportsDirectAccess && (
|
|
20
|
-
* <div>This app supports direct access!</div>
|
|
21
|
-
* )}
|
|
22
|
-
* {requiresEvent && (
|
|
23
|
-
* <EventSelector />
|
|
24
|
-
* )}
|
|
25
|
-
* </div>
|
|
26
|
-
* );
|
|
19
|
+
* return <div>App: {appName}</div>;
|
|
27
20
|
* }
|
|
28
21
|
* ```
|
|
29
22
|
*/
|
|
@@ -33,10 +26,8 @@ import { useUnifiedAuth } from '../providers/services/UnifiedAuthProvider';
|
|
|
33
26
|
import { useIsPublicPage, PublicPageContext } from '../components/PublicLayout/PublicPageProvider';
|
|
34
27
|
|
|
35
28
|
export interface UseAppConfigReturn {
|
|
36
|
-
supportsDirectAccess: boolean;
|
|
37
|
-
requiresEvent: boolean;
|
|
38
|
-
isLoading: boolean;
|
|
39
29
|
appName: string;
|
|
30
|
+
isLoading: boolean;
|
|
40
31
|
}
|
|
41
32
|
|
|
42
33
|
/**
|
|
@@ -92,32 +83,26 @@ export function useAppConfig(): UseAppConfigReturn {
|
|
|
92
83
|
};
|
|
93
84
|
|
|
94
85
|
return useMemo(() => ({
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
isLoading: false,
|
|
98
|
-
appName: getAppName()
|
|
86
|
+
appName: getAppName(),
|
|
87
|
+
isLoading: false
|
|
99
88
|
}), [contextAppName, hasPublicContext]);
|
|
100
89
|
}
|
|
101
90
|
|
|
102
91
|
// For authenticated pages, use UnifiedAuthProvider
|
|
103
92
|
try {
|
|
104
|
-
const {
|
|
93
|
+
const { appName } = useUnifiedAuth();
|
|
105
94
|
return useMemo(() => ({
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
appName
|
|
110
|
-
}), [appConfig?.requires_event, appName]);
|
|
95
|
+
appName,
|
|
96
|
+
isLoading: false
|
|
97
|
+
}), [appName]);
|
|
111
98
|
} catch (error) {
|
|
112
99
|
// Fallback if UnifiedAuthProvider is not available
|
|
113
100
|
return useMemo(() => ({
|
|
114
|
-
supportsDirectAccess: false,
|
|
115
|
-
requiresEvent: true,
|
|
116
|
-
isLoading: false,
|
|
117
101
|
appName: contextAppName ||
|
|
118
102
|
getNodeEnvVar('VITE_APP_NAME') ||
|
|
119
103
|
getNodeEnvVar('NEXT_PUBLIC_APP_NAME') ||
|
|
120
|
-
'PACE'
|
|
104
|
+
'PACE',
|
|
105
|
+
isLoading: false
|
|
121
106
|
}), [contextAppName]);
|
|
122
107
|
}
|
|
123
108
|
}
|
package/src/hooks/useDebounce.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
|
|
2
2
|
import { useState, useEffect } from 'react';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Hook for debouncing a value.
|
|
6
|
+
* Returns a debounced version of the value that only updates after the specified delay.
|
|
7
|
+
*
|
|
8
|
+
* @template T - The type of the value to debounce
|
|
9
|
+
* @param value - The value to debounce
|
|
10
|
+
* @param delay - The delay in milliseconds
|
|
11
|
+
* @returns The debounced value
|
|
12
|
+
*/
|
|
4
13
|
export function useDebounce<T>(value: T, delay: number): T {
|
|
5
14
|
const [debouncedValue, setDebouncedValue] = useState<T>(value);
|
|
6
15
|
|
|
@@ -92,6 +92,12 @@ const log = createLogger('useEventTheme');
|
|
|
92
92
|
* }
|
|
93
93
|
* ```
|
|
94
94
|
*/
|
|
95
|
+
/**
|
|
96
|
+
* Hook that automatically applies event-specific theming.
|
|
97
|
+
* Works in authenticated mode (via EventProvider) or public page mode (via event prop).
|
|
98
|
+
*
|
|
99
|
+
* @param event - Optional event object for public page mode. If not provided, uses EventProvider context.
|
|
100
|
+
*/
|
|
95
101
|
export function useEventTheme(event?: Event | null): void {
|
|
96
102
|
const location = useLocation();
|
|
97
103
|
|