@jmruthers/pace-core 0.5.134 → 0.5.136
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/dist/{DataTable-C7GaRZye.d.ts → DataTable-CWAZZcXC.d.ts} +1 -1
- package/dist/{DataTable-A36PJG6N.js → DataTable-CYOHOX3O.js} +25 -13
- package/dist/{PublicLoadingSpinner-CUAnTvcg.d.ts → EventLogo-801uofbR.d.ts} +51 -135
- package/dist/UnifiedAuthProvider-5E5TUNMS.js +17 -0
- package/dist/{UnifiedAuthProvider-BVKmQd9u.d.ts → UnifiedAuthProvider-DJxGTftH.d.ts} +1 -1
- package/dist/{api-TNIBJWLM.js → api-45XYYO2A.js} +4 -3
- package/dist/{audit-T36HM7IM.js → audit-64X3VJXB.js} +3 -2
- package/dist/{chunk-CTJRBUX2.js → chunk-2TWNJ46Y.js} +2 -2
- package/dist/{chunk-UJI6WSMD.js → chunk-444EZN6N.js} +3 -3
- package/dist/chunk-444EZN6N.js.map +1 -0
- package/dist/{chunk-3CG5L6RN.js → chunk-4MT5BGGL.js} +90 -73
- package/dist/chunk-4MT5BGGL.js.map +1 -0
- package/dist/{chunk-PYUXFQJ3.js → chunk-56XJ3TU6.js} +2 -2
- package/dist/chunk-56XJ3TU6.js.map +1 -0
- package/dist/chunk-5DPZ5EAT.js +60 -0
- package/dist/chunk-5DPZ5EAT.js.map +1 -0
- package/dist/{chunk-66C4BSAY.js → chunk-ANBQRTPX.js} +9 -2
- package/dist/chunk-ANBQRTPX.js.map +1 -0
- package/dist/chunk-APIBCTL2.js +670 -0
- package/dist/chunk-APIBCTL2.js.map +1 -0
- package/dist/{chunk-GKHF54DI.js → chunk-BESYRHQM.js} +10 -4
- package/dist/chunk-BESYRHQM.js.map +1 -0
- package/dist/{chunk-WP5I5GLN.js → chunk-BVYWGZVV.js} +112 -97
- package/dist/chunk-BVYWGZVV.js.map +1 -0
- package/dist/{chunk-GEVIB2UB.js → chunk-ERISIBYU.js} +14 -5
- package/dist/chunk-ERISIBYU.js.map +1 -0
- package/dist/{chunk-CQZU6TFE.js → chunk-FHWWBIHA.js} +100 -62
- package/dist/chunk-FHWWBIHA.js.map +1 -0
- package/dist/{chunk-O3NWNXDY.js → chunk-FMUCXFII.js} +2 -2
- package/dist/chunk-FMUCXFII.js.map +1 -0
- package/dist/{chunk-GVDR7WNV.js → chunk-HJGGOMQ6.js} +194 -518
- package/dist/chunk-HJGGOMQ6.js.map +1 -0
- package/dist/{chunk-BDZUMRBD.js → chunk-K2WWTH7O.js} +13 -6
- package/dist/chunk-K2WWTH7O.js.map +1 -0
- package/dist/{chunk-BYXRHAIF.js → chunk-L6PGMCMD.js} +23 -14
- package/dist/chunk-L6PGMCMD.js.map +1 -0
- package/dist/chunk-LMC26NLJ.js +84 -0
- package/dist/chunk-LMC26NLJ.js.map +1 -0
- package/dist/{chunk-M6DDYFUD.js → chunk-LS353YLY.js} +19 -16
- package/dist/chunk-LS353YLY.js.map +1 -0
- package/dist/{chunk-ZYZCRSBD.js → chunk-LTV3XIJJ.js} +16 -11
- package/dist/chunk-LTV3XIJJ.js.map +1 -0
- package/dist/{chunk-HMNOSGVA.js → chunk-NOHEVYVX.js} +377 -666
- package/dist/chunk-NOHEVYVX.js.map +1 -0
- package/dist/{chunk-JCQZ6LA7.js → chunk-Q5QRDWKI.js} +9 -3
- package/dist/chunk-Q5QRDWKI.js.map +1 -0
- package/dist/chunk-S5OFRT4M.js +94 -0
- package/dist/chunk-S5OFRT4M.js.map +1 -0
- package/dist/{chunk-3DBFLLLU.js → chunk-SBVILCCA.js} +14 -9
- package/dist/chunk-SBVILCCA.js.map +1 -0
- package/dist/{chunk-TGIY2AR2.js → chunk-SL2YQDR6.js} +4 -3
- package/dist/{chunk-TGIY2AR2.js.map → chunk-SL2YQDR6.js.map} +1 -1
- package/dist/{chunk-VZ5OR6HD.js → chunk-TVYPTYOY.js} +55 -179
- package/dist/chunk-TVYPTYOY.js.map +1 -0
- package/dist/{chunk-ZV77RZMU.js → chunk-XARJS7CD.js} +2 -2
- package/dist/chunk-XDNLUEXI.js +138 -0
- package/dist/chunk-XDNLUEXI.js.map +1 -0
- package/dist/{chunk-F64FFPOZ.js → chunk-YLKIDTUK.js} +26 -20
- package/dist/chunk-YLKIDTUK.js.map +1 -0
- package/dist/{chunk-5F3NDPJV.js → chunk-ZZ2SS7NI.js} +10 -5
- package/dist/chunk-ZZ2SS7NI.js.map +1 -0
- package/dist/components.d.ts +7 -287
- package/dist/components.js +26 -157
- package/dist/components.js.map +1 -1
- package/dist/{file-reference-C9isKNPn.d.ts → file-reference-C6Gkn77H.d.ts} +1 -1
- package/dist/{formatting-DFcCxUEk.d.ts → formatting-CvUXy2mF.d.ts} +1 -1
- package/dist/hooks.d.ts +3 -3
- package/dist/hooks.js +22 -16
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +219 -9
- package/dist/index.js +49 -31
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +5 -4
- package/dist/rbac/index.js +13 -12
- package/dist/styles/index.js +2 -1
- package/dist/theming/runtime.d.ts +2 -19
- package/dist/theming/runtime.js +2 -1
- package/dist/{types-D5rqZQXk.d.ts → types-Dfz9dmVH.d.ts} +12 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- package/dist/{useInactivityTracker-MRUU55XI.js → useInactivityTracker-TO6ZOF35.js} +3 -2
- package/dist/{usePublicRouteParams-Dyt1tzI9.d.ts → usePublicRouteParams-B7PabvuH.d.ts} +1 -1
- package/dist/utils.d.ts +195 -232
- package/dist/utils.js +173 -331
- package/dist/utils.js.map +1 -1
- package/dist/{validation-DnhrNMju.d.ts → validation-8npbysjg.d.ts} +26 -8
- package/dist/validation.d.ts +261 -10
- package/dist/validation.js +82 -440
- package/dist/validation.js.map +1 -1
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +6 -6
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +6 -6
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +7 -7
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- 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 +29 -4
- package/docs/api/interfaces/DataAccessRecord.md +9 -9
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +18 -18
- package/docs/api/interfaces/DataTableColumn.md +61 -1
- package/docs/api/interfaces/DataTableProps.md +3 -3
- package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
- package/docs/api/interfaces/EmptyStateConfig.md +5 -5
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +14 -14
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +152 -0
- package/docs/api/interfaces/ExportColumn.md +90 -0
- package/docs/api/interfaces/ExportOptions.md +126 -0
- package/docs/api/interfaces/FileDisplayProps.md +15 -15
- 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/GrantEventAppRoleParams.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 +10 -10
- package/docs/api/interfaces/NavigationContextType.md +9 -9
- package/docs/api/interfaces/NavigationGuardProps.md +10 -10
- 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 +27 -27
- package/docs/api/interfaces/PaceLoginPageProps.md +4 -4
- package/docs/api/interfaces/PageAccessRecord.md +8 -8
- package/docs/api/interfaces/PagePermissionContextType.md +8 -8
- package/docs/api/interfaces/PagePermissionGuardProps.md +11 -11
- package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
- package/docs/api/interfaces/PaletteData.md +4 -4
- package/docs/api/interfaces/PermissionEnforcerProps.md +11 -11
- package/docs/api/interfaces/ProtectedRouteProps.md +6 -6
- 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/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
- package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +10 -10
- package/docs/api/interfaces/RouteConfig.md +10 -10
- package/docs/api/interfaces/SecureDataContextType.md +9 -9
- package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +21 -0
- 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 +53 -53
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +9 -9
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
- package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
- package/docs/api/interfaces/UsePublicEventReturn.md +5 -5
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +9 -9
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +4 -4
- package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
- 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 +648 -212
- package/docs/api-reference/components.md +106 -26
- package/docs/architecture/README.md +0 -2
- package/docs/implementation-guides/data-tables.md +277 -13
- package/docs/implementation-guides/forms.md +1 -16
- package/docs/implementation-guides/permission-enforcement.md +8 -2
- package/examples/README.md +30 -14
- package/examples/STRUCTURE.md +125 -0
- package/examples/components/DataTable/HierarchicalActionsExample.tsx +421 -0
- package/examples/components/DataTable/HierarchicalExample.tsx +475 -0
- package/examples/components/DataTable/InitialPageSizeExample.tsx +177 -0
- package/examples/components/DataTable/PerformanceExample.tsx +506 -0
- package/examples/components/DataTable/index.ts +13 -0
- package/examples/components/Dialog/BasicHtmlTest.tsx +55 -0
- package/examples/components/Dialog/DebugHtmlExample.tsx +68 -0
- package/examples/components/Dialog/HtmlDialogExample.tsx +202 -0
- package/examples/components/Dialog/ScrollableDialogExample.tsx +290 -0
- package/examples/components/Dialog/SimpleHtmlTest.tsx +61 -0
- package/examples/components/Dialog/SmartDialogExample.tsx +322 -0
- package/examples/components/Dialog/index.ts +15 -0
- package/examples/components/index.ts +11 -0
- package/examples/features/index.ts +12 -0
- package/examples/{public-pages → features/public-pages}/CorrectPublicPageImplementation.tsx +1 -1
- package/examples/{public-pages → features/public-pages}/PublicEventPage.tsx +1 -1
- package/examples/{public-pages → features/public-pages}/PublicPageApp.tsx +1 -1
- package/examples/{public-pages → features/public-pages}/PublicPageUsageExample.tsx +1 -1
- package/examples/index.ts +11 -3
- package/package.json +30 -10
- package/src/components/Alert/Alert.tsx +1 -1
- package/src/components/Avatar/Avatar.tsx +1 -1
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Card/Card.tsx +1 -1
- package/src/components/Checkbox/Checkbox.tsx +1 -1
- package/src/components/DataTable/DataTable.test.tsx +1 -1
- package/src/components/DataTable/DataTable.tsx +1 -30
- package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +562 -0
- package/src/components/DataTable/__tests__/styles.test.ts +2 -2
- package/src/components/DataTable/components/ActionButtons.tsx +0 -15
- package/src/components/DataTable/components/DataTableCore.tsx +4 -185
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +1 -1
- package/src/components/DataTable/components/DataTableModals.tsx +1 -27
- package/src/components/DataTable/components/EditableRow.tsx +1 -1
- package/src/components/DataTable/components/ImportModal.tsx +2 -14
- package/src/components/DataTable/components/PaginationControls.tsx +1 -1
- package/src/components/DataTable/components/UnifiedTableBody.tsx +109 -82
- package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +1 -1
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +1 -1
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +1 -1
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +1 -1
- package/src/components/DataTable/examples/GroupingAggregationExample.tsx +273 -0
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +1 -1
- package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +1 -1
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +1 -1
- package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +1 -1
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +2 -23
- package/src/components/DataTable/index.ts +4 -0
- package/src/components/DataTable/styles.ts +1 -1
- package/src/components/DataTable/types.ts +13 -0
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +1 -1
- package/src/components/DataTable/utils/aggregationUtils.ts +161 -0
- package/src/components/DataTable/utils/exportUtils.ts +1 -1
- package/src/components/DataTable/utils/flexibleImport.ts +1 -11
- package/src/components/DataTable/utils/index.ts +1 -0
- package/src/components/DataTable/utils/paginationUtils.ts +1 -1
- package/src/components/Dialog/Dialog.tsx +2 -2
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +35 -7
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +5 -4
- package/src/components/EventSelector/EventSelector.tsx +3 -2
- package/src/components/FileDisplay/FileDisplay.tsx +2 -36
- package/src/components/FileUpload/FileUpload.test.tsx +2 -2
- package/src/components/FileUpload/FileUpload.tsx +2 -2
- package/src/components/Footer/Footer.tsx +1 -1
- package/src/components/Form/Form.test.tsx +4 -509
- package/src/components/Form/Form.tsx +1 -1
- package/src/components/Form/FormField.tsx +1 -1
- package/src/components/Form/index.ts +0 -12
- package/src/components/Header/Header.tsx +1 -1
- package/src/components/Input/Input.tsx +1 -1
- package/src/components/Label/Label.tsx +1 -1
- package/src/components/LoginForm/LoginForm.tsx +1 -1
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -3
- package/src/components/NavigationMenu/NavigationMenu.tsx +9 -8
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +4 -3
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +14 -12
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +0 -16
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +0 -1
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -9
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +35 -3
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +13 -12
- package/src/components/PasswordReset/PasswordChangeForm.tsx +1 -1
- package/src/components/PasswordReset/index.ts +0 -2
- package/src/components/Progress/Progress.tsx +1 -1
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +35 -8
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -2
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +1 -1
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +1 -1
- package/src/components/PublicLayout/PublicPageContextChecker.tsx +44 -43
- package/src/components/PublicLayout/PublicPageFooter.tsx +1 -1
- package/src/components/PublicLayout/PublicPageHeader.tsx +1 -15
- package/src/components/PublicLayout/PublicPageProvider.tsx +3 -2
- package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +2 -0
- package/src/components/PublicLayout/index.ts +4 -2
- package/src/components/Select/Select.tsx +1 -1
- package/src/components/{SessionRestorationLoader.tsx → SessionRestorationLoader/SessionRestorationLoader.tsx} +3 -2
- package/src/components/SessionRestorationLoader/index.ts +3 -0
- package/src/components/Switch/Switch.tsx +1 -1
- package/src/components/Table/Table.tsx +1 -1
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/components/Tooltip/Tooltip.tsx +1 -1
- package/src/components/index.ts +4 -10
- package/src/hooks/__tests__/hooks.integration.test.tsx +37 -22
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +33 -17
- package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +28 -3
- package/src/hooks/__tests__/useFileDisplay.unit.test.ts +36 -9
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +26 -2
- package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +19 -6
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +17 -4
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +17 -4
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +26 -6
- package/src/hooks/__tests__/usePublicFileDisplay.test.ts +16 -6
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +3 -3
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +17 -3
- package/src/hooks/public/usePublicEvent.ts +7 -6
- package/src/hooks/public/usePublicEventLogo.ts +7 -4
- package/src/hooks/public/usePublicFileDisplay.ts +6 -150
- package/src/hooks/useComponentPerformance.ts +4 -1
- package/src/hooks/useDataTablePerformance.ts +4 -3
- package/src/hooks/useEventTheme.test.ts +18 -5
- package/src/hooks/useEventTheme.ts +4 -1
- package/src/hooks/useEvents.ts +2 -0
- package/src/hooks/useFileDisplay.ts +9 -8
- package/src/hooks/useFileReference.ts +4 -1
- package/src/hooks/useFileUrl.ts +4 -1
- package/src/hooks/useInactivityTracker.ts +5 -4
- package/src/hooks/useOrganisationSecurity.test.ts +33 -12
- package/src/hooks/useOrganisationSecurity.ts +8 -7
- package/src/hooks/usePerformanceMonitor.ts +6 -3
- package/src/hooks/usePermissionCache.ts +13 -6
- package/src/hooks/useSecureDataAccess.test.ts +2 -2
- package/src/hooks/useSecureDataAccess.ts +9 -8
- package/src/hooks/useSessionRestoration.ts +4 -1
- package/src/hooks/useStorage.ts +4 -1
- package/src/index.ts +25 -8
- package/src/providers/services/AuthServiceProvider.tsx +3 -2
- package/src/providers/services/EventServiceProvider.tsx +2 -1
- package/src/providers/services/InactivityServiceProvider.tsx +2 -1
- package/src/providers/services/OrganisationServiceProvider.tsx +2 -1
- package/src/providers/services/UnifiedAuthProvider.tsx +4 -3
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +22 -2
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +24 -2
- package/src/rbac/__tests__/cache-invalidation.test.ts +20 -6
- package/src/rbac/api.ts +5 -2
- package/src/rbac/audit-enhanced.ts +6 -6
- package/src/rbac/audit.test.ts +60 -38
- package/src/rbac/audit.ts +8 -8
- package/src/rbac/cache-invalidation.ts +7 -4
- package/src/rbac/components/EnhancedNavigationMenu.tsx +11 -5
- package/src/rbac/components/NavigationGuard.tsx +7 -3
- package/src/rbac/components/NavigationProvider.tsx +6 -3
- package/src/rbac/components/PagePermissionGuard.tsx +28 -16
- package/src/rbac/components/PagePermissionProvider.tsx +4 -1
- package/src/rbac/components/PermissionEnforcer.tsx +9 -3
- package/src/rbac/components/RoleBasedRouter.tsx +3 -1
- package/src/rbac/components/SecureDataProvider.tsx +7 -3
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +87 -61
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +83 -33
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +36 -13
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +2 -2
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +22 -8
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +19 -6
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +43 -17
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +42 -17
- package/src/rbac/engine.ts +15 -7
- package/src/rbac/hooks/usePermissions.ts +7 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +2 -2
- package/src/rbac/hooks/useResolvedScope.ts +10 -7
- package/src/rbac/permissions.ts +5 -2
- package/src/rbac/security.test.ts +27 -16
- package/src/rbac/security.ts +5 -4
- package/src/services/AuthService.ts +22 -21
- package/src/services/EventService.ts +12 -12
- package/src/services/InactivityService.ts +5 -4
- package/src/services/OrganisationService.ts +26 -25
- package/src/services/__tests__/AuthService.test.ts +51 -19
- package/src/services/__tests__/EventService.test.ts +37 -5
- package/src/services/__tests__/InactivityService.test.ts +38 -4
- package/src/services/__tests__/OrganisationService.test.ts +3 -8
- package/src/services/base/BaseService.ts +3 -1
- package/src/theming/__tests__/runtime.test.ts +21 -12
- package/src/theming/parseEventColours.ts +5 -19
- package/src/theming/runtime.ts +8 -4
- package/src/types/validation.ts +2 -29
- package/src/utils/__tests__/appConfig.unit.test.ts +1 -1
- package/src/utils/__tests__/audit.unit.test.ts +1 -1
- package/src/utils/__tests__/auth-utils.unit.test.ts +1 -1
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +19 -19
- package/src/utils/__tests__/cn.unit.test.ts +1 -1
- package/src/utils/__tests__/debugLogger.test.ts +1 -1
- package/src/utils/__tests__/deviceFingerprint.unit.test.ts +1 -1
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +1 -1
- package/src/utils/__tests__/formatting.unit.test.ts +1 -1
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +1 -1
- package/src/utils/__tests__/logger.unit.test.ts +1 -1
- package/src/utils/__tests__/organisationContext.unit.test.ts +1 -1
- package/src/utils/__tests__/performanceBenchmark.test.ts +1 -1
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +1 -1
- package/src/utils/__tests__/permissionTypes.unit.test.ts +1 -1
- package/src/utils/__tests__/permissionUtils.unit.test.ts +1 -1
- package/src/utils/__tests__/sanitization.unit.test.ts +1 -1
- package/src/utils/__tests__/schemaUtils.unit.test.ts +1 -1
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +1 -1
- package/src/utils/__tests__/secureErrors.unit.test.ts +33 -15
- package/src/utils/__tests__/secureStorage.unit.test.ts +1 -1
- package/src/utils/__tests__/security.unit.test.ts +40 -18
- package/src/utils/__tests__/securityMonitor.unit.test.ts +1 -1
- package/src/utils/__tests__/sessionTracking.unit.test.ts +40 -29
- package/src/utils/__tests__/validationUtils.unit.test.ts +19 -6
- package/src/utils/{appIdResolver.test.ts → app/appIdResolver.test.ts} +28 -30
- package/src/utils/{appIdResolver.ts → app/appIdResolver.ts} +8 -5
- package/src/utils/{appNameResolver.test.ts → app/appNameResolver.test.ts} +1 -1
- package/src/utils/{appNameResolver.ts → app/appNameResolver.ts} +5 -1
- package/src/utils/{organisationContext.ts → context/organisationContext.ts} +6 -3
- package/src/utils/{sessionTracking.ts → context/sessionTracking.ts} +11 -12
- package/src/utils/{logger.ts → core/logger.ts} +4 -2
- package/src/utils/{deviceFingerprint.ts → device/deviceFingerprint.ts} +1 -1
- package/src/utils/{lazyLoad.tsx → dynamic/lazyLoad.tsx} +2 -2
- package/src/utils/{file-reference.test.ts → file-reference/__tests__/file-reference.test.ts} +5 -5
- package/src/utils/{file-reference.ts → file-reference/index.ts} +20 -38
- package/src/utils/index.ts +32 -54
- package/src/utils/{secureErrors.ts → security/secureErrors.ts} +6 -3
- package/src/utils/{security.ts → security/security.ts} +5 -2
- package/src/utils/storage/__tests__/helpers.unit.test.ts +1 -4
- package/src/utils/storage/helpers.ts +15 -8
- package/src/{components/Dialog/utils/__tests__/safeHtml.unit.test.ts → utils/validation/__tests__/htmlSanitization.unit.test.ts} +9 -15
- package/src/{validation → utils/validation}/csrf.ts +1 -1
- package/src/{components/Dialog/utils/safeHtml.ts → utils/validation/htmlSanitization.ts} +9 -10
- package/src/utils/validation/index.ts +79 -0
- package/src/utils/{sanitization.ts → validation/sanitization.ts} +71 -2
- package/src/{validation/schemaUtils.ts → utils/validation/schema.ts} +11 -6
- package/src/{validation → utils/validation}/sqlInjectionProtection.ts +2 -0
- package/src/utils/{validationUtils.ts → validation/validationUtils.ts} +4 -1
- package/src/validation/index.ts +3 -34
- package/dist/UnifiedAuthProvider-CQDZRJIS.js +0 -16
- package/dist/chunk-24MKLB7U.js +0 -81
- package/dist/chunk-24MKLB7U.js.map +0 -1
- package/dist/chunk-3CG5L6RN.js.map +0 -1
- package/dist/chunk-3DBFLLLU.js.map +0 -1
- package/dist/chunk-5F3NDPJV.js.map +0 -1
- package/dist/chunk-66C4BSAY.js.map +0 -1
- package/dist/chunk-BDZUMRBD.js.map +0 -1
- package/dist/chunk-BYXRHAIF.js.map +0 -1
- package/dist/chunk-CDQ3PX7L.js +0 -18
- package/dist/chunk-CDQ3PX7L.js.map +0 -1
- package/dist/chunk-CQZU6TFE.js.map +0 -1
- package/dist/chunk-F64FFPOZ.js.map +0 -1
- package/dist/chunk-GEVIB2UB.js.map +0 -1
- package/dist/chunk-GKHF54DI.js.map +0 -1
- package/dist/chunk-GVDR7WNV.js.map +0 -1
- package/dist/chunk-HMNOSGVA.js.map +0 -1
- package/dist/chunk-JCQZ6LA7.js.map +0 -1
- package/dist/chunk-M6DDYFUD.js.map +0 -1
- package/dist/chunk-O3NWNXDY.js.map +0 -1
- package/dist/chunk-PYUXFQJ3.js.map +0 -1
- package/dist/chunk-UJI6WSMD.js.map +0 -1
- package/dist/chunk-VZ5OR6HD.js.map +0 -1
- package/dist/chunk-WP5I5GLN.js.map +0 -1
- package/dist/chunk-ZYZCRSBD.js.map +0 -1
- package/src/components/Dialog/README.md +0 -804
- package/src/components/Form/FormErrorSummary.tsx +0 -113
- package/src/components/Form/FormFieldset.tsx +0 -127
- package/src/components/Form/FormLiveRegion.tsx +0 -198
- package/src/components/PasswordReset/PasswordResetForm.test.tsx +0 -597
- package/src/components/PasswordReset/PasswordResetForm.tsx +0 -201
- package/src/components/PublicLayout/PublicPageDebugger.tsx +0 -104
- package/src/components/PublicLayout/PublicPageDiagnostic.tsx +0 -162
- package/src/components/PublicLayout/__tests__/PublicPageDebugger.test.tsx +0 -185
- package/src/examples/CorrectPublicPageImplementation.tsx +0 -304
- package/src/examples/PublicEventPage.tsx +0 -287
- package/src/examples/PublicPageApp.tsx +0 -321
- package/src/examples/PublicPageUsageExample.tsx +0 -218
- package/src/utils/schemaUtils.ts +0 -37
- package/src/validation/__tests__/common.unit.test.ts +0 -101
- package/src/validation/__tests__/csrf.unit.test.ts +0 -365
- package/src/validation/__tests__/passwordSchema.unit.test.ts +0 -203
- package/src/validation/__tests__/sanitization.unit.test.ts +0 -250
- package/src/validation/__tests__/schemaUtils.unit.test.ts +0 -451
- package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +0 -462
- package/src/validation/__tests__/user.unit.test.ts +0 -440
- package/src/validation/sanitization.ts +0 -96
- /package/dist/{DataTable-A36PJG6N.js.map → DataTable-CYOHOX3O.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-CQDZRJIS.js.map → UnifiedAuthProvider-5E5TUNMS.js.map} +0 -0
- /package/dist/{api-TNIBJWLM.js.map → api-45XYYO2A.js.map} +0 -0
- /package/dist/{audit-T36HM7IM.js.map → audit-64X3VJXB.js.map} +0 -0
- /package/dist/{chunk-CTJRBUX2.js.map → chunk-2TWNJ46Y.js.map} +0 -0
- /package/dist/{chunk-ZV77RZMU.js.map → chunk-XARJS7CD.js.map} +0 -0
- /package/dist/{useInactivityTracker-MRUU55XI.js.map → useInactivityTracker-TO6ZOF35.js.map} +0 -0
- /package/examples/{public-pages → features/public-pages}/index.ts +0 -0
- /package/examples/{RBAC → features/rbac}/CompleteRBACExample.tsx +0 -0
- /package/examples/{RBAC → features/rbac}/EventBasedApp.tsx +0 -0
- /package/examples/{RBAC → features/rbac}/PermissionExample.tsx +0 -0
- /package/examples/{RBAC → features/rbac}/index.ts +0 -0
- /package/src/utils/{appConfig.ts → app/appConfig.ts} +0 -0
- /package/src/utils/{appNameResolver.simple.test.ts → app/appNameResolver.simple.test.ts} +0 -0
- /package/src/utils/{audit.ts → audit/audit.ts} +0 -0
- /package/src/utils/{organisationContext.test.ts → context/organisationContext.test.ts} +0 -0
- /package/src/utils/{cn.ts → core/cn.ts} +0 -0
- /package/src/utils/{debugLogger.ts → core/debugLogger.ts} +0 -0
- /package/src/utils/{dynamicUtils.ts → dynamic/dynamicUtils.ts} +0 -0
- /package/src/utils/{formatDate.test.ts → formatting/formatDate.test.ts} +0 -0
- /package/src/utils/{formatting.ts → formatting/formatting.ts} +0 -0
- /package/src/utils/{bundleAnalysis.ts → performance/bundleAnalysis.ts} +0 -0
- /package/src/utils/{performanceBenchmark.ts → performance/performanceBenchmark.ts} +0 -0
- /package/src/utils/{performanceBudgets.ts → performance/performanceBudgets.ts} +0 -0
- /package/src/utils/{permissionTypes.ts → permissions/permissionTypes.ts} +0 -0
- /package/src/utils/{permissionUtils.test.ts → permissions/permissionUtils.test.ts} +0 -0
- /package/src/utils/{permissionUtils.ts → permissions/permissionUtils.ts} +0 -0
- /package/src/utils/{auth-utils.ts → security/auth-utils.ts} +0 -0
- /package/src/utils/{secureDataAccess.test.ts → security/secureDataAccess.test.ts} +0 -0
- /package/src/utils/{secureDataAccess.ts → security/secureDataAccess.ts} +0 -0
- /package/src/utils/{secureStorage.ts → security/secureStorage.ts} +0 -0
- /package/src/utils/{securityMonitor.ts → security/securityMonitor.ts} +0 -0
- /package/src/{validation → utils/validation}/common.ts +0 -0
- /package/src/{validation → utils/validation}/passwordSchema.ts +0 -0
- /package/src/{validation → utils/validation}/user.ts +0 -0
- /package/src/utils/{validation.ts → validation/validation.ts} +0 -0
|
@@ -12,6 +12,7 @@ import { type SupabaseClient, type User, type Session, AuthError } from '@supaba
|
|
|
12
12
|
import type { SessionRestorationState } from '../types/auth';
|
|
13
13
|
import { BaseService } from './base/BaseService';
|
|
14
14
|
import { IAuthService, AuthResult } from './interfaces/IAuthService';
|
|
15
|
+
import { logger } from '../utils/core/logger';
|
|
15
16
|
|
|
16
17
|
export class AuthService extends BaseService implements IAuthService {
|
|
17
18
|
private user: User | null = null;
|
|
@@ -327,11 +328,11 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
327
328
|
};
|
|
328
329
|
this.authLoading = true;
|
|
329
330
|
this.restorationStartTime = Date.now();
|
|
330
|
-
|
|
331
|
+
logger.debug('AuthService', 'Starting session restoration at', this.restorationStartTime);
|
|
331
332
|
this.notify();
|
|
332
333
|
|
|
333
334
|
this.restorationTimeoutId = setTimeout(() => {
|
|
334
|
-
|
|
335
|
+
logger.warn('AuthService', 'Session restoration timed out after', this.restorationTimeoutMs, 'ms');
|
|
335
336
|
const timeoutError = new Error(`Session restoration timed out after ${this.restorationTimeoutMs}ms`);
|
|
336
337
|
timeoutError.name = 'SessionRestorationTimeoutError';
|
|
337
338
|
this.finishSessionRestoration(timeoutError);
|
|
@@ -356,9 +357,9 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
356
357
|
this.authLoading = false;
|
|
357
358
|
|
|
358
359
|
if (error) {
|
|
359
|
-
|
|
360
|
+
logger.warn('AuthService', 'Session restoration finished with error:', error, 'duration(ms):', duration ?? 'unknown');
|
|
360
361
|
} else {
|
|
361
|
-
|
|
362
|
+
logger.debug('AuthService', 'Session restoration completed successfully in', duration ?? 'unknown', 'ms');
|
|
362
363
|
}
|
|
363
364
|
|
|
364
365
|
this.notify();
|
|
@@ -382,7 +383,7 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
382
383
|
this.authStateSubscription = this.supabaseClient.auth.onAuthStateChange(
|
|
383
384
|
(event, session) => {
|
|
384
385
|
try {
|
|
385
|
-
|
|
386
|
+
logger.debug('AuthService', 'Auth state change event received:', event);
|
|
386
387
|
// Handle different auth events
|
|
387
388
|
if (event === 'SIGNED_OUT') {
|
|
388
389
|
this.session = null;
|
|
@@ -392,7 +393,7 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
392
393
|
// Automatic session tracking (non-blocking)
|
|
393
394
|
if (session?.user) {
|
|
394
395
|
this.trackSession('logout', session).catch(err => {
|
|
395
|
-
|
|
396
|
+
logger.warn('AuthService', 'Failed to track logout session:', err);
|
|
396
397
|
});
|
|
397
398
|
}
|
|
398
399
|
} else if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED') {
|
|
@@ -408,7 +409,7 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
408
409
|
// Only track on SIGNED_IN, not TOKEN_REFRESHED (to avoid duplicate login records)
|
|
409
410
|
if (event === 'SIGNED_IN' && session?.user) {
|
|
410
411
|
this.trackSession('login', session).catch(err => {
|
|
411
|
-
|
|
412
|
+
logger.warn('AuthService', 'Failed to track login session:', err);
|
|
412
413
|
});
|
|
413
414
|
}
|
|
414
415
|
} else if (event === 'INITIAL_SESSION') {
|
|
@@ -438,14 +439,14 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
438
439
|
this.authLoading = false;
|
|
439
440
|
this.notify();
|
|
440
441
|
} catch (error) {
|
|
441
|
-
|
|
442
|
+
logger.warn('AuthService', 'Error in auth state change handler:', error);
|
|
442
443
|
this.authLoading = false;
|
|
443
444
|
this.notify();
|
|
444
445
|
}
|
|
445
446
|
}
|
|
446
447
|
);
|
|
447
448
|
} catch (error) {
|
|
448
|
-
|
|
449
|
+
logger.error('AuthService', 'Failed to setup auth state listener:', error);
|
|
449
450
|
throw error; // Re-throw to propagate to the provider
|
|
450
451
|
}
|
|
451
452
|
}
|
|
@@ -453,7 +454,7 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
453
454
|
private async restoreSession(): Promise<void> {
|
|
454
455
|
if (!this.supabaseClient) {
|
|
455
456
|
const error = new Error('Supabase client not available during session restoration');
|
|
456
|
-
|
|
457
|
+
logger.error('AuthService', 'Unable to restore session:', error);
|
|
457
458
|
this.finishSessionRestoration(error);
|
|
458
459
|
return;
|
|
459
460
|
}
|
|
@@ -461,7 +462,7 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
461
462
|
this.startSessionRestoration();
|
|
462
463
|
|
|
463
464
|
try {
|
|
464
|
-
|
|
465
|
+
logger.debug('AuthService', 'Fetching existing session from Supabase');
|
|
465
466
|
let currentSession: Session | null = null;
|
|
466
467
|
let sessionError: AuthError | null = null;
|
|
467
468
|
|
|
@@ -471,14 +472,14 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
471
472
|
sessionError = error ?? null;
|
|
472
473
|
} catch (error) {
|
|
473
474
|
// Handle cases where getSession might not exist (mocked/test clients)
|
|
474
|
-
|
|
475
|
+
logger.debug('AuthService', 'getSession unavailable, treating as no active session');
|
|
475
476
|
currentSession = null;
|
|
476
477
|
sessionError = null;
|
|
477
478
|
}
|
|
478
479
|
|
|
479
480
|
if (sessionError) {
|
|
480
481
|
// Record error but continue to attempt getUser to satisfy edge cases
|
|
481
|
-
|
|
482
|
+
logger.debug('AuthService', 'getSession returned error, attempting to fetch user anyway');
|
|
482
483
|
this.authError = sessionError;
|
|
483
484
|
|
|
484
485
|
// Attempt getUser as fallback when getSession fails
|
|
@@ -497,7 +498,7 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
497
498
|
}
|
|
498
499
|
} catch (getUserError) {
|
|
499
500
|
// If getUser also fails, we've already recorded the sessionError
|
|
500
|
-
|
|
501
|
+
logger.debug('AuthService', 'getUser also failed:', getUserError);
|
|
501
502
|
}
|
|
502
503
|
}
|
|
503
504
|
|
|
@@ -509,7 +510,7 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
509
510
|
// Only skip getUser if we didn't already attempt it due to a sessionError
|
|
510
511
|
// Treat missing session as a normal cold-start state on public pages (e.g., login)
|
|
511
512
|
// Do not call getUser() which can raise AuthSessionMissingError and surface a noisy banner
|
|
512
|
-
|
|
513
|
+
logger.debug('AuthService', 'No active session found; treating as normal unauthenticated state');
|
|
513
514
|
this.session = null;
|
|
514
515
|
this.user = null;
|
|
515
516
|
this.authError = null;
|
|
@@ -521,7 +522,7 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
521
522
|
const restorationError = error instanceof Error
|
|
522
523
|
? error
|
|
523
524
|
: new Error('Unknown error during auth initialization');
|
|
524
|
-
|
|
525
|
+
logger.error('AuthService', 'Error during auth initialization:', restorationError);
|
|
525
526
|
if (restorationError instanceof AuthError) {
|
|
526
527
|
this.authError = restorationError;
|
|
527
528
|
}
|
|
@@ -580,13 +581,13 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
580
581
|
});
|
|
581
582
|
|
|
582
583
|
if (error) {
|
|
583
|
-
|
|
584
|
+
logger.warn('AuthService', `Failed to track ${sessionType} session:`, error);
|
|
584
585
|
} else {
|
|
585
|
-
|
|
586
|
+
logger.debug('AuthService', `Successfully tracked ${sessionType} session`);
|
|
586
587
|
}
|
|
587
588
|
} catch (error) {
|
|
588
589
|
// Log error but don't throw (non-blocking)
|
|
589
|
-
|
|
590
|
+
logger.warn('AuthService', `Error tracking ${sessionType} session:`, error);
|
|
590
591
|
}
|
|
591
592
|
}
|
|
592
593
|
|
|
@@ -596,7 +597,7 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
596
597
|
const handleError = (event: ErrorEvent) => {
|
|
597
598
|
if (event.error?.message?.includes('AuthSessionMissingError') ||
|
|
598
599
|
event.error?.message?.includes('Auth session missing')) {
|
|
599
|
-
|
|
600
|
+
logger.warn('AuthService', 'Suppressing AuthSessionMissingError during logout');
|
|
600
601
|
event.preventDefault();
|
|
601
602
|
return false;
|
|
602
603
|
}
|
|
@@ -605,7 +606,7 @@ export class AuthService extends BaseService implements IAuthService {
|
|
|
605
606
|
const handleUnhandledRejection = (event: PromiseRejectionEvent) => {
|
|
606
607
|
if (event.reason?.message?.includes('AuthSessionMissingError') ||
|
|
607
608
|
event.reason?.message?.includes('Auth session missing')) {
|
|
608
|
-
|
|
609
|
+
logger.warn('AuthService', 'Suppressing unhandled AuthSessionMissingError');
|
|
609
610
|
event.preventDefault();
|
|
610
611
|
return false;
|
|
611
612
|
}
|
|
@@ -13,8 +13,8 @@ import { BaseService } from './base/BaseService';
|
|
|
13
13
|
import { IEventService } from './interfaces/IEventService';
|
|
14
14
|
import { Event } from '../types/unified';
|
|
15
15
|
import { Organisation } from '../types/organisation';
|
|
16
|
-
import {
|
|
17
|
-
import { secureStorage } from '../utils/secureStorage';
|
|
16
|
+
import { logger } from '../utils/core/logger';
|
|
17
|
+
import { secureStorage } from '../utils/security/secureStorage';
|
|
18
18
|
|
|
19
19
|
export class EventService extends BaseService implements IEventService {
|
|
20
20
|
private events: Event[] = [];
|
|
@@ -134,7 +134,7 @@ export class EventService extends BaseService implements IEventService {
|
|
|
134
134
|
// SECURITY: Validate event belongs to current organisation
|
|
135
135
|
try {
|
|
136
136
|
if (this.selectedOrganisation && event.organisation_id !== this.selectedOrganisation.id) {
|
|
137
|
-
|
|
137
|
+
logger.error('EventService', 'Event organisation_id does not match selected organisation', {
|
|
138
138
|
eventOrganisationId: event.organisation_id,
|
|
139
139
|
selectedOrganisationId: this.selectedOrganisation.id,
|
|
140
140
|
eventName: event.event_name
|
|
@@ -142,14 +142,14 @@ export class EventService extends BaseService implements IEventService {
|
|
|
142
142
|
return;
|
|
143
143
|
}
|
|
144
144
|
} catch (error) {
|
|
145
|
-
|
|
145
|
+
logger.error('EventService', 'Error during event validation:', error);
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
this.selectedEvent = event;
|
|
149
149
|
this.setSelectedEventId?.(event.event_id);
|
|
150
150
|
// Persist asynchronously (don't await to avoid blocking)
|
|
151
151
|
this.persistEventSelection(event.event_id).catch(error => {
|
|
152
|
-
|
|
152
|
+
logger.warn('EventService', 'Failed to persist event selection:', error);
|
|
153
153
|
});
|
|
154
154
|
// Reset the user cleared flag when selecting an event
|
|
155
155
|
this.userClearedEventRef = false;
|
|
@@ -158,7 +158,7 @@ export class EventService extends BaseService implements IEventService {
|
|
|
158
158
|
this.setSelectedEventId?.(null);
|
|
159
159
|
// Clear from secure storage (don't await to avoid blocking)
|
|
160
160
|
this.clearEventSelection().catch(error => {
|
|
161
|
-
|
|
161
|
+
logger.warn('EventService', 'Failed to clear event selection:', error);
|
|
162
162
|
});
|
|
163
163
|
// Reset the auto-selection flag when clearing the event
|
|
164
164
|
this.hasAutoSelectedRef = false;
|
|
@@ -205,7 +205,7 @@ export class EventService extends BaseService implements IEventService {
|
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
} catch (error) {
|
|
208
|
-
|
|
208
|
+
logger.warn('EventService', 'Failed to load persisted event:', error);
|
|
209
209
|
}
|
|
210
210
|
return false;
|
|
211
211
|
}
|
|
@@ -232,7 +232,7 @@ export class EventService extends BaseService implements IEventService {
|
|
|
232
232
|
// Store with encryption using secureStorage
|
|
233
233
|
await secureStorage.setItem(storageKey, eventId, { encrypt: true });
|
|
234
234
|
} catch (error) {
|
|
235
|
-
|
|
235
|
+
logger.warn('EventService', 'Failed to persist event selection:', error);
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
|
|
@@ -248,7 +248,7 @@ export class EventService extends BaseService implements IEventService {
|
|
|
248
248
|
this.selectedEvent = null;
|
|
249
249
|
this.setSelectedEventId?.(null);
|
|
250
250
|
} catch (error) {
|
|
251
|
-
|
|
251
|
+
logger.warn('EventService', 'Failed to clear event selection:', error);
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
254
|
|
|
@@ -262,7 +262,7 @@ export class EventService extends BaseService implements IEventService {
|
|
|
262
262
|
const storageKey = this.getStorageKey(userId);
|
|
263
263
|
await secureStorage.removeItem(storageKey);
|
|
264
264
|
} catch (error) {
|
|
265
|
-
|
|
265
|
+
logger.warn('EventService', 'Failed to clear event selection for user:', error);
|
|
266
266
|
}
|
|
267
267
|
}
|
|
268
268
|
|
|
@@ -292,7 +292,7 @@ export class EventService extends BaseService implements IEventService {
|
|
|
292
292
|
localStorage.removeItem('_sec_pace-core-selected-event');
|
|
293
293
|
}
|
|
294
294
|
} catch (error) {
|
|
295
|
-
|
|
295
|
+
logger.warn('EventService', 'Failed to clean up old storage keys:', error);
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
// Load persisted event during initialization (don't skip)
|
|
@@ -399,7 +399,7 @@ export class EventService extends BaseService implements IEventService {
|
|
|
399
399
|
}
|
|
400
400
|
}
|
|
401
401
|
} catch (err) {
|
|
402
|
-
|
|
402
|
+
logger.error('EventService', 'Error fetching events:', err);
|
|
403
403
|
const _error = err instanceof Error ? err : new Error('Unknown error occurred');
|
|
404
404
|
|
|
405
405
|
if (isMounted) {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { BaseService } from './base/BaseService';
|
|
12
12
|
import { IInactivityService } from './interfaces/IInactivityService';
|
|
13
|
+
import { logger } from '../utils/core/logger';
|
|
13
14
|
|
|
14
15
|
export class InactivityService extends BaseService implements IInactivityService {
|
|
15
16
|
private _showInactivityWarning = false;
|
|
@@ -169,7 +170,7 @@ export class InactivityService extends BaseService implements IInactivityService
|
|
|
169
170
|
await this.supabaseClient.auth.signOut();
|
|
170
171
|
}
|
|
171
172
|
} catch (error: any) {
|
|
172
|
-
|
|
173
|
+
logger.error('InactivityService', 'Error during idle logout:', error);
|
|
173
174
|
}
|
|
174
175
|
|
|
175
176
|
// Call app callback for navigation/redirect
|
|
@@ -195,7 +196,7 @@ export class InactivityService extends BaseService implements IInactivityService
|
|
|
195
196
|
await this.supabaseClient.auth.signOut();
|
|
196
197
|
}
|
|
197
198
|
} catch (error: any) {
|
|
198
|
-
|
|
199
|
+
logger.error('InactivityService', 'Error during manual sign out:', error);
|
|
199
200
|
}
|
|
200
201
|
|
|
201
202
|
// Call app callback for navigation/redirect
|
|
@@ -229,7 +230,7 @@ export class InactivityService extends BaseService implements IInactivityService
|
|
|
229
230
|
const isProduction = import.meta.env.MODE === 'production';
|
|
230
231
|
|
|
231
232
|
if (isProduction) {
|
|
232
|
-
|
|
233
|
+
logger.warn('InactivityService', 'Inactivity feature enabled in production');
|
|
233
234
|
}
|
|
234
235
|
}
|
|
235
236
|
}
|
|
@@ -284,7 +285,7 @@ export class InactivityService extends BaseService implements IInactivityService
|
|
|
284
285
|
// Set up event handlers
|
|
285
286
|
this.setupEventHandlers();
|
|
286
287
|
} catch (error) {
|
|
287
|
-
|
|
288
|
+
logger.error('InactivityService', 'Failed to setup inactivity tracker:', error);
|
|
288
289
|
}
|
|
289
290
|
}
|
|
290
291
|
|
|
@@ -17,7 +17,8 @@ import type {
|
|
|
17
17
|
OrganisationSecurityError,
|
|
18
18
|
OrganisationHierarchy
|
|
19
19
|
} from '../types/organisation';
|
|
20
|
-
import { setOrganisationContext } from '../utils/organisationContext';
|
|
20
|
+
import { setOrganisationContext } from '../utils/context/organisationContext';
|
|
21
|
+
import { logger } from '../utils/core/logger';
|
|
21
22
|
|
|
22
23
|
export class OrganisationService extends BaseService implements IOrganisationService {
|
|
23
24
|
private _selectedOrganisation: Organisation | null = null;
|
|
@@ -254,14 +255,14 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
254
255
|
|
|
255
256
|
private async setDatabaseOrganisationContext(organisation: Organisation): Promise<void> {
|
|
256
257
|
if (!this.supabaseClient || !this.session) {
|
|
257
|
-
|
|
258
|
+
logger.warn('OrganisationService', 'No Supabase client or session available for setting organisation context');
|
|
258
259
|
this._isContextReady = false;
|
|
259
260
|
this.notify();
|
|
260
261
|
return;
|
|
261
262
|
}
|
|
262
263
|
|
|
263
264
|
try {
|
|
264
|
-
|
|
265
|
+
logger.debug('OrganisationService', 'Setting database organisation context for:', organisation.id);
|
|
265
266
|
|
|
266
267
|
// Add timeout to prevent hanging
|
|
267
268
|
const timeoutPromise = new Promise((_, reject) => {
|
|
@@ -272,11 +273,11 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
272
273
|
|
|
273
274
|
await Promise.race([contextPromise, timeoutPromise]);
|
|
274
275
|
|
|
275
|
-
|
|
276
|
+
logger.debug('OrganisationService', 'Database organisation context set successfully');
|
|
276
277
|
this._isContextReady = true;
|
|
277
278
|
this.notify();
|
|
278
279
|
} catch (error) {
|
|
279
|
-
|
|
280
|
+
logger.error('OrganisationService', 'Failed to set database organisation context:', error);
|
|
280
281
|
// Set context ready to true anyway - this is a non-critical operation
|
|
281
282
|
// The app should still work without database context
|
|
282
283
|
this._isContextReady = true;
|
|
@@ -288,7 +289,7 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
288
289
|
private async loadUserOrganisations(): Promise<void> {
|
|
289
290
|
// Add call tracking to detect race conditions
|
|
290
291
|
const callId = Math.random().toString(36).substr(2, 9);
|
|
291
|
-
|
|
292
|
+
logger.debug('OrganisationService', `Starting loadUserOrganisations call ${callId}`);
|
|
292
293
|
|
|
293
294
|
if (!this.user || !this.session || !this.supabaseClient) {
|
|
294
295
|
// Clear state when no user, session, or supabase client
|
|
@@ -303,7 +304,7 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
303
304
|
|
|
304
305
|
// Additional check to prevent loading during auth state changes
|
|
305
306
|
if (this.isLoadingRef) {
|
|
306
|
-
|
|
307
|
+
logger.debug("OrganisationService", "Already loading, skipping duplicate load");
|
|
307
308
|
// Ensure loading state is correct
|
|
308
309
|
this._isLoading = true;
|
|
309
310
|
this.notify();
|
|
@@ -313,7 +314,7 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
313
314
|
// Prevent rapid retries - minimum 2 seconds between attempts
|
|
314
315
|
const now = Date.now();
|
|
315
316
|
if (now - this.lastLoadTimeRef < 2000) {
|
|
316
|
-
|
|
317
|
+
logger.debug("OrganisationService", "Too soon since last load, skipping");
|
|
317
318
|
// Ensure loading state is correct
|
|
318
319
|
if (this._organisations.length > 0 || this._selectedOrganisation) {
|
|
319
320
|
this._isLoading = false;
|
|
@@ -340,7 +341,7 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
340
341
|
this.notify();
|
|
341
342
|
|
|
342
343
|
try {
|
|
343
|
-
|
|
344
|
+
logger.debug("OrganisationService", "Supabase client ready:", {
|
|
344
345
|
isConnected: !!this.supabaseClient,
|
|
345
346
|
hasAuth: !!this.supabaseClient.auth,
|
|
346
347
|
hasRpc: !!this.supabaseClient.rpc
|
|
@@ -350,7 +351,7 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
350
351
|
// Only get actual members (org_admin, leader, member) - exclude supporters
|
|
351
352
|
let memberships, membershipError;
|
|
352
353
|
try {
|
|
353
|
-
|
|
354
|
+
logger.debug("OrganisationService", "Making RPC call to data_user_organisation_roles_get...");
|
|
354
355
|
|
|
355
356
|
// Add timeout and abort signal to prevent hanging RPC calls
|
|
356
357
|
const timeoutPromise = new Promise((_, reject) => {
|
|
@@ -373,7 +374,7 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
373
374
|
|
|
374
375
|
const result = await Promise.race([rpcPromise, timeoutPromise]) as any;
|
|
375
376
|
|
|
376
|
-
|
|
377
|
+
logger.debug("OrganisationService", "RPC call completed:", {
|
|
377
378
|
hasData: !!result.data,
|
|
378
379
|
hasError: !!result.error,
|
|
379
380
|
dataLength: result.data?.length || 0,
|
|
@@ -390,11 +391,11 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
390
391
|
}
|
|
391
392
|
|
|
392
393
|
if (membershipError) {
|
|
393
|
-
|
|
394
|
+
logger.error("OrganisationService", "Error loading memberships:", membershipError);
|
|
394
395
|
|
|
395
396
|
// If RPC fails with timeout, try direct database query as fallback
|
|
396
397
|
if (membershipError.message?.includes('timeout')) {
|
|
397
|
-
|
|
398
|
+
logger.debug("OrganisationService", "RPC timed out, trying direct database query as fallback...");
|
|
398
399
|
try {
|
|
399
400
|
// Check if request was aborted before making fallback query
|
|
400
401
|
if (abortSignal.aborted) {
|
|
@@ -434,15 +435,15 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
434
435
|
.in('role', ['org_admin', 'leader', 'member']);
|
|
435
436
|
|
|
436
437
|
if (fallbackError) {
|
|
437
|
-
|
|
438
|
+
logger.error("OrganisationService", "Fallback query also failed:", fallbackError);
|
|
438
439
|
throw membershipError; // Throw original error
|
|
439
440
|
}
|
|
440
441
|
|
|
441
|
-
|
|
442
|
+
logger.debug("OrganisationService", "Fallback query successful, got", fallbackData?.length || 0, "memberships");
|
|
442
443
|
memberships = fallbackData || [];
|
|
443
444
|
membershipError = null;
|
|
444
445
|
} catch (fallbackErr) {
|
|
445
|
-
|
|
446
|
+
logger.error("OrganisationService", "Fallback query failed:", fallbackErr);
|
|
446
447
|
throw membershipError; // Throw original error
|
|
447
448
|
}
|
|
448
449
|
} else {
|
|
@@ -460,24 +461,24 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
460
461
|
.filter((id: string) => {
|
|
461
462
|
// Better validation to prevent empty string UUID errors
|
|
462
463
|
if (!id || typeof id !== 'string') {
|
|
463
|
-
|
|
464
|
+
logger.warn("OrganisationService", "Invalid organisation ID (not string):", id);
|
|
464
465
|
return false;
|
|
465
466
|
}
|
|
466
467
|
const trimmedId = id.trim();
|
|
467
468
|
if (trimmedId === '') {
|
|
468
|
-
|
|
469
|
+
logger.warn("OrganisationService", "Empty organisation ID found");
|
|
469
470
|
return false;
|
|
470
471
|
}
|
|
471
472
|
// Validate UUID format
|
|
472
473
|
const isValidUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(trimmedId);
|
|
473
474
|
if (!isValidUuid) {
|
|
474
|
-
|
|
475
|
+
logger.warn("OrganisationService", "Invalid UUID format:", trimmedId);
|
|
475
476
|
}
|
|
476
477
|
return isValidUuid;
|
|
477
478
|
});
|
|
478
479
|
|
|
479
480
|
if (organisationIds.length === 0) {
|
|
480
|
-
|
|
481
|
+
logger.warn("OrganisationService", "No valid organisation IDs found in memberships:", memberships);
|
|
481
482
|
throw new Error('No valid organisation IDs found in memberships') as OrganisationSecurityError;
|
|
482
483
|
}
|
|
483
484
|
|
|
@@ -491,7 +492,7 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
491
492
|
.select('id, name, display_name, subscription_tier, settings, is_active, parent_id, created_at, updated_at');
|
|
492
493
|
|
|
493
494
|
if (orgError) {
|
|
494
|
-
|
|
495
|
+
logger.error("OrganisationService", "Error loading organisations:", orgError);
|
|
495
496
|
throw orgError;
|
|
496
497
|
}
|
|
497
498
|
|
|
@@ -534,16 +535,16 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
534
535
|
if (validPersistedOrg) {
|
|
535
536
|
initialOrg = validPersistedOrg;
|
|
536
537
|
} else {
|
|
537
|
-
|
|
538
|
+
logger.warn("OrganisationService", "Persisted organisation not found in active orgs, clearing cache");
|
|
538
539
|
localStorage.removeItem('pace-core-selected-organisation');
|
|
539
540
|
}
|
|
540
541
|
} else {
|
|
541
|
-
|
|
542
|
+
logger.warn("OrganisationService", "Invalid persisted organisation ID, clearing cache");
|
|
542
543
|
localStorage.removeItem('pace-core-selected-organisation');
|
|
543
544
|
}
|
|
544
545
|
}
|
|
545
546
|
} catch (storageError) {
|
|
546
|
-
|
|
547
|
+
logger.warn("OrganisationService", "Failed to restore persisted organisation:", storageError);
|
|
547
548
|
// Clear potentially corrupted cache
|
|
548
549
|
localStorage.removeItem('pace-core-selected-organisation');
|
|
549
550
|
}
|
|
@@ -581,7 +582,7 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
581
582
|
this.hasFailedRef = false;
|
|
582
583
|
|
|
583
584
|
} catch (err) {
|
|
584
|
-
|
|
585
|
+
logger.error("OrganisationService", "Failed to load organisations:", err);
|
|
585
586
|
this._error = err as Error;
|
|
586
587
|
// Increment retry count on error
|
|
587
588
|
this.retryCount = this.retryCount + 1;
|
|
@@ -12,6 +12,17 @@ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
|
|
|
12
12
|
import { AuthService } from '../AuthService';
|
|
13
13
|
import { AuthError } from '@supabase/supabase-js';
|
|
14
14
|
|
|
15
|
+
// Don't mock the logger - it now works in test mode
|
|
16
|
+
// We'll spy on the Logger class methods in beforeEach to verify calls
|
|
17
|
+
import { Logger } from '../../utils/core/logger';
|
|
18
|
+
|
|
19
|
+
let mockLoggerFunctions: {
|
|
20
|
+
debug: ReturnType<typeof vi.spyOn>;
|
|
21
|
+
error: ReturnType<typeof vi.spyOn>;
|
|
22
|
+
warn: ReturnType<typeof vi.spyOn>;
|
|
23
|
+
info: ReturnType<typeof vi.spyOn>;
|
|
24
|
+
};
|
|
25
|
+
|
|
15
26
|
// Mock Supabase client
|
|
16
27
|
const createMockSupabaseClient = () => ({
|
|
17
28
|
auth: {
|
|
@@ -32,12 +43,25 @@ describe('AuthService', () => {
|
|
|
32
43
|
let authService: AuthService;
|
|
33
44
|
|
|
34
45
|
beforeEach(() => {
|
|
46
|
+
// Spy on Logger methods to verify calls (logger now works in test mode)
|
|
47
|
+
mockLoggerFunctions = {
|
|
48
|
+
debug: vi.spyOn(Logger, 'debug'),
|
|
49
|
+
error: vi.spyOn(Logger, 'error'),
|
|
50
|
+
warn: vi.spyOn(Logger, 'warn'),
|
|
51
|
+
info: vi.spyOn(Logger, 'info'),
|
|
52
|
+
};
|
|
53
|
+
|
|
35
54
|
mockSupabase = createMockSupabaseClient();
|
|
36
55
|
authService = new AuthService(mockSupabase as any);
|
|
37
56
|
});
|
|
38
57
|
|
|
39
58
|
afterEach(() => {
|
|
40
59
|
authService.cleanup();
|
|
60
|
+
// Restore spies
|
|
61
|
+
mockLoggerFunctions.debug.mockRestore();
|
|
62
|
+
mockLoggerFunctions.error.mockRestore();
|
|
63
|
+
mockLoggerFunctions.warn.mockRestore();
|
|
64
|
+
mockLoggerFunctions.info.mockRestore();
|
|
41
65
|
vi.clearAllMocks();
|
|
42
66
|
});
|
|
43
67
|
|
|
@@ -760,9 +784,9 @@ describe('AuthService', () => {
|
|
|
760
784
|
it('should handle tracking errors gracefully without breaking authentication', async () => {
|
|
761
785
|
const mockUser = { id: 'user-123', email: 'test@example.com' };
|
|
762
786
|
const mockSession = { access_token: 'token', user: mockUser };
|
|
763
|
-
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
764
787
|
|
|
765
|
-
|
|
788
|
+
// Mock rpc to reject (this will trigger the catch block in trackSession)
|
|
789
|
+
(mockSupabase as any).rpc = vi.fn().mockRejectedValue(new Error('Tracking failed'));
|
|
766
790
|
|
|
767
791
|
let authStateCallback: any;
|
|
768
792
|
mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
|
|
@@ -777,19 +801,29 @@ describe('AuthService', () => {
|
|
|
777
801
|
if (authStateCallback) {
|
|
778
802
|
authStateCallback('SIGNED_IN', mockSession);
|
|
779
803
|
|
|
780
|
-
// Wait
|
|
781
|
-
|
|
804
|
+
// Wait for async tracking to complete (trackSession is async)
|
|
805
|
+
// The catch block in trackSession will log the error
|
|
806
|
+
// Note: The logger may be called in the .catch() handler with "Failed to track"
|
|
807
|
+
// or in the catch block with "Error tracking"
|
|
808
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
782
809
|
|
|
783
|
-
//
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
810
|
+
// Check for either error message pattern
|
|
811
|
+
const warnCalls = mockLoggerFunctions.warn.mock.calls;
|
|
812
|
+
const hasErrorTracking = warnCalls.some(call =>
|
|
813
|
+
call[0] === 'AuthService' &&
|
|
814
|
+
typeof call[1] === 'string' &&
|
|
815
|
+
call[1].includes('Error tracking')
|
|
788
816
|
);
|
|
817
|
+
const hasFailedToTrack = warnCalls.some(call =>
|
|
818
|
+
call[0] === 'AuthService' &&
|
|
819
|
+
typeof call[1] === 'string' &&
|
|
820
|
+
call[1].includes('Failed to track')
|
|
821
|
+
);
|
|
822
|
+
|
|
823
|
+
expect(hasErrorTracking || hasFailedToTrack).toBe(true);
|
|
824
|
+
expect(mockLoggerFunctions.warn).toHaveBeenCalled();
|
|
789
825
|
expect(authServiceWithApp.isAuthenticated()).toBe(true);
|
|
790
826
|
}
|
|
791
|
-
|
|
792
|
-
consoleWarnSpy.mockRestore();
|
|
793
827
|
authServiceWithApp.cleanup();
|
|
794
828
|
});
|
|
795
829
|
|
|
@@ -1115,7 +1149,7 @@ describe('AuthService', () => {
|
|
|
1115
1149
|
});
|
|
1116
1150
|
|
|
1117
1151
|
it('should handle tracking when RPC fails', async () => {
|
|
1118
|
-
|
|
1152
|
+
vi.clearAllMocks();
|
|
1119
1153
|
(mockSupabase as any).rpc = vi.fn().mockResolvedValue({
|
|
1120
1154
|
error: { message: 'RPC failed' }
|
|
1121
1155
|
});
|
|
@@ -1147,16 +1181,14 @@ describe('AuthService', () => {
|
|
|
1147
1181
|
if (authStateCallback) {
|
|
1148
1182
|
authStateCallback('SIGNED_IN', mockSession);
|
|
1149
1183
|
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
expect.stringContaining('Failed to track
|
|
1184
|
+
// Wait for async tracking to complete
|
|
1185
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
1186
|
+
expect(mockLoggerFunctions.warn).toHaveBeenCalledWith(
|
|
1187
|
+
'AuthService',
|
|
1188
|
+
expect.stringContaining('Failed to track'),
|
|
1155
1189
|
expect.anything()
|
|
1156
1190
|
);
|
|
1157
1191
|
}
|
|
1158
|
-
|
|
1159
|
-
consoleWarnSpy.mockRestore();
|
|
1160
1192
|
authServiceWithApp.cleanup();
|
|
1161
1193
|
});
|
|
1162
1194
|
|