@jmruthers/pace-core 0.5.76 → 0.5.78
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 +8 -0
- package/dist/{RBACService-C4udt_Zp.d.ts → AuthService-Df3IozMG.d.ts} +10 -118
- package/dist/{DataTable-ntgmhO2W.d.ts → DataTable-BE0OXZKQ.d.ts} +9 -2
- package/dist/{DataTable-4GAVPIEG.js → DataTable-ETGVF4Y5.js} +50 -13
- package/dist/{PublicLoadingSpinner-BiNER8F5.d.ts → PublicLoadingSpinner-CnUaz0vG.d.ts} +5 -2
- package/dist/{UnifiedAuthProvider-Bj6YCf7c.d.ts → UnifiedAuthProvider-B391Aqum.d.ts} +42 -45
- package/dist/{UnifiedAuthProvider-3NKDOSOK.js → UnifiedAuthProvider-P5SOJAQ6.js} +4 -5
- package/dist/{api-DDMUKIUD.js → api-KG4A2X7P.js} +9 -3
- package/dist/{audit-6TOCAMKO.js → audit-65VNHEV2.js} +2 -2
- package/dist/{chunk-K34IM5CT.js → chunk-2OGV6IRV.js} +196 -626
- package/dist/chunk-2OGV6IRV.js.map +1 -0
- package/dist/{chunk-NTNILOBC.js → chunk-5BO3MI5Y.js} +4 -4
- package/dist/{chunk-XLZ7U46Z.js → chunk-CVMVPYAL.js} +9 -60
- package/dist/chunk-CVMVPYAL.js.map +1 -0
- package/dist/{chunk-URUTVZ7N.js → chunk-FL4ZCQLD.js} +2 -2
- package/dist/{chunk-LW7MMEAQ.js → chunk-FT2M4R4F.js} +2 -2
- package/dist/{chunk-5BSLGBYI.js → chunk-JCQZ6LA7.js} +2 -8
- package/dist/{chunk-5BSLGBYI.js.map → chunk-JCQZ6LA7.js.map} +1 -1
- package/dist/{chunk-KHJS6VIA.js → chunk-LRQ6RBJC.js} +157 -112
- package/dist/chunk-LRQ6RBJC.js.map +1 -0
- package/dist/{chunk-WN6XJWOS.js → chunk-MNJXXD6C.js} +274 -743
- package/dist/chunk-MNJXXD6C.js.map +1 -0
- package/dist/{chunk-KK73ZB4E.js → chunk-PTR5PMPE.js} +153 -132
- package/dist/chunk-PTR5PMPE.js.map +1 -0
- package/dist/{chunk-B2WTCLCV.js → chunk-Q7APDV6H.js} +18 -8
- package/dist/chunk-Q7APDV6H.js.map +1 -0
- package/dist/{chunk-A4FUBC7B.js → chunk-QGVSOUJ2.js} +2 -4
- package/dist/{chunk-A4FUBC7B.js.map → chunk-QGVSOUJ2.js.map} +1 -1
- package/dist/{chunk-FGMFQSHX.js → chunk-S63MFSY6.js} +500 -551
- package/dist/chunk-S63MFSY6.js.map +1 -0
- package/dist/{chunk-AFGTSUAD.js → chunk-VSOKOFRF.js} +4 -4
- package/dist/chunk-WUXCWRL6.js +20 -0
- package/dist/chunk-WUXCWRL6.js.map +1 -0
- package/dist/{chunk-Y6TXWPJO.js → chunk-YVVGHRGI.js} +105 -31
- package/dist/chunk-YVVGHRGI.js.map +1 -0
- package/dist/{chunk-M5IWZRBT.js → chunk-ZMNXIJP4.js} +2187 -981
- package/dist/chunk-ZMNXIJP4.js.map +1 -0
- package/dist/components.d.ts +6 -6
- package/dist/components.js +14 -18
- package/dist/components.js.map +1 -1
- package/dist/{database-C3Szpi5J.d.ts → database-BXAfr2Y_.d.ts} +18 -0
- package/dist/hooks.d.ts +5 -5
- package/dist/hooks.js +8 -9
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +19 -27
- package/dist/index.js +21 -29
- package/dist/index.js.map +1 -1
- package/dist/{organisation-BtshODVF.d.ts → organisation-D6qRDtbF.d.ts} +1 -1
- package/dist/providers.d.ts +7 -21
- package/dist/providers.js +3 -10
- package/dist/rbac/index.d.ts +71 -221
- package/dist/rbac/index.js +15 -16
- package/dist/{types-CGX9Vyf5.d.ts → types-BDg1mAGG.d.ts} +36 -6
- package/dist/types.d.ts +3 -3
- package/dist/types.js +61 -18
- package/dist/types.js.map +1 -1
- package/dist/{unified-CM7T0aTK.d.ts → unified-DQ4VcT7H.d.ts} +1 -1
- package/dist/{usePublicRouteParams-B-CumWRc.d.ts → usePublicRouteParams-BlgwXweB.d.ts} +3 -3
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +52 -9
- package/dist/utils.js.map +1 -1
- package/docs/CONTENT_AUDIT_REPORT.md +253 -0
- package/docs/DOCUMENTATION_AUDIT.md +172 -0
- package/docs/README.md +142 -147
- package/docs/STYLE_GUIDE.md +37 -0
- package/docs/api/classes/ColumnFactory.md +17 -17
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +4 -4
- package/docs/api/classes/MissingUserContextError.md +4 -4
- package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
- package/docs/api/classes/PermissionDeniedError.md +5 -5
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +8 -8
- package/docs/api/classes/RBACCache.md +35 -5
- package/docs/api/classes/RBACEngine.md +49 -20
- package/docs/api/classes/RBACError.md +4 -4
- package/docs/api/classes/RBACNotInitializedError.md +4 -4
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +4 -4
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +11 -0
- package/docs/api/interfaces/DataTableAction.md +65 -29
- package/docs/api/interfaces/DataTableColumn.md +36 -23
- package/docs/api/interfaces/DataTableProps.md +80 -38
- package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
- package/docs/api/interfaces/EmptyStateConfig.md +5 -5
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +11 -11
- package/docs/api/interfaces/NavigationContextType.md +9 -9
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +7 -7
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +16 -3
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +2 -2
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +4 -4
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +2 -2
- package/docs/api/interfaces/RouteConfig.md +2 -2
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +94 -521
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +16 -16
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +11 -11
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +251 -269
- package/docs/api-reference/components.md +193 -0
- package/docs/api-reference/hooks.md +265 -0
- package/docs/api-reference/providers.md +6 -0
- package/docs/api-reference/types.md +6 -0
- package/docs/api-reference/utilities.md +207 -0
- package/docs/architecture/README.md +6 -0
- package/docs/{database-schema-requirements.md → architecture/database-schema-requirements.md} +6 -0
- package/docs/architecture/rbac-security-architecture.md +258 -0
- package/docs/architecture/services.md +9 -1
- package/docs/best-practices/README.md +6 -0
- package/docs/best-practices/accessibility.md +6 -0
- package/docs/{common-patterns.md → best-practices/common-patterns.md} +6 -0
- package/docs/best-practices/deployment.md +6 -0
- package/docs/best-practices/performance.md +475 -2
- package/docs/best-practices/security.md +6 -0
- package/docs/best-practices/testing.md +6 -0
- package/docs/core-concepts/authentication.md +6 -0
- package/docs/core-concepts/events.md +6 -0
- package/docs/core-concepts/organisations.md +6 -0
- package/docs/core-concepts/permissions.md +6 -0
- package/docs/core-concepts/rbac-system.md +8 -0
- package/docs/documentation-index.md +121 -182
- package/docs/{consuming-app-vite-config.md → getting-started/consuming-app-vite-config.md} +6 -0
- package/docs/getting-started/documentation-index.md +40 -0
- package/docs/getting-started/examples/README.md +878 -35
- package/docs/{faq.md → getting-started/faq.md} +7 -1
- package/docs/getting-started/installation-guide.md +6 -0
- package/docs/{quick-reference.md → getting-started/quick-reference.md} +6 -0
- package/docs/implementation-guides/app-layout.md +6 -0
- package/docs/implementation-guides/authentication.md +1021 -0
- package/docs/implementation-guides/component-styling.md +6 -0
- package/docs/implementation-guides/data-tables.md +1264 -2076
- package/docs/implementation-guides/dynamic-colors.md +6 -0
- package/docs/implementation-guides/event-theming-summary.md +6 -0
- package/docs/{file-reference-system.md → implementation-guides/file-reference-system.md} +6 -0
- package/docs/implementation-guides/file-upload-storage.md +6 -0
- package/docs/implementation-guides/forms.md +6 -0
- package/docs/implementation-guides/inactivity-tracking.md +6 -0
- package/docs/implementation-guides/navigation.md +6 -0
- package/docs/implementation-guides/organisation-security.md +6 -0
- package/docs/implementation-guides/permission-enforcement.md +6 -0
- package/docs/implementation-guides/public-pages-advanced.md +6 -0
- package/docs/implementation-guides/public-pages.md +6 -0
- package/docs/migration/MIGRATION_GUIDE.md +827 -351
- package/docs/migration/README.md +7 -1
- package/docs/migration/organisation-context-timing-fix.md +6 -0
- package/docs/migration/rbac-migration.md +44 -1
- package/docs/migration/service-architecture.md +6 -0
- package/docs/migration/v0.4.15-tailwind-scanning.md +6 -0
- package/docs/migration/v0.4.16-css-first-approach.md +6 -0
- package/docs/migration/v0.4.17-source-path-fix.md +6 -0
- package/docs/rbac/README-rbac-rls-integration.md +6 -0
- package/docs/rbac/README.md +6 -0
- package/docs/rbac/advanced-patterns.md +6 -0
- package/docs/rbac/api-reference.md +7 -1
- package/docs/rbac/breaking-changes-v3.md +222 -0
- package/docs/rbac/examples/rbac-rls-integration-example.md +6 -0
- package/docs/rbac/examples.md +6 -0
- package/docs/rbac/getting-started.md +6 -0
- package/docs/rbac/migration-guide.md +260 -0
- package/docs/rbac/quick-start.md +70 -13
- package/docs/rbac/rbac-rls-integration.md +6 -0
- package/docs/rbac/super-admin-guide.md +6 -0
- package/docs/rbac/troubleshooting.md +6 -0
- package/docs/security/README.md +6 -0
- package/docs/security/checklist.md +6 -0
- package/docs/styles/README.md +7 -1
- package/docs/{usage.md → styles/usage.md} +6 -0
- package/docs/testing/README.md +6 -0
- package/docs/{visual-testing.md → testing/visual-testing.md} +6 -0
- package/docs/troubleshooting/README.md +387 -5
- package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +6 -0
- package/docs/troubleshooting/common-issues.md +6 -0
- package/docs/troubleshooting/database-view-compatibility.md +6 -0
- package/docs/troubleshooting/organisation-context-setup.md +6 -0
- package/docs/troubleshooting/react-hooks-issue-analysis.md +6 -0
- package/docs/troubleshooting/styling-issues.md +6 -0
- package/docs/troubleshooting/tailwind-content-scanning.md +6 -0
- package/package.json +1 -1
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -1
- package/src/__tests__/helpers/test-providers.tsx +3 -53
- package/src/components/DataTable/DataTable.test.tsx +319 -0
- package/src/components/DataTable/DataTable.tsx +32 -11
- package/src/components/DataTable/__tests__/{DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx.skip} +6 -4
- package/src/components/DataTable/__tests__/{DataTable.test.tsx → DataTable.test.tsx.skip} +6 -4
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +31 -9
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +601 -0
- package/src/components/DataTable/__tests__/keyboard.test.tsx +615 -0
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +639 -0
- package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx.skip +330 -0
- package/src/components/DataTable/components/AccessDeniedPage.tsx +2 -2
- package/src/components/DataTable/components/ActionButtons.tsx +88 -104
- package/src/components/DataTable/components/DataTableCore.tsx +309 -337
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +4 -2
- package/src/components/DataTable/components/DataTableModals.tsx +22 -1
- package/src/components/DataTable/components/EditableRow.tsx +69 -84
- package/src/components/DataTable/components/EmptyState.tsx +5 -1
- package/src/components/DataTable/components/ImportModal.tsx +65 -36
- package/src/components/DataTable/components/PaginationControls.tsx +40 -100
- package/src/components/DataTable/components/UnifiedTableBody.tsx +125 -148
- package/src/components/DataTable/context/DataTableContext.tsx +1 -1
- package/src/components/DataTable/core/ColumnFactory.ts +5 -0
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +12 -10
- package/src/components/DataTable/examples/HierarchicalExample.tsx +1 -1
- package/src/components/DataTable/examples/InitialPageSizeExample.tsx +1 -0
- package/src/components/DataTable/examples/PerformanceExample.tsx +1 -0
- package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +1 -5
- package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +167 -0
- package/src/components/DataTable/hooks/index.ts +7 -0
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +32 -15
- package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +102 -0
- package/src/components/DataTable/hooks/useDataTableConfiguration.ts +89 -0
- package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +117 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +71 -27
- package/src/components/DataTable/hooks/useDataTableState.ts +39 -11
- package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +33 -0
- package/src/components/DataTable/hooks/useHierarchicalState.ts +15 -1
- package/src/components/DataTable/hooks/useKeyboardNavigation.ts +447 -0
- package/src/components/DataTable/hooks/useServerSideDataEffect.ts +94 -0
- package/src/components/DataTable/hooks/useTableColumns.ts +10 -7
- package/src/components/DataTable/hooks/useTableHandlers.ts +174 -0
- package/src/components/DataTable/index.ts +12 -3
- package/src/components/DataTable/types.ts +129 -9
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +159 -22
- package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +111 -0
- package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +15 -29
- package/src/components/DataTable/utils/a11yUtils.ts +244 -0
- package/src/components/DataTable/utils/debugTools.ts +609 -0
- package/src/components/DataTable/utils/exportUtils.ts +114 -16
- package/src/components/DataTable/utils/flexibleImport.ts +202 -32
- package/src/components/DataTable/utils/hierarchicalUtils.ts +1 -1
- package/src/components/DataTable/utils/index.ts +2 -0
- package/src/components/DataTable/utils/paginationUtils.ts +350 -0
- package/src/components/DataTable/utils/rowUtils.ts +6 -5
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -24
- package/src/components/NavigationMenu/NavigationMenu.tsx +19 -8
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +1 -23
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +56 -6
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +137 -13
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +1 -1
- package/src/components/Select/Select.tsx +1 -0
- package/src/components/examples/PermissionExample.tsx +173 -0
- package/src/examples/CorrectPublicPageImplementation.tsx +301 -0
- package/src/examples/PublicEventPage.tsx +274 -0
- package/src/examples/PublicPageApp.tsx +308 -0
- package/src/examples/PublicPageUsageExample.tsx +216 -0
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +12 -1
- package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +129 -17
- package/src/hooks/__tests__/useRBAC.unit.test.ts +151 -846
- package/src/hooks/useOrganisationPermissions.test.ts +42 -18
- package/src/hooks/useOrganisationPermissions.ts +12 -6
- package/src/hooks/useOrganisationSecurity.test.ts +138 -85
- package/src/hooks/useOrganisationSecurity.ts +41 -10
- package/src/index.ts +0 -1
- package/src/providers/AuthProvider.simplified.tsx +880 -0
- package/src/providers/UnifiedAuthProvider.test.simple.tsx +8 -8
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +29 -19
- package/src/providers/index.ts +0 -1
- package/src/providers/services/EventServiceProvider.tsx +19 -15
- package/src/providers/services/InactivityServiceProvider.tsx +19 -15
- package/src/providers/services/OrganisationServiceProvider.tsx +19 -15
- package/src/providers/services/UnifiedAuthProvider.tsx +156 -127
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +1 -1
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -3
- package/src/rbac/README.md +1 -1
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +25 -27
- package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +313 -0
- package/src/rbac/__tests__/engine.comprehensive.test.ts +114 -348
- package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +28 -110
- package/src/rbac/__tests__/rbac-engine-simplified.test.ts +33 -85
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +2 -2
- package/src/rbac/adapters.tsx +26 -69
- package/src/rbac/api.test.ts +90 -27
- package/src/rbac/api.ts +61 -10
- package/src/rbac/audit.test.ts +33 -38
- package/src/rbac/audit.ts +21 -6
- package/src/rbac/cache.ts +33 -1
- package/src/rbac/components/NavigationGuard.tsx +11 -11
- package/src/rbac/components/NavigationProvider.test.tsx +11 -5
- package/src/rbac/components/NavigationProvider.tsx +37 -13
- package/src/rbac/components/PagePermissionGuard.tsx +111 -50
- package/src/rbac/components/PagePermissionProvider.tsx +5 -5
- package/src/rbac/components/PermissionEnforcer.tsx +11 -11
- package/src/rbac/components/RoleBasedRouter.tsx +5 -5
- package/src/rbac/components/SecureDataProvider.tsx +5 -5
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +8 -8
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +14 -14
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +12 -12
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +6 -6
- package/src/rbac/engine.test.simple.ts +19 -13
- package/src/rbac/engine.test.ts +1 -0
- package/src/rbac/engine.ts +330 -766
- package/src/rbac/errors.ts +156 -0
- package/src/rbac/hooks/usePermissions.ts +32 -10
- package/src/rbac/hooks/useRBAC.test.ts +126 -512
- package/src/rbac/hooks/useRBAC.ts +147 -193
- package/src/rbac/hooks/useResolvedScope.ts +12 -0
- package/src/rbac/index.ts +7 -4
- package/src/rbac/security.ts +109 -18
- package/src/rbac/types.ts +12 -1
- package/src/services/AuthService.ts +2 -15
- package/src/services/EventService.ts +43 -46
- package/src/services/OrganisationService.ts +51 -31
- package/src/services/__tests__/AuthService.test.ts +1 -1
- package/src/services/__tests__/EventService.test.ts +1 -1
- package/src/services/__tests__/OrganisationService.test.ts +1 -1
- package/src/services/base/BaseService.ts +8 -0
- package/src/styles/base.css +208 -0
- package/src/styles/semantic.css +24 -0
- package/src/types/database.generated.ts +7347 -0
- package/src/types/database.ts +20 -0
- package/src/utils/logger.ts +179 -0
- package/src/utils/organisationContext.ts +11 -4
- package/src/utils/storage/__tests__/helpers.unit.test.ts +6 -2
- package/dist/appNameResolver-UURKN7NF.js +0 -22
- package/dist/audit-6TOCAMKO.js.map +0 -1
- package/dist/chunk-B2WTCLCV.js.map +0 -1
- package/dist/chunk-FGMFQSHX.js.map +0 -1
- package/dist/chunk-K34IM5CT.js.map +0 -1
- package/dist/chunk-KHJS6VIA.js.map +0 -1
- package/dist/chunk-KK73ZB4E.js.map +0 -1
- package/dist/chunk-M5IWZRBT.js.map +0 -1
- package/dist/chunk-ULBI5JGB.js +0 -109
- package/dist/chunk-ULBI5JGB.js.map +0 -1
- package/dist/chunk-WN6XJWOS.js.map +0 -1
- package/dist/chunk-XLZ7U46Z.js.map +0 -1
- package/dist/chunk-Y6TXWPJO.js.map +0 -1
- package/docs/DOCUMENTATION_CHECKLIST.md +0 -281
- package/docs/TERMINOLOGY.md +0 -231
- package/docs/api/interfaces/RBACContextType.md +0 -468
- package/docs/api/interfaces/RBACProviderProps.md +0 -107
- package/docs/best-practices/performance-expansion.md +0 -473
- package/docs/breaking-changes.md +0 -179
- package/docs/consuming-app-example.md +0 -290
- package/docs/documentation-templates.md +0 -539
- package/docs/examples/navigation-menu-auth-fix.md +0 -344
- package/docs/getting-started/examples/basic-auth-app.md +0 -520
- package/docs/getting-started/examples/full-featured-app.md +0 -616
- package/docs/getting-started/quick-start.md +0 -376
- package/docs/implementation-guides/datatable-filtering.md +0 -313
- package/docs/implementation-guides/datatable-rbac-usage.md +0 -317
- package/docs/implementation-guides/hierarchical-datatable.md +0 -850
- package/docs/implementation-guides/large-datasets.md +0 -281
- package/docs/implementation-guides/performance.md +0 -403
- package/docs/migration/quick-migration-guide.md +0 -320
- package/docs/migration-guide.md +0 -193
- package/docs/migration-guides/unified-auth-provider-mandatory-timeouts.md +0 -226
- package/docs/performance/README.md +0 -551
- package/docs/style-guide.md +0 -964
- package/docs/troubleshooting/authentication-issues.md +0 -334
- package/docs/troubleshooting/debugging.md +0 -1117
- package/docs/troubleshooting/migration.md +0 -918
- package/src/__tests__/hooks/usePermissions.test.ts +0 -261
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +0 -574
- package/src/hooks/__tests__/ServiceHooks.test.tsx +0 -613
- package/src/hooks/services/__tests__/useServiceHooks.test.tsx +0 -137
- package/src/hooks/services/usePermissions.ts +0 -70
- package/src/hooks/services/useRBACService.ts +0 -30
- package/src/hooks/usePermissionCheck.ts +0 -150
- package/src/providers/__tests__/ServiceProviders.test.tsx +0 -477
- package/src/providers/services/RBACServiceProvider.tsx +0 -79
- package/src/rbac/__tests__/integration.authflow.test.tsx +0 -119
- package/src/rbac/__tests__/integration.navigation.test.tsx +0 -69
- package/src/rbac/__tests__/integration.securedata.test.tsx +0 -92
- package/src/rbac/__tests__/integration.smoke.test.tsx +0 -73
- package/src/rbac/providers/RBACProvider.tsx +0 -645
- package/src/rbac/providers/__tests__/RBACProvider.integration.test.tsx +0 -688
- package/src/rbac/providers/__tests__/RBACProvider.test.tsx +0 -1186
- package/src/rbac/providers/index.ts +0 -11
- package/src/services/RBACService.ts +0 -522
- package/src/services/__tests__/RBACService.test.ts +0 -492
- package/src/services/interfaces/IRBACService.ts +0 -62
- package/src/utils/appNameResolver.test 2.ts +0 -494
- /package/dist/{DataTable-4GAVPIEG.js.map → DataTable-ETGVF4Y5.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-3NKDOSOK.js.map → UnifiedAuthProvider-P5SOJAQ6.js.map} +0 -0
- /package/dist/{api-DDMUKIUD.js.map → api-KG4A2X7P.js.map} +0 -0
- /package/dist/{appNameResolver-UURKN7NF.js.map → audit-65VNHEV2.js.map} +0 -0
- /package/dist/{chunk-NTNILOBC.js.map → chunk-5BO3MI5Y.js.map} +0 -0
- /package/dist/{chunk-URUTVZ7N.js.map → chunk-FL4ZCQLD.js.map} +0 -0
- /package/dist/{chunk-LW7MMEAQ.js.map → chunk-FT2M4R4F.js.map} +0 -0
- /package/dist/{chunk-AFGTSUAD.js.map → chunk-VSOKOFRF.js.map} +0 -0
- /package/docs/{app.css.example → styles/app.css.example} +0 -0
|
@@ -0,0 +1,1021 @@
|
|
|
1
|
+
---
|
|
2
|
+
lastUpdated: 2025-10-29T22:43:00+11:00
|
|
3
|
+
version: 0.5.76
|
|
4
|
+
reviewedBy: content-audit
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Authentication Implementation Guide
|
|
8
|
+
|
|
9
|
+
> **📚 Complete Authentication Guide** | [← Back to Documentation](../README.md) | [Installation Guide](../getting-started/installation-guide.md)
|
|
10
|
+
|
|
11
|
+
This comprehensive guide covers implementing authentication with PACE Core's UnifiedAuthProvider, including setup, configuration, troubleshooting, and best practices.
|
|
12
|
+
|
|
13
|
+
> **📚 API Reference**: See [useUnifiedAuth Hook](../api-reference/hooks.md#useunifiedauth) for complete hook documentation.
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
PACE Core provides a comprehensive authentication system built on Supabase that includes:
|
|
18
|
+
|
|
19
|
+
- **🔐 Unified Authentication** - Single provider for auth, RBAC, and event management
|
|
20
|
+
- **⏰ Inactivity Management** - Automatic session timeout with warnings
|
|
21
|
+
- **🏢 Organisation Context** - Multi-tenant support with organisation switching
|
|
22
|
+
- **📱 Event Management** - Event-based access control
|
|
23
|
+
- **🔒 Session Persistence** - Secure session management with auto-refresh
|
|
24
|
+
- **🎯 Permission Integration** - Built-in RBAC integration
|
|
25
|
+
- **📊 Debug Support** - Comprehensive debugging and monitoring
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
### 1. Project Setup
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Install PACE Core and dependencies
|
|
33
|
+
npm install @jmruthers/pace-core @supabase/supabase-js react-router-dom
|
|
34
|
+
|
|
35
|
+
# Install Tailwind CSS v4 (required)
|
|
36
|
+
npm install -D @tailwindcss/vite tailwindcss@^4.0.0
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 2. Environment Configuration
|
|
40
|
+
|
|
41
|
+
Create `.env.local`:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Supabase Configuration
|
|
45
|
+
REACT_APP_SUPABASE_URL=https://your-project.supabase.co
|
|
46
|
+
REACT_APP_SUPABASE_ANON_KEY=your-anon-key-here
|
|
47
|
+
|
|
48
|
+
# ⚠️ CRITICAL: Use anon key, NOT service role key
|
|
49
|
+
# The anon key starts with: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
|
|
50
|
+
# The service role key has different permissions and can cause RPC timeouts
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. Supabase Client Setup
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// src/lib/supabase.ts
|
|
57
|
+
import { createClient } from '@supabase/supabase-js'
|
|
58
|
+
|
|
59
|
+
const supabaseUrl = process.env.REACT_APP_SUPABASE_URL!
|
|
60
|
+
const supabaseAnonKey = process.env.REACT_APP_SUPABASE_ANON_KEY!
|
|
61
|
+
|
|
62
|
+
if (!supabaseUrl || !supabaseAnonKey) {
|
|
63
|
+
throw new Error('Missing Supabase environment variables')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 4. App Setup with Authentication
|
|
70
|
+
|
|
71
|
+
**CRITICAL**: UnifiedAuthProvider now requires inactivity timeout configuration:
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
// src/main.tsx
|
|
75
|
+
import React from 'react'
|
|
76
|
+
import ReactDOM from 'react-dom/client'
|
|
77
|
+
import { BrowserRouter } from 'react-router-dom'
|
|
78
|
+
import {
|
|
79
|
+
UnifiedAuthProvider
|
|
80
|
+
} from '@jmruthers/pace-core'
|
|
81
|
+
import { supabase } from './lib/supabase'
|
|
82
|
+
import App from './App.tsx'
|
|
83
|
+
|
|
84
|
+
// CRITICAL: Import the CSS system - includes everything you need
|
|
85
|
+
import '@jmruthers/pace-core/src/styles/core.css'
|
|
86
|
+
|
|
87
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
88
|
+
<React.StrictMode>
|
|
89
|
+
<BrowserRouter>
|
|
90
|
+
<UnifiedAuthProvider
|
|
91
|
+
supabaseClient={supabase}
|
|
92
|
+
appName="my-app"
|
|
93
|
+
enableRBAC={true}
|
|
94
|
+
requireOrganisationContext={true}
|
|
95
|
+
idleTimeoutMs={30 * 60 * 1000} // 30 minutes - REQUIRED
|
|
96
|
+
warnBeforeMs={60 * 1000} // 60 seconds - REQUIRED
|
|
97
|
+
onIdleLogout={() => window.location.href = '/login'} // REQUIRED
|
|
98
|
+
>
|
|
99
|
+
<App />
|
|
100
|
+
</UnifiedAuthProvider>
|
|
101
|
+
</BrowserRouter>
|
|
102
|
+
</React.StrictMode>,
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 5. Basic Login Page
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
// src/pages/LoginPage.tsx
|
|
110
|
+
import { LoginForm } from '@jmruthers/pace-core';
|
|
111
|
+
import { useNavigate } from 'react-router-dom';
|
|
112
|
+
|
|
113
|
+
export function LoginPage() {
|
|
114
|
+
const navigate = useNavigate();
|
|
115
|
+
|
|
116
|
+
const handleLoginSuccess = () => {
|
|
117
|
+
navigate('/');
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<div className="min-h-screen flex items-center justify-center bg-sec-50">
|
|
122
|
+
<div className="max-w-md w-full space-y-8">
|
|
123
|
+
<div>
|
|
124
|
+
<h2 className="mt-6 text-center text-3xl font-extrabold text-sec-900">
|
|
125
|
+
Sign in to My App
|
|
126
|
+
</h2>
|
|
127
|
+
</div>
|
|
128
|
+
<LoginForm onLoginSuccess={handleLoginSuccess} />
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 6. Protected Routes
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
// src/components/ProtectedRoute.tsx
|
|
139
|
+
import { useUnifiedAuth, Navigate } from '@jmruthers/pace-core';
|
|
140
|
+
|
|
141
|
+
function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
|
142
|
+
const { user, loading } = useUnifiedAuth();
|
|
143
|
+
|
|
144
|
+
if (loading) return <div>Loading...</div>;
|
|
145
|
+
if (!user) return <Navigate to="/login" />;
|
|
146
|
+
|
|
147
|
+
return <>{children}</>;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Usage in App.tsx
|
|
151
|
+
function App() {
|
|
152
|
+
return (
|
|
153
|
+
<Routes>
|
|
154
|
+
<Route path="/login" element={<LoginPage />} />
|
|
155
|
+
<Route path="/" element={
|
|
156
|
+
<ProtectedRoute>
|
|
157
|
+
<DashboardPage />
|
|
158
|
+
</ProtectedRoute>
|
|
159
|
+
} />
|
|
160
|
+
</Routes>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Configuration Options
|
|
166
|
+
|
|
167
|
+
### UnifiedAuthProvider Props
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
interface UnifiedAuthProviderProps {
|
|
171
|
+
// Required props
|
|
172
|
+
supabaseClient: SupabaseClient;
|
|
173
|
+
appName: string;
|
|
174
|
+
idleTimeoutMs: number; // Session timeout in milliseconds
|
|
175
|
+
warnBeforeMs: number; // Warning time before timeout
|
|
176
|
+
onIdleLogout: () => void; // Callback when session times out
|
|
177
|
+
|
|
178
|
+
// Optional props
|
|
179
|
+
enableRBAC?: boolean; // Enable RBAC integration (default: true)
|
|
180
|
+
requireOrganisationContext?: boolean; // Require organisation selection (default: false)
|
|
181
|
+
debug?: boolean; // Enable debug logging (default: false)
|
|
182
|
+
children: React.ReactNode;
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Complete Configuration Example
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
<UnifiedAuthProvider
|
|
190
|
+
supabaseClient={supabase}
|
|
191
|
+
appName="meal-manager"
|
|
192
|
+
enableRBAC={true}
|
|
193
|
+
requireOrganisationContext={true}
|
|
194
|
+
debug={process.env.NODE_ENV === 'development'}
|
|
195
|
+
idleTimeoutMs={30 * 60 * 1000} // 30 minutes
|
|
196
|
+
warnBeforeMs={5 * 60 * 1000} // 5 minutes warning
|
|
197
|
+
onIdleLogout={() => {
|
|
198
|
+
// Custom logout logic
|
|
199
|
+
console.log('Session expired');
|
|
200
|
+
window.location.href = '/login';
|
|
201
|
+
}}
|
|
202
|
+
>
|
|
203
|
+
<YourApp />
|
|
204
|
+
</UnifiedAuthProvider>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## useUnifiedAuth Hook
|
|
208
|
+
|
|
209
|
+
### Basic Usage
|
|
210
|
+
|
|
211
|
+
```tsx
|
|
212
|
+
import { useUnifiedAuth } from '@jmruthers/pace-core';
|
|
213
|
+
|
|
214
|
+
function UserDashboard() {
|
|
215
|
+
const {
|
|
216
|
+
user, // Current user object
|
|
217
|
+
loading, // Loading state
|
|
218
|
+
error, // Error state
|
|
219
|
+
session, // Current session
|
|
220
|
+
signIn, // Sign in function
|
|
221
|
+
signOut, // Sign out function
|
|
222
|
+
signUp, // Sign up function
|
|
223
|
+
resetPassword, // Password reset function
|
|
224
|
+
selectedEvent, // Currently selected event
|
|
225
|
+
setSelectedEvent, // Set selected event
|
|
226
|
+
hasEventAccess, // Check event access
|
|
227
|
+
} = useUnifiedAuth();
|
|
228
|
+
|
|
229
|
+
if (loading) return <div>Loading...</div>;
|
|
230
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
231
|
+
if (!user) return <div>Please log in</div>;
|
|
232
|
+
|
|
233
|
+
return (
|
|
234
|
+
<div>
|
|
235
|
+
<h1>Welcome, {user.email}</h1>
|
|
236
|
+
<button onClick={signOut}>Sign Out</button>
|
|
237
|
+
</div>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Authentication Methods
|
|
243
|
+
|
|
244
|
+
#### Sign In
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
const { signIn } = useUnifiedAuth();
|
|
248
|
+
|
|
249
|
+
// Email/password login
|
|
250
|
+
const handleLogin = async (email: string, password: string) => {
|
|
251
|
+
try {
|
|
252
|
+
await signIn({ email, password });
|
|
253
|
+
// User is now logged in
|
|
254
|
+
} catch (error) {
|
|
255
|
+
console.error('Login failed:', error);
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
// OAuth login (if configured)
|
|
260
|
+
const handleGoogleLogin = async () => {
|
|
261
|
+
try {
|
|
262
|
+
await signIn({ provider: 'google' });
|
|
263
|
+
} catch (error) {
|
|
264
|
+
console.error('Google login failed:', error);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
#### Sign Up
|
|
270
|
+
|
|
271
|
+
```tsx
|
|
272
|
+
const { signUp } = useUnifiedAuth();
|
|
273
|
+
|
|
274
|
+
const handleSignUp = async (email: string, password: string) => {
|
|
275
|
+
try {
|
|
276
|
+
await signUp({ email, password });
|
|
277
|
+
// User created, may need email confirmation
|
|
278
|
+
} catch (error) {
|
|
279
|
+
console.error('Sign up failed:', error);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
#### Password Reset
|
|
285
|
+
|
|
286
|
+
```tsx
|
|
287
|
+
const { resetPassword } = useUnifiedAuth();
|
|
288
|
+
|
|
289
|
+
const handlePasswordReset = async (email: string) => {
|
|
290
|
+
try {
|
|
291
|
+
await resetPassword(email);
|
|
292
|
+
// Password reset email sent
|
|
293
|
+
} catch (error) {
|
|
294
|
+
console.error('Password reset failed:', error);
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
#### Sign Out
|
|
300
|
+
|
|
301
|
+
```tsx
|
|
302
|
+
const { signOut } = useUnifiedAuth();
|
|
303
|
+
|
|
304
|
+
const handleSignOut = async () => {
|
|
305
|
+
try {
|
|
306
|
+
await signOut();
|
|
307
|
+
// User is now logged out
|
|
308
|
+
} catch (error) {
|
|
309
|
+
console.error('Sign out failed:', error);
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Event Management Integration
|
|
315
|
+
|
|
316
|
+
### Event Selection
|
|
317
|
+
|
|
318
|
+
```tsx
|
|
319
|
+
function EventSelector() {
|
|
320
|
+
const { selectedEvent, setSelectedEvent, hasEventAccess } = useUnifiedAuth();
|
|
321
|
+
|
|
322
|
+
const handleEventChange = (eventId: string) => {
|
|
323
|
+
if (hasEventAccess(eventId)) {
|
|
324
|
+
setSelectedEvent(eventId);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
return (
|
|
329
|
+
<select value={selectedEvent?.id || ''} onChange={(e) => handleEventChange(e.target.value)}>
|
|
330
|
+
<option value="">Select an event</option>
|
|
331
|
+
{/* Event options */}
|
|
332
|
+
</select>
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Event Access Control
|
|
338
|
+
|
|
339
|
+
```tsx
|
|
340
|
+
function EventContent() {
|
|
341
|
+
const { selectedEvent, hasEventAccess } = useUnifiedAuth();
|
|
342
|
+
|
|
343
|
+
if (!selectedEvent) {
|
|
344
|
+
return <div>Please select an event</div>;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (!hasEventAccess(selectedEvent.id)) {
|
|
348
|
+
return <div>You don't have access to this event</div>;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return <div>Event content for {selectedEvent.name}</div>;
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Organisation Context
|
|
356
|
+
|
|
357
|
+
### Organisation Selection
|
|
358
|
+
|
|
359
|
+
```tsx
|
|
360
|
+
function OrganisationSelector() {
|
|
361
|
+
const { user, selectedOrganisation, setSelectedOrganisation } = useUnifiedAuth();
|
|
362
|
+
|
|
363
|
+
const handleOrganisationChange = (orgId: string) => {
|
|
364
|
+
setSelectedOrganisation(orgId);
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
return (
|
|
368
|
+
<select
|
|
369
|
+
value={selectedOrganisation?.id || ''}
|
|
370
|
+
onChange={(e) => handleOrganisationChange(e.target.value)}
|
|
371
|
+
>
|
|
372
|
+
<option value="">Select organisation</option>
|
|
373
|
+
{user?.organisations?.map(org => (
|
|
374
|
+
<option key={org.id} value={org.id}>
|
|
375
|
+
{org.name}
|
|
376
|
+
</option>
|
|
377
|
+
))}
|
|
378
|
+
</select>
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Session Management
|
|
384
|
+
|
|
385
|
+
### Session Persistence
|
|
386
|
+
|
|
387
|
+
```tsx
|
|
388
|
+
// Supabase client configuration for session persistence
|
|
389
|
+
const supabase = createClient(url, key, {
|
|
390
|
+
auth: {
|
|
391
|
+
persistSession: true,
|
|
392
|
+
storage: window.localStorage,
|
|
393
|
+
autoRefreshToken: true,
|
|
394
|
+
detectSessionInUrl: true
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Session Monitoring
|
|
400
|
+
|
|
401
|
+
```tsx
|
|
402
|
+
import { useEffect } from 'react';
|
|
403
|
+
import { supabase } from './lib/supabase';
|
|
404
|
+
|
|
405
|
+
function SessionMonitor() {
|
|
406
|
+
useEffect(() => {
|
|
407
|
+
const {
|
|
408
|
+
data: { subscription },
|
|
409
|
+
} = supabase.auth.onAuthStateChange((event, session) => {
|
|
410
|
+
console.log('Auth event:', event, session?.user?.id);
|
|
411
|
+
|
|
412
|
+
if (event === 'SIGNED_IN') {
|
|
413
|
+
console.log('User signed in:', session?.user);
|
|
414
|
+
}
|
|
415
|
+
if (event === 'SIGNED_OUT') {
|
|
416
|
+
console.log('User signed out');
|
|
417
|
+
}
|
|
418
|
+
if (event === 'TOKEN_REFRESHED') {
|
|
419
|
+
console.log('Token refreshed');
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
return () => subscription.unsubscribe();
|
|
424
|
+
}, []);
|
|
425
|
+
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## Inactivity Management
|
|
431
|
+
|
|
432
|
+
### Configuration
|
|
433
|
+
|
|
434
|
+
```tsx
|
|
435
|
+
<UnifiedAuthProvider
|
|
436
|
+
supabaseClient={supabase}
|
|
437
|
+
appName="my-app"
|
|
438
|
+
idleTimeoutMs={30 * 60 * 1000} // 30 minutes
|
|
439
|
+
warnBeforeMs={5 * 60 * 1000} // 5 minutes warning
|
|
440
|
+
onIdleLogout={() => {
|
|
441
|
+
// Custom logout logic
|
|
442
|
+
localStorage.clear();
|
|
443
|
+
window.location.href = '/login';
|
|
444
|
+
}}
|
|
445
|
+
>
|
|
446
|
+
<App />
|
|
447
|
+
</UnifiedAuthProvider>
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Custom Inactivity Handling
|
|
451
|
+
|
|
452
|
+
```tsx
|
|
453
|
+
function InactivityHandler() {
|
|
454
|
+
const { user } = useUnifiedAuth();
|
|
455
|
+
|
|
456
|
+
useEffect(() => {
|
|
457
|
+
if (!user) return;
|
|
458
|
+
|
|
459
|
+
let inactivityTimer: NodeJS.Timeout;
|
|
460
|
+
let warningTimer: NodeJS.Timeout;
|
|
461
|
+
|
|
462
|
+
const resetTimers = () => {
|
|
463
|
+
clearTimeout(inactivityTimer);
|
|
464
|
+
clearTimeout(warningTimer);
|
|
465
|
+
|
|
466
|
+
// Set warning timer
|
|
467
|
+
warningTimer = setTimeout(() => {
|
|
468
|
+
alert('You will be logged out in 5 minutes due to inactivity');
|
|
469
|
+
}, 25 * 60 * 1000); // 25 minutes
|
|
470
|
+
|
|
471
|
+
// Set logout timer
|
|
472
|
+
inactivityTimer = setTimeout(() => {
|
|
473
|
+
window.location.href = '/login';
|
|
474
|
+
}, 30 * 60 * 1000); // 30 minutes
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
// Reset timers on user activity
|
|
478
|
+
const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart'];
|
|
479
|
+
events.forEach(event => {
|
|
480
|
+
document.addEventListener(event, resetTimers, true);
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
resetTimers();
|
|
484
|
+
|
|
485
|
+
return () => {
|
|
486
|
+
clearTimeout(inactivityTimer);
|
|
487
|
+
clearTimeout(warningTimer);
|
|
488
|
+
events.forEach(event => {
|
|
489
|
+
document.removeEventListener(event, resetTimers, true);
|
|
490
|
+
});
|
|
491
|
+
};
|
|
492
|
+
}, [user]);
|
|
493
|
+
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
## Navigation Integration
|
|
499
|
+
|
|
500
|
+
### Permission-Based Navigation
|
|
501
|
+
|
|
502
|
+
```tsx
|
|
503
|
+
import { NavigationMenu, NavigationItem } from '@jmruthers/pace-core';
|
|
504
|
+
import { useUnifiedAuth } from '@jmruthers/pace-core';
|
|
505
|
+
|
|
506
|
+
const navigationItems = [
|
|
507
|
+
{
|
|
508
|
+
label: 'Dashboard',
|
|
509
|
+
href: '/dashboard',
|
|
510
|
+
icon: 'Home',
|
|
511
|
+
permissions: ['read:dashboard']
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
label: 'Users',
|
|
515
|
+
href: '/users',
|
|
516
|
+
icon: 'Users',
|
|
517
|
+
permissions: ['read:users']
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
label: 'Events',
|
|
521
|
+
href: '/events',
|
|
522
|
+
icon: 'Calendar',
|
|
523
|
+
permissions: ['read:events']
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
label: 'Settings',
|
|
527
|
+
href: '/settings',
|
|
528
|
+
icon: 'Settings',
|
|
529
|
+
permissions: ['read:settings']
|
|
530
|
+
}
|
|
531
|
+
];
|
|
532
|
+
|
|
533
|
+
function AppNavigation() {
|
|
534
|
+
const { user } = useUnifiedAuth();
|
|
535
|
+
|
|
536
|
+
return (
|
|
537
|
+
<NavigationMenu
|
|
538
|
+
items={navigationItems}
|
|
539
|
+
currentPath={pathname}
|
|
540
|
+
onNavigate={(href) => router.push(href)}
|
|
541
|
+
user={user}
|
|
542
|
+
/>
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### User Menu Integration
|
|
548
|
+
|
|
549
|
+
```tsx
|
|
550
|
+
import {
|
|
551
|
+
NavigationMenu,
|
|
552
|
+
UserMenu,
|
|
553
|
+
Header
|
|
554
|
+
} from '@jmruthers/pace-core';
|
|
555
|
+
|
|
556
|
+
function AppHeader() {
|
|
557
|
+
const { user, signOut } = useUnifiedAuth();
|
|
558
|
+
|
|
559
|
+
const handleLogout = async () => {
|
|
560
|
+
await signOut();
|
|
561
|
+
window.location.href = '/login';
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
return (
|
|
565
|
+
<Header
|
|
566
|
+
title="My App"
|
|
567
|
+
user={user}
|
|
568
|
+
onLogout={handleLogout}
|
|
569
|
+
navigation={
|
|
570
|
+
<NavigationMenu
|
|
571
|
+
items={navigationItems}
|
|
572
|
+
currentPath={pathname}
|
|
573
|
+
onNavigate={(href) => router.push(href)}
|
|
574
|
+
/>
|
|
575
|
+
}
|
|
576
|
+
/>
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
## Common Patterns
|
|
582
|
+
|
|
583
|
+
### Authentication State Management
|
|
584
|
+
|
|
585
|
+
```tsx
|
|
586
|
+
function useAuthState() {
|
|
587
|
+
const { user, loading, error } = useUnifiedAuth();
|
|
588
|
+
|
|
589
|
+
return {
|
|
590
|
+
isAuthenticated: !!user,
|
|
591
|
+
isLoading: loading,
|
|
592
|
+
hasError: !!error,
|
|
593
|
+
user,
|
|
594
|
+
error
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### Conditional Rendering
|
|
600
|
+
|
|
601
|
+
```tsx
|
|
602
|
+
function ConditionalContent() {
|
|
603
|
+
const { user, loading } = useUnifiedAuth();
|
|
604
|
+
|
|
605
|
+
if (loading) {
|
|
606
|
+
return <div>Loading...</div>;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (!user) {
|
|
610
|
+
return <div>Please log in to continue</div>;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
return <div>Welcome, {user.email}!</div>;
|
|
614
|
+
}
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### Form Integration
|
|
618
|
+
|
|
619
|
+
```tsx
|
|
620
|
+
function LoginForm() {
|
|
621
|
+
const [email, setEmail] = useState('');
|
|
622
|
+
const [password, setPassword] = useState('');
|
|
623
|
+
const [loading, setLoading] = useState(false);
|
|
624
|
+
const [error, setError] = useState('');
|
|
625
|
+
const { signIn } = useUnifiedAuth();
|
|
626
|
+
|
|
627
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
628
|
+
e.preventDefault();
|
|
629
|
+
setLoading(true);
|
|
630
|
+
setError('');
|
|
631
|
+
|
|
632
|
+
try {
|
|
633
|
+
await signIn({ email, password });
|
|
634
|
+
} catch (err) {
|
|
635
|
+
setError(err instanceof Error ? err.message : 'Login failed');
|
|
636
|
+
} finally {
|
|
637
|
+
setLoading(false);
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
return (
|
|
642
|
+
<form onSubmit={handleSubmit}>
|
|
643
|
+
<input
|
|
644
|
+
type="email"
|
|
645
|
+
value={email}
|
|
646
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
647
|
+
placeholder="Email"
|
|
648
|
+
required
|
|
649
|
+
/>
|
|
650
|
+
<input
|
|
651
|
+
type="password"
|
|
652
|
+
value={password}
|
|
653
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
654
|
+
placeholder="Password"
|
|
655
|
+
required
|
|
656
|
+
/>
|
|
657
|
+
{error && <div className="error">{error}</div>}
|
|
658
|
+
<button type="submit" disabled={loading}>
|
|
659
|
+
{loading ? 'Signing in...' : 'Sign in'}
|
|
660
|
+
</button>
|
|
661
|
+
</form>
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
## Troubleshooting
|
|
667
|
+
|
|
668
|
+
### Most Common Issues
|
|
669
|
+
|
|
670
|
+
#### 1. Login Not Working
|
|
671
|
+
|
|
672
|
+
**Symptoms:**
|
|
673
|
+
- Login button does nothing
|
|
674
|
+
- "Invalid credentials" error
|
|
675
|
+
- Redirect not happening after login
|
|
676
|
+
|
|
677
|
+
**Immediate Fix:**
|
|
678
|
+
```tsx
|
|
679
|
+
// ✅ Ensure proper provider hierarchy
|
|
680
|
+
import { UnifiedAuthProvider } from '@jmruthers/pace-core';
|
|
681
|
+
import { supabase } from './lib/supabase';
|
|
682
|
+
|
|
683
|
+
function App() {
|
|
684
|
+
return (
|
|
685
|
+
<UnifiedAuthProvider
|
|
686
|
+
supabaseClient={supabase}
|
|
687
|
+
appName="my-app"
|
|
688
|
+
idleTimeoutMs={30 * 60 * 1000}
|
|
689
|
+
warnBeforeMs={5 * 60 * 1000}
|
|
690
|
+
onIdleLogout={() => window.location.href = '/login'}
|
|
691
|
+
>
|
|
692
|
+
<YourApp />
|
|
693
|
+
</UnifiedAuthProvider>
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
**Checklist:**
|
|
699
|
+
- [ ] Supabase URL and key are correct
|
|
700
|
+
- [ ] Provider hierarchy correct (Auth > Org > Event)
|
|
701
|
+
- [ ] User credentials are valid in Supabase
|
|
702
|
+
- [ ] Network connectivity working
|
|
703
|
+
- [ ] Browser not blocking cookies
|
|
704
|
+
|
|
705
|
+
#### 2. Session Not Persisting
|
|
706
|
+
|
|
707
|
+
**Symptoms:**
|
|
708
|
+
- User logged out on page refresh
|
|
709
|
+
- Session cleared on browser restart
|
|
710
|
+
- Need to login repeatedly
|
|
711
|
+
|
|
712
|
+
**Fix:**
|
|
713
|
+
```tsx
|
|
714
|
+
// Check Supabase session configuration
|
|
715
|
+
const supabase = createClient(url, key, {
|
|
716
|
+
auth: {
|
|
717
|
+
persistSession: true,
|
|
718
|
+
storage: window.localStorage,
|
|
719
|
+
autoRefreshToken: true,
|
|
720
|
+
detectSessionInUrl: true
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
// Verify session exists
|
|
725
|
+
useEffect(() => {
|
|
726
|
+
supabase.auth.getSession().then(({ data: { session } }) => {
|
|
727
|
+
console.log('Current session:', session);
|
|
728
|
+
});
|
|
729
|
+
}, []);
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
#### 3. User State Not Updating
|
|
733
|
+
|
|
734
|
+
**Symptoms:**
|
|
735
|
+
- Login succeeds but user state is null
|
|
736
|
+
- `useUnifiedAuth()` returns undefined
|
|
737
|
+
- Components don't react to auth changes
|
|
738
|
+
|
|
739
|
+
**Fix:**
|
|
740
|
+
```tsx
|
|
741
|
+
// ✅ Ensure provider is set up correctly
|
|
742
|
+
function App() {
|
|
743
|
+
return (
|
|
744
|
+
<UnifiedAuthProvider supabaseClient={supabase} appName="my-app">
|
|
745
|
+
<AuthTest />
|
|
746
|
+
</UnifiedAuthProvider>
|
|
747
|
+
);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
function AuthTest() {
|
|
751
|
+
const { user, loading, error } = useUnifiedAuth();
|
|
752
|
+
|
|
753
|
+
if (loading) return <div>Loading...</div>;
|
|
754
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
755
|
+
if (!user) return <div>Not logged in</div>;
|
|
756
|
+
|
|
757
|
+
return <div>Welcome {user.email}</div>;
|
|
758
|
+
}
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
### Detailed Solutions
|
|
762
|
+
|
|
763
|
+
#### Wrong Supabase Configuration
|
|
764
|
+
|
|
765
|
+
**Problem:** Using service role key instead of anon key
|
|
766
|
+
|
|
767
|
+
```tsx
|
|
768
|
+
// ❌ WRONG - Service role key
|
|
769
|
+
const supabase = createClient(url, SERVICE_ROLE_KEY);
|
|
770
|
+
|
|
771
|
+
// ✅ CORRECT - Anonymous key
|
|
772
|
+
const supabase = createClient(url, ANON_KEY);
|
|
773
|
+
|
|
774
|
+
// Check key format
|
|
775
|
+
console.log('Key starts with:', ANON_KEY.substring(0, 30));
|
|
776
|
+
// Should be: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
#### Provider Hierarchy Issues
|
|
780
|
+
|
|
781
|
+
**Problem:** Providers not in correct order
|
|
782
|
+
|
|
783
|
+
```tsx
|
|
784
|
+
// ❌ WRONG ORDER
|
|
785
|
+
<EventProvider>
|
|
786
|
+
<OrganisationProvider>
|
|
787
|
+
<UnifiedAuthProvider supabaseClient={supabase} appName="my-app">
|
|
788
|
+
<App />
|
|
789
|
+
</UnifiedAuthProvider>
|
|
790
|
+
</OrganisationProvider>
|
|
791
|
+
</EventProvider>
|
|
792
|
+
|
|
793
|
+
// ✅ CORRECT ORDER
|
|
794
|
+
<UnifiedAuthProvider supabaseClient={supabase} appName="my-app">
|
|
795
|
+
<OrganisationProvider>
|
|
796
|
+
<EventProvider>
|
|
797
|
+
<App />
|
|
798
|
+
</EventProvider>
|
|
799
|
+
</OrganisationProvider>
|
|
800
|
+
</UnifiedAuthProvider>
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
#### Missing Inactivity Timeout Props
|
|
804
|
+
|
|
805
|
+
**Problem:** TypeScript error in v0.5.65+
|
|
806
|
+
|
|
807
|
+
```tsx
|
|
808
|
+
// ❌ OLD API (broken in v0.5.65+)
|
|
809
|
+
<UnifiedAuthProvider supabaseClient={supabase} appName="my-app">
|
|
810
|
+
<App />
|
|
811
|
+
</UnifiedAuthProvider>
|
|
812
|
+
|
|
813
|
+
// ✅ NEW API (required)
|
|
814
|
+
<UnifiedAuthProvider
|
|
815
|
+
supabaseClient={supabase}
|
|
816
|
+
appName="my-app"
|
|
817
|
+
idleTimeoutMs={30 * 60 * 1000} // Required
|
|
818
|
+
warnBeforeMs={5 * 60 * 1000} // Required
|
|
819
|
+
onIdleLogout={() => navigate('/login')} // Required
|
|
820
|
+
>
|
|
821
|
+
<App />
|
|
822
|
+
</UnifiedAuthProvider>
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
### Debugging Techniques
|
|
826
|
+
|
|
827
|
+
#### Enable Debug Logging
|
|
828
|
+
|
|
829
|
+
```tsx
|
|
830
|
+
<UnifiedAuthProvider
|
|
831
|
+
supabaseClient={supabase}
|
|
832
|
+
appName="my-app"
|
|
833
|
+
debug={true} // Enable debug mode
|
|
834
|
+
idleTimeoutMs={30 * 60 * 1000}
|
|
835
|
+
warnBeforeMs={5 * 60 * 1000}
|
|
836
|
+
onIdleLogout={() => window.location.href = '/login'}
|
|
837
|
+
>
|
|
838
|
+
<App />
|
|
839
|
+
</UnifiedAuthProvider>
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
#### Check Auth State
|
|
843
|
+
|
|
844
|
+
```tsx
|
|
845
|
+
function AuthDebugger() {
|
|
846
|
+
const { user, loading, error, session } = useUnifiedAuth();
|
|
847
|
+
|
|
848
|
+
useEffect(() => {
|
|
849
|
+
console.log('Auth state:', {
|
|
850
|
+
user: user?.id,
|
|
851
|
+
email: user?.email,
|
|
852
|
+
loading,
|
|
853
|
+
error: error?.message,
|
|
854
|
+
hasSession: !!session
|
|
855
|
+
});
|
|
856
|
+
}, [user, loading, error, session]);
|
|
857
|
+
|
|
858
|
+
return null;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
// Add to your app
|
|
862
|
+
<AuthDebugger />
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
### Common Error Messages
|
|
866
|
+
|
|
867
|
+
#### "Missing supabaseClient prop"
|
|
868
|
+
|
|
869
|
+
**Problem:** `UnifiedAuthProvider` not receiving supabase client
|
|
870
|
+
|
|
871
|
+
**Fix:**
|
|
872
|
+
```tsx
|
|
873
|
+
// ✅ Ensure you're passing the client
|
|
874
|
+
import { createClient } from '@supabase/supabase-js';
|
|
875
|
+
import { UnifiedAuthProvider } from '@jmruthers/pace-core';
|
|
876
|
+
|
|
877
|
+
const supabase = createClient(url, key);
|
|
878
|
+
|
|
879
|
+
<UnifiedAuthProvider supabaseClient={supabase} appName="my-app">
|
|
880
|
+
<App />
|
|
881
|
+
</UnifiedAuthProvider>
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
#### "Invalid credentials"
|
|
885
|
+
|
|
886
|
+
**Problem:** Wrong email/password or user not found
|
|
887
|
+
|
|
888
|
+
**Solutions:**
|
|
889
|
+
1. Check user exists in Supabase Auth
|
|
890
|
+
2. Verify email/password are correct
|
|
891
|
+
3. Check email confirmation required
|
|
892
|
+
4. Verify user is not disabled
|
|
893
|
+
|
|
894
|
+
```tsx
|
|
895
|
+
// Check user exists
|
|
896
|
+
const { data, error } = await supabase.auth.signInWithPassword({
|
|
897
|
+
email: 'user@example.com',
|
|
898
|
+
password: 'password'
|
|
899
|
+
});
|
|
900
|
+
console.log('Login result:', { data, error });
|
|
901
|
+
```
|
|
902
|
+
|
|
903
|
+
#### "Missing timeout props" (v0.5.65+)
|
|
904
|
+
|
|
905
|
+
**Problem:** Required props not provided
|
|
906
|
+
|
|
907
|
+
**Fix:**
|
|
908
|
+
```tsx
|
|
909
|
+
// Add all required props
|
|
910
|
+
<UnifiedAuthProvider
|
|
911
|
+
supabaseClient={supabase}
|
|
912
|
+
appName="my-app"
|
|
913
|
+
idleTimeoutMs={30 * 60 * 1000} // 30 minutes
|
|
914
|
+
warnBeforeMs={5 * 60 * 1000} // 5 minutes warning
|
|
915
|
+
onIdleLogout={() => window.location.href = '/login'}
|
|
916
|
+
>
|
|
917
|
+
<App />
|
|
918
|
+
</UnifiedAuthProvider>
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
## Best Practices
|
|
922
|
+
|
|
923
|
+
### Security
|
|
924
|
+
|
|
925
|
+
1. **Use Anonymous Key**: Never use service role key in client-side code
|
|
926
|
+
2. **Enable RLS**: Use Row Level Security in Supabase
|
|
927
|
+
3. **Validate Input**: Always validate user input
|
|
928
|
+
4. **Secure Storage**: Use secure storage for sensitive data
|
|
929
|
+
5. **HTTPS Only**: Always use HTTPS in production
|
|
930
|
+
|
|
931
|
+
### Performance
|
|
932
|
+
|
|
933
|
+
1. **Lazy Loading**: Load authentication components lazily
|
|
934
|
+
2. **Memoization**: Use React.memo for expensive components
|
|
935
|
+
3. **Debouncing**: Debounce user input in forms
|
|
936
|
+
4. **Session Caching**: Cache session data appropriately
|
|
937
|
+
5. **Error Boundaries**: Use error boundaries for auth components
|
|
938
|
+
|
|
939
|
+
### User Experience
|
|
940
|
+
|
|
941
|
+
1. **Loading States**: Always show loading states
|
|
942
|
+
2. **Error Messages**: Provide clear error messages
|
|
943
|
+
3. **Redirects**: Handle redirects gracefully
|
|
944
|
+
4. **Session Warnings**: Warn users before session timeout
|
|
945
|
+
5. **Accessibility**: Ensure auth components are accessible
|
|
946
|
+
|
|
947
|
+
### Code Organization
|
|
948
|
+
|
|
949
|
+
1. **Separation of Concerns**: Separate auth logic from UI
|
|
950
|
+
2. **Custom Hooks**: Create custom hooks for auth logic
|
|
951
|
+
3. **Type Safety**: Use TypeScript for better type safety
|
|
952
|
+
4. **Error Handling**: Implement comprehensive error handling
|
|
953
|
+
5. **Testing**: Write tests for auth components
|
|
954
|
+
|
|
955
|
+
## Migration Guide
|
|
956
|
+
|
|
957
|
+
### From v0.5.64 to v0.5.65+
|
|
958
|
+
|
|
959
|
+
**Breaking Changes:**
|
|
960
|
+
- Inactivity timeout props are now required
|
|
961
|
+
- Provider hierarchy has changed
|
|
962
|
+
- Some hook interfaces have been updated
|
|
963
|
+
|
|
964
|
+
**Migration Steps:**
|
|
965
|
+
|
|
966
|
+
1. **Update Provider Configuration:**
|
|
967
|
+
```tsx
|
|
968
|
+
// Before
|
|
969
|
+
<UnifiedAuthProvider supabaseClient={supabase} appName="my-app">
|
|
970
|
+
<App />
|
|
971
|
+
</UnifiedAuthProvider>
|
|
972
|
+
|
|
973
|
+
// After
|
|
974
|
+
<UnifiedAuthProvider
|
|
975
|
+
supabaseClient={supabase}
|
|
976
|
+
appName="my-app"
|
|
977
|
+
idleTimeoutMs={30 * 60 * 1000}
|
|
978
|
+
warnBeforeMs={5 * 60 * 1000}
|
|
979
|
+
onIdleLogout={() => window.location.href = '/login'}
|
|
980
|
+
>
|
|
981
|
+
<App />
|
|
982
|
+
</UnifiedAuthProvider>
|
|
983
|
+
```
|
|
984
|
+
|
|
985
|
+
2. **Update Hook Usage:**
|
|
986
|
+
```tsx
|
|
987
|
+
// Before
|
|
988
|
+
const { user, signIn, signOut } = useUnifiedAuth();
|
|
989
|
+
|
|
990
|
+
// After (same interface, but with additional features)
|
|
991
|
+
const { user, signIn, signOut, selectedEvent, setSelectedEvent } = useUnifiedAuth();
|
|
992
|
+
```
|
|
993
|
+
|
|
994
|
+
3. **Test Authentication Flow:**
|
|
995
|
+
- Verify login/logout works
|
|
996
|
+
- Check session persistence
|
|
997
|
+
- Test inactivity timeout
|
|
998
|
+
- Verify error handling
|
|
999
|
+
|
|
1000
|
+
## Examples
|
|
1001
|
+
|
|
1002
|
+
### Complete Authentication App
|
|
1003
|
+
|
|
1004
|
+
See the [Authentication Implementation Guide](./authentication.md) for a complete working example with step-by-step instructions.
|
|
1005
|
+
|
|
1006
|
+
### Advanced Patterns
|
|
1007
|
+
|
|
1008
|
+
See the [Common Patterns Guide](./best-practices/common-patterns.md) for advanced authentication patterns.
|
|
1009
|
+
|
|
1010
|
+
## Related Documentation
|
|
1011
|
+
|
|
1012
|
+
- [RBAC Integration](./rbac/README.md) - Role-based access control
|
|
1013
|
+
- [Event Management](./events/README.md) - Event-based access control
|
|
1014
|
+
- [Navigation Integration](./navigation.md) - Permission-based navigation
|
|
1015
|
+
- [Troubleshooting Guide](./troubleshooting/README.md) - Common issues and solutions
|
|
1016
|
+
|
|
1017
|
+
## Conclusion
|
|
1018
|
+
|
|
1019
|
+
PACE Core's authentication system provides a comprehensive solution for user authentication, session management, and access control. With built-in RBAC integration, event management, and inactivity handling, it provides everything needed for secure, user-friendly applications.
|
|
1020
|
+
|
|
1021
|
+
The system is designed to be both powerful and easy to use, with extensive debugging support and clear error messages to help developers build robust authentication flows.
|