@jmruthers/pace-core 0.2.7 → 0.5.1
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-EEUDXPE5.js → DataTable-GX3XERFJ.js} +8 -4
- package/dist/{DataTable-C1AEm9Cx.d.ts → DataTable-ltTFXHS3.d.ts} +3 -1
- package/dist/{chunk-VYG4AXYW.js → chunk-5EL3KHOQ.js} +2 -2
- package/dist/{chunk-ETEJVKYK.js → chunk-6CR3MRZN.js} +1426 -62
- package/dist/chunk-6CR3MRZN.js.map +1 -0
- package/dist/chunk-AUE24LVR.js +268 -0
- package/dist/chunk-AUE24LVR.js.map +1 -0
- package/dist/chunk-COBPIXXQ.js +379 -0
- package/dist/chunk-COBPIXXQ.js.map +1 -0
- package/dist/{chunk-EWKPTNPO.js → chunk-GSNM5D6H.js} +388 -86
- package/dist/chunk-GSNM5D6H.js.map +1 -0
- package/dist/{chunk-2V3Y6YBC.js → chunk-OEGRKULD.js} +1 -42
- package/dist/chunk-OEGRKULD.js.map +1 -0
- package/dist/chunk-OYRY44Q2.js +62 -0
- package/dist/chunk-OYRY44Q2.js.map +1 -0
- package/dist/{chunk-RRUYHORU.js → chunk-T3XIA4AJ.js} +297 -433
- package/dist/chunk-T3XIA4AJ.js.map +1 -0
- package/dist/{chunk-HEMJ4SUJ.js → chunk-TGDCLPP2.js} +11 -7
- package/dist/{chunk-HEMJ4SUJ.js.map → chunk-TGDCLPP2.js.map} +1 -1
- package/dist/{chunk-HNDFPXUU.js → chunk-U6JDHVC2.js} +6 -4
- package/dist/{chunk-HNDFPXUU.js.map → chunk-U6JDHVC2.js.map} +1 -1
- package/dist/{chunk-TIVL4UQ7.js → chunk-XJK2J4N6.js} +6 -4
- package/dist/{chunk-TIVL4UQ7.js.map → chunk-XJK2J4N6.js.map} +1 -1
- package/dist/components.d.ts +2 -2
- package/dist/components.js +21 -20
- package/dist/components.js.map +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +7 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.js +26 -25
- package/dist/index.js.map +1 -1
- package/dist/providers.js +8 -7
- package/dist/rbac/index.d.ts +806 -806
- package/dist/rbac/index.js +937 -1179
- package/dist/rbac/index.js.map +1 -1
- package/dist/{types-DiRQsGJs.d.ts → types-BRDU7N6w.d.ts} +12 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +6 -6
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.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/DataTableAction.md +21 -8
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +46 -33
- package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
- package/docs/api/interfaces/EmptyStateConfig.md +5 -5
- package/docs/api/interfaces/EventContextType.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +1 -1
- package/docs/api/interfaces/EventProviderProps.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.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/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +2 -2
- 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 +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- 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/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/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- 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/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +3 -3
- package/package.json +5 -2
- package/src/__tests__/REBUILD_PLAN.md +223 -0
- package/src/__tests__/TESTING_GUIDELINES.md +341 -0
- package/src/__tests__/fixtures/mocks.ts +93 -0
- package/src/__tests__/helpers/component-test-utils.tsx +145 -0
- package/src/__tests__/helpers/test-utils.tsx +117 -0
- package/src/__tests__/integration/UserProfile.test.tsx +128 -0
- package/src/__tests__/setup.ts +37 -225
- package/src/__tests__/templates/component.test.template.tsx +97 -75
- package/src/__tests__/templates/hook.test.template.ts +173 -0
- package/src/__tests__/types/test.types.ts +106 -0
- package/src/components/Alert/Alert.test.tsx +496 -0
- package/src/components/Avatar/Avatar.test.tsx +484 -0
- package/src/components/Button/Button.test.tsx +662 -0
- package/src/components/Card/Card.test.tsx +593 -0
- package/src/components/Checkbox/Checkbox.test.tsx +461 -0
- package/src/components/DataTable/DataTable.tsx +9 -1
- package/src/components/DataTable/components/AccessDeniedPage.tsx +168 -0
- package/src/components/DataTable/components/ActionButtons.tsx +18 -1
- package/src/components/DataTable/components/DataTableCore.tsx +97 -11
- package/src/components/DataTable/components/DataTableToolbar.tsx +22 -10
- package/src/components/DataTable/components/UnifiedTableBody.tsx +33 -4
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +1 -0
- package/src/components/DataTable/examples/HierarchicalExample.tsx +3 -0
- package/src/components/DataTable/examples/InitialPageSizeExample.tsx +3 -0
- package/src/components/DataTable/examples/PerformanceExample.tsx +3 -0
- package/src/components/DataTable/types.ts +39 -1
- package/src/components/Dialog/Dialog.test.tsx +1139 -0
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +752 -0
- package/src/components/FileUpload/FileUpload.test.tsx +665 -0
- package/src/hooks/useCounter.test.ts +135 -0
- package/src/rbac/index.ts +3 -3
- package/dist/chunk-2V3Y6YBC.js.map +0 -1
- package/dist/chunk-BEZRLNK3.js +0 -1744
- package/dist/chunk-BEZRLNK3.js.map +0 -1
- package/dist/chunk-ETEJVKYK.js.map +0 -1
- package/dist/chunk-EWKPTNPO.js.map +0 -1
- package/dist/chunk-OHXGNT3K.js +0 -21
- package/dist/chunk-OHXGNT3K.js.map +0 -1
- package/dist/chunk-RRUYHORU.js.map +0 -1
- package/src/__tests__/README.md +0 -404
- package/src/__tests__/debug-provider.unit.test.tsx +0 -67
- package/src/__tests__/e2e/workflows.test.tsx +0 -373
- package/src/__tests__/hybridPermissions.unit.test.tsx +0 -474
- package/src/__tests__/index.integration.test.ts +0 -491
- package/src/__tests__/mocks/MockAuthProvider-standalone.tsx +0 -47
- package/src/__tests__/mocks/MockAuthProvider.tsx +0 -63
- package/src/__tests__/mocks/enhancedSupabaseMock.ts +0 -252
- package/src/__tests__/mocks/index.test.ts +0 -23
- package/src/__tests__/mocks/index.ts +0 -16
- package/src/__tests__/mocks/mockAuth.ts +0 -155
- package/src/__tests__/mocks/mockSupabase.ts +0 -83
- package/src/__tests__/mocks/mockSupabaseClient.ts +0 -63
- package/src/__tests__/mocks/providers.tsx +0 -22
- package/src/__tests__/patterns/__tests__/testPatterns.test.ts +0 -394
- package/src/__tests__/patterns/testPatterns.ts +0 -124
- package/src/__tests__/performance/componentPerformance.performance.test.ts +0 -27
- package/src/__tests__/performance/index.ts +0 -24
- package/src/__tests__/performance/performanceValidation.performance.test.ts +0 -15
- package/src/__tests__/security/security.unit.test.tsx +0 -7
- package/src/__tests__/security/securityValidation.security.test.tsx +0 -153
- package/src/__tests__/setupTests.d.ts +0 -1
- package/src/__tests__/shared/componentTestUtils.tsx +0 -475
- package/src/__tests__/shared/errorHandlingTestUtils.ts +0 -107
- package/src/__tests__/shared/index.ts +0 -81
- package/src/__tests__/shared/integrationTestUtils.tsx +0 -375
- package/src/__tests__/shared/performanceTestUtils.tsx +0 -476
- package/src/__tests__/shared/testUtils.optimized.tsx +0 -685
- package/src/__tests__/simple.test.tsx +0 -20
- package/src/__tests__/test-utils/dataFactories.ts +0 -60
- package/src/__tests__/test-utils/index.ts +0 -6
- package/src/__tests__/typeSafety.unit.test.ts +0 -65
- package/src/__tests__/unifiedAuth.unit.test.tsx +0 -151
- package/src/__tests__/utils/accessibilityHelpers.ts +0 -254
- package/src/__tests__/utils/assertions.ts +0 -50
- package/src/__tests__/utils/deterministicHelpers.ts +0 -31
- package/src/__tests__/utils/edgeCaseConfig.test.ts +0 -75
- package/src/__tests__/utils/edgeCaseConfig.ts +0 -98
- package/src/__tests__/utils/mockHelpers.ts +0 -149
- package/src/__tests__/utils/mockLoader.ts +0 -101
- package/src/__tests__/utils/performanceHelpers.ts +0 -55
- package/src/__tests__/utils/performanceTestHelpers.ts +0 -68
- package/src/__tests__/utils/testDataFactories.ts +0 -28
- package/src/__tests__/utils/testIsolation.ts +0 -67
- package/src/__tests__/utils/visualTestHelpers.ts +0 -20
- package/src/__tests__/visual/__snapshots__/componentSnapshots.visual.test.tsx.snap +0 -68
- package/src/__tests__/visual/__snapshots__/componentVisuals.visual.test.tsx.snap +0 -14
- package/src/__tests__/visual/__snapshots__/visualRegression.test.tsx.snap +0 -217
- package/src/__tests__/visual/__snapshots__/visualRegression.visual.test.tsx.snap +0 -24
- package/src/__tests__/visual/componentSnapshots.visual.test.tsx +0 -33
- package/src/__tests__/visual/componentVisuals.visual.test.tsx +0 -12
- package/src/__tests__/visual/visualRegression.visual.test.tsx +0 -20
- package/src/components/Alert/__tests__/Alert.unit.test.tsx +0 -381
- package/src/components/Avatar/__tests__/Avatar.unit.test.tsx +0 -232
- package/src/components/Button/__tests__/Button.accessibility.test.tsx +0 -131
- package/src/components/Button/__tests__/Button.comprehensive.test.tsx +0 -721
- package/src/components/Button/__tests__/Button.unit.test.tsx +0 -189
- package/src/components/Button/__tests__/EventSelector.integration.test.tsx +0 -285
- package/src/components/Card/__tests__/Card.accessibility.test.tsx +0 -394
- package/src/components/Card/__tests__/Card.comprehensive.test.tsx +0 -599
- package/src/components/Card/__tests__/Card.integration.test.tsx +0 -673
- package/src/components/Card/__tests__/Card.performance.test.tsx +0 -546
- package/src/components/Card/__tests__/Card.unit.test.tsx +0 -330
- package/src/components/Card/__tests__/Card.visual.test.tsx +0 -599
- package/src/components/Card/__tests__/README.md +0 -211
- package/src/components/Checkbox/__tests__/Checkbox.unit.test.tsx +0 -520
- package/src/components/DataTable/__tests__/DataTable.errorHandling.test.tsx +0 -251
- package/src/components/DataTable/__tests__/DataTable.hierarchical.test.tsx +0 -680
- package/src/components/DataTable/__tests__/DataTable.infinite-loop.test.tsx +0 -323
- package/src/components/DataTable/__tests__/DataTable.integration.test.tsx +0 -716
- package/src/components/DataTable/__tests__/DataTable.performance.test.tsx +0 -589
- package/src/components/DataTable/__tests__/DataTable.permissions.test.tsx +0 -316
- package/src/components/DataTable/__tests__/DataTable.regressionFixes.test.tsx +0 -546
- package/src/components/DataTable/__tests__/DataTable.selection.controlled.test.tsx +0 -386
- package/src/components/DataTable/__tests__/DataTable.selection.test.tsx +0 -338
- package/src/components/DataTable/__tests__/DataTable.sorting.test.tsx +0 -321
- package/src/components/DataTable/__tests__/DataTable.userWorkflows.test.tsx +0 -320
- package/src/components/DataTable/__tests__/DataTable.workflowValidation.test.tsx +0 -583
- package/src/components/DataTable/__tests__/DataTable.workflows.test.tsx +0 -711
- package/src/components/DataTable/__tests__/performance-regression.test.tsx +0 -777
- package/src/components/DataTable/__tests__/performance.test.tsx +0 -365
- package/src/components/DataTable/components/__tests__/ActionButtons.unit.test.tsx +0 -150
- package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +0 -224
- package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.unit.test.tsx +0 -244
- package/src/components/DataTable/components/__tests__/DataTable.accessibility.test.tsx +0 -629
- package/src/components/DataTable/components/__tests__/DataTable.integration.test.tsx +0 -470
- package/src/components/DataTable/components/__tests__/DataTable.performance.test.tsx +0 -160
- package/src/components/DataTable/components/__tests__/DataTable.real.test.tsx +0 -251
- package/src/components/DataTable/components/__tests__/DataTable.security.test.tsx +0 -171
- package/src/components/DataTable/components/__tests__/DataTable.unit.test.tsx +0 -290
- package/src/components/DataTable/components/__tests__/DataTableBody.unit.test.tsx +0 -147
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.unit.test.tsx +0 -182
- package/src/components/DataTable/components/__tests__/DataTableModals.unit.test.tsx +0 -123
- package/src/components/DataTable/components/__tests__/EditableRow.unit.test.tsx +0 -660
- package/src/components/DataTable/components/__tests__/EmptyState.unit.test.tsx +0 -256
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -498
- package/src/components/DataTable/components/__tests__/FilterRow.unit.test.tsx +0 -112
- package/src/components/DataTable/components/__tests__/FilteringToggle.unit.test.tsx +0 -133
- package/src/components/DataTable/components/__tests__/GroupHeader.unit.test.tsx +0 -172
- package/src/components/DataTable/components/__tests__/GroupingDropdown.unit.test.tsx +0 -222
- package/src/components/DataTable/components/__tests__/ImportModal.unit.test.tsx +0 -780
- package/src/components/DataTable/components/__tests__/LoadingState.unit.test.tsx +0 -65
- package/src/components/DataTable/components/__tests__/PaginationControls.unit.test.tsx +0 -634
- package/src/components/DataTable/components/__tests__/StateComponents.unit.test.tsx +0 -48
- package/src/components/DataTable/components/__tests__/UnifiedTableBody.hierarchical.test.tsx +0 -541
- package/src/components/DataTable/components/__tests__/ViewRowModal.unit.test.tsx +0 -228
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.unit.test.tsx +0 -568
- package/src/components/DataTable/core/__tests__/ActionManager.unit.test.ts +0 -405
- package/src/components/DataTable/core/__tests__/ArchitectureIntegration.unit.test.tsx +0 -445
- package/src/components/DataTable/core/__tests__/ColumnFactory.unit.test.ts +0 -288
- package/src/components/DataTable/core/__tests__/ColumnManager.unit.test.ts +0 -623
- package/src/components/DataTable/core/__tests__/DataManager.unit.test.ts +0 -431
- package/src/components/DataTable/core/__tests__/DataTableContext.unit.test.tsx +0 -433
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.unit.test.ts +0 -422
- package/src/components/DataTable/core/__tests__/PluginRegistry.unit.test.tsx +0 -207
- package/src/components/DataTable/core/__tests__/StateManager.unit.test.ts +0 -278
- package/src/components/DataTable/examples/__tests__/PerformanceExample.unit.test.tsx +0 -281
- package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.unit.test.ts +0 -407
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.unit.test.ts +0 -679
- package/src/components/DataTable/utils/__tests__/debugTools.unit.test.ts +0 -267
- package/src/components/DataTable/utils/__tests__/errorHandling.unit.test.ts +0 -467
- package/src/components/DataTable/utils/__tests__/exportUtils.unit.test.ts +0 -380
- package/src/components/DataTable/utils/__tests__/flexibleImport.unit.test.ts +0 -233
- package/src/components/DataTable/utils/__tests__/performanceUtils.unit.test.ts +0 -414
- package/src/components/Dialog/__tests__/Dialog.accessibility.test.tsx +0 -521
- package/src/components/Dialog/__tests__/Dialog.auto-size.example.tsx +0 -157
- package/src/components/Dialog/__tests__/Dialog.enhanced.test.tsx +0 -538
- package/src/components/Dialog/__tests__/Dialog.unit.test.tsx +0 -1373
- package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +0 -151
- package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +0 -611
- package/src/components/ErrorBoundary/__tests__/ErrorBoundary.accessibility.test.tsx +0 -517
- package/src/components/ErrorBoundary/__tests__/ErrorBoundary.integration.test.tsx +0 -572
- package/src/components/ErrorBoundary/__tests__/ErrorBoundary.unit.test.tsx +0 -579
- package/src/components/EventSelector/__tests__/EventSelector.test.tsx +0 -528
- package/src/components/FileUpload/__tests__/FileUpload.integration.test.tsx +0 -992
- package/src/components/FileUpload/__tests__/FileUpload.real.test.tsx +0 -927
- package/src/components/FileUpload/__tests__/FileUpload.test.tsx +0 -855
- package/src/components/FileUpload/__tests__/FileUpload.unit.test.tsx +0 -1311
- package/src/components/FileUpload/__tests__/FileUpload.unmocked.test.tsx +0 -937
- package/src/components/Footer/__tests__/Footer.accessibility.test.tsx +0 -359
- package/src/components/Footer/__tests__/Footer.integration.test.tsx +0 -353
- package/src/components/Footer/__tests__/Footer.performance.test.tsx +0 -309
- package/src/components/Footer/__tests__/Footer.unit.test.tsx +0 -309
- package/src/components/Footer/__tests__/Footer.visual.test.tsx +0 -335
- package/src/components/Form/__tests__/Form.accessibility.test.tsx +0 -820
- package/src/components/Form/__tests__/Form.unit.test.tsx +0 -305
- package/src/components/Form/__tests__/FormErrorSummary.unit.test.tsx +0 -285
- package/src/components/Form/__tests__/FormFieldset.unit.test.tsx +0 -241
- package/src/components/Header/__tests__/Header.accessibility.test.tsx +0 -382
- package/src/components/Header/__tests__/Header.comprehensive.test.tsx +0 -509
- package/src/components/Header/__tests__/Header.unit.test.tsx +0 -335
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +0 -196
- package/src/components/InactivityWarningModal/__tests__/InactivityWarningModal.unit.test.tsx +0 -224
- package/src/components/Input/__tests__/Input.accessibility.test.tsx +0 -632
- package/src/components/Input/__tests__/Input.unit.test.tsx +0 -1121
- package/src/components/Label/__tests__/Label.accessibility.test.tsx +0 -239
- package/src/components/Label/__tests__/Label.unit.test.tsx +0 -331
- package/src/components/LoadingSpinner/__tests__/LoadingSpinner.accessibility.test.tsx +0 -116
- package/src/components/LoadingSpinner/__tests__/LoadingSpinner.unit.test.tsx +0 -144
- package/src/components/LoginForm/__tests__/LoginForm.accessibility.test.tsx +0 -201
- package/src/components/LoginForm/__tests__/LoginForm.unit.test.tsx +0 -119
- package/src/components/NavigationMenu/__tests__/NavigationMenu.accessibility.test.tsx +0 -378
- package/src/components/NavigationMenu/__tests__/NavigationMenu.enhanced.test.tsx +0 -768
- package/src/components/NavigationMenu/__tests__/NavigationMenu.integration.test.tsx +0 -576
- package/src/components/NavigationMenu/__tests__/NavigationMenu.performance.test.tsx +0 -585
- package/src/components/NavigationMenu/__tests__/NavigationMenu.real.component.test.tsx +0 -783
- package/src/components/NavigationMenu/__tests__/NavigationMenu.security.enhanced.test.tsx +0 -810
- package/src/components/NavigationMenu/__tests__/NavigationMenu.security.test.tsx +0 -494
- package/src/components/NavigationMenu/__tests__/NavigationMenu.unit.test.tsx +0 -331
- package/src/components/NavigationMenu/__tests__/NavigationMenu.userWorkflows.test.tsx +0 -347
- package/src/components/NavigationMenu/__tests__/NavigationMenu.workflows.test.tsx +0 -584
- package/src/components/OrganisationSelector/__tests__/OrganisationSelector.unit.test.tsx +0 -664
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +0 -288
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +0 -893
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +0 -629
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +0 -782
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -904
- package/src/components/PaceLoginPage/__tests__/PaceLoginPage.accessibility.test.tsx +0 -463
- package/src/components/PaceLoginPage/__tests__/PaceLoginPage.integration.test.tsx +0 -586
- package/src/components/PaceLoginPage/__tests__/PaceLoginPage.unit.test.tsx +0 -533
- package/src/components/PasswordReset/__tests__/PasswordChangeForm.accessibility.test.tsx +0 -408
- package/src/components/PasswordReset/__tests__/PasswordChangeForm.unit.test.tsx +0 -561
- package/src/components/PasswordReset/__tests__/PasswordReset.integration.test.tsx +0 -304
- package/src/components/PasswordReset/__tests__/PasswordResetForm.accessibility.test.tsx +0 -20
- package/src/components/PasswordReset/__tests__/PasswordResetForm.unit.test.tsx +0 -523
- package/src/components/PasswordReset/__tests__/__mocks__/UnifiedAuthProvider.ts +0 -29
- package/src/components/Print/__tests__/Print.comprehensive.test.tsx +0 -331
- package/src/components/PrintButton/__tests__/PrintButton.unit.test.tsx +0 -429
- package/src/components/PrintButton/__tests__/PrintButtonGroup.unit.test.tsx +0 -277
- package/src/components/PrintButton/__tests__/PrintToolbar.unit.test.tsx +0 -264
- package/src/components/PrintCard/__tests__/PrintCard.unit.test.tsx +0 -233
- package/src/components/PrintCard/__tests__/PrintCardContent.test.tsx +0 -284
- package/src/components/PrintCard/__tests__/PrintCardGrid.unit.test.tsx +0 -214
- package/src/components/PrintCard/__tests__/PrintCardImage.unit.test.tsx +0 -264
- package/src/components/PrintDataTable/__tests__/PrintDataTable.unit.test.tsx +0 -361
- package/src/components/PrintDataTable/__tests__/PrintTableGroup.unit.test.tsx +0 -314
- package/src/components/PrintDataTable/__tests__/PrintTableRow.unit.test.tsx +0 -362
- package/src/components/PrintFooter/__tests__/PrintFooter.unit.test.tsx +0 -500
- package/src/components/PrintFooter/__tests__/PrintFooterContent.unit.test.tsx +0 -321
- package/src/components/PrintFooter/__tests__/PrintFooterInfo.unit.test.tsx +0 -335
- package/src/components/PrintFooter/__tests__/PrintPageNumber.unit.test.tsx +0 -340
- package/src/components/PrintGrid/__tests__/PrintGrid.unit.test.tsx +0 -340
- package/src/components/PrintGrid/__tests__/PrintGridBreakpoint.unit.test.tsx +0 -261
- package/src/components/PrintGrid/__tests__/PrintGridContainer.unit.test.tsx +0 -338
- package/src/components/PrintGrid/__tests__/PrintGridItem.unit.test.tsx +0 -338
- package/src/components/PrintHeader/__tests__/PrintCoverHeader.unit.test.tsx +0 -309
- package/src/components/PrintHeader/__tests__/PrintHeader.unit.test.tsx +0 -202
- package/src/components/PrintLayout/__tests__/PrintLayout.unit.test.tsx +0 -238
- package/src/components/PrintPageBreak/__tests__/PrintPageBreak.unit.test.tsx +0 -263
- package/src/components/PrintPageBreak/__tests__/PrintPageBreakGroup.unit.test.tsx +0 -239
- package/src/components/PrintPageBreak/__tests__/PrintPageBreakIndicator.unit.test.tsx +0 -235
- package/src/components/PrintSection/__tests__/PrintColumn.unit.test.tsx +0 -385
- package/src/components/PrintSection/__tests__/PrintDivider.unit.test.tsx +0 -373
- package/src/components/PrintSection/__tests__/PrintSection.unit.test.tsx +0 -390
- package/src/components/PrintSection/__tests__/PrintSectionContent.unit.test.tsx +0 -321
- package/src/components/PrintSection/__tests__/PrintSectionHeader.unit.test.tsx +0 -334
- package/src/components/PrintText/__tests__/PrintText.unit.test.tsx +0 -351
- package/src/components/Progress/__tests__/Progress.accessibility.test.tsx +0 -240
- package/src/components/Progress/__tests__/Progress.unit.test.tsx +0 -242
- package/src/components/PublicLayout/__tests__/EventLogo.test.tsx +0 -761
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.simplified.test.tsx +0 -228
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +0 -228
- package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +0 -459
- package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +0 -362
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +0 -522
- package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +0 -599
- package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +0 -513
- package/src/components/RBAC/__tests__/PagePermissionGuard.unit.test.tsx +0 -683
- package/src/components/RBAC/__tests__/RBAC.integration.test.tsx +0 -573
- package/src/components/RBAC/__tests__/RBACGuard.unit.test.tsx +0 -467
- package/src/components/RBAC/__tests__/RBACProvider.accessibility.test.tsx +0 -475
- package/src/components/RBAC/__tests__/RBACProvider.advanced.test.tsx +0 -569
- package/src/components/RBAC/__tests__/RBACProvider.integration.test.tsx +0 -352
- package/src/components/RBAC/__tests__/RBACProvider.unit.test.tsx +0 -128
- package/src/components/RBAC/__tests__/RoleBasedContent.unit.test.tsx +0 -657
- package/src/components/Select/__tests__/SearchableSelect.unit.test.tsx +0 -437
- package/src/components/Select/__tests__/Select.accessibility.test.tsx +0 -1202
- package/src/components/Select/__tests__/Select.actual.test.tsx +0 -774
- package/src/components/Select/__tests__/Select.comprehensive.test.tsx +0 -837
- package/src/components/Select/__tests__/Select.enhanced.test.tsx +0 -1101
- package/src/components/Select/__tests__/Select.integration.test.tsx +0 -772
- package/src/components/Select/__tests__/Select.performance.test.tsx +0 -695
- package/src/components/Select/__tests__/Select.real-world.test.tsx +0 -1046
- package/src/components/Select/__tests__/Select.search-algorithms.test.tsx +0 -968
- package/src/components/Select/__tests__/Select.unit.test.tsx +0 -647
- package/src/components/Select/__tests__/Select.utils.test.tsx +0 -890
- package/src/components/Table/__tests__/Table.accessibility.test.tsx +0 -233
- package/src/components/Table/__tests__/Table.unit.test.tsx +0 -235
- package/src/components/Toast/__tests__/Toast.accessibility.test.tsx +0 -238
- package/src/components/Toast/__tests__/Toast.integration.test.tsx +0 -699
- package/src/components/Toast/__tests__/Toast.unit.test.tsx +0 -750
- package/src/components/Tooltip/__tests__/Tooltip.accessibility.test.tsx +0 -121
- package/src/components/Tooltip/__tests__/Tooltip.unit.test.tsx +0 -185
- package/src/components/UserMenu/__tests__/UserMenu.accessibility.test.tsx +0 -139
- package/src/components/UserMenu/__tests__/UserMenu.integration.test.tsx +0 -188
- package/src/components/UserMenu/__tests__/UserMenu.unit.test.tsx +0 -458
- package/src/components/__tests__/EdgeCaseTesting.enhanced.test.tsx +0 -524
- package/src/components/__tests__/ErrorTesting.enhanced.test.tsx +0 -455
- package/src/components/__tests__/SuperAdminGuard.test.tsx +0 -456
- package/src/components/__tests__/SuperAdminGuard.unit.test.tsx +0 -456
- package/src/components/examples/__tests__/PermissionExample.unit.test.tsx +0 -360
- package/src/hooks/__tests__/hooks.integration.test.tsx +0 -575
- package/src/hooks/__tests__/useApiFetch.unit.test.ts +0 -115
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +0 -133
- package/src/hooks/__tests__/useDebounce.unit.test.ts +0 -82
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +0 -293
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +0 -385
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -286
- package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +0 -838
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -627
- package/src/hooks/__tests__/useRBAC.unit.test.ts +0 -911
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -537
- package/src/hooks/__tests__/useToast.unit.test.tsx +0 -62
- package/src/hooks/__tests__/useZodForm.unit.test.tsx +0 -37
- package/src/hooks/public/__tests__/usePublicEvent.test.tsx +0 -397
- package/src/hooks/public/__tests__/usePublicEventLogo.test.tsx +0 -690
- package/src/hooks/public/__tests__/usePublicRouteParams.test.tsx +0 -449
- package/src/providers/__tests__/EventProvider.unit.test.tsx +0 -768
- package/src/providers/__tests__/OrganisationProvider.basic.test.tsx +0 -116
- package/src/providers/__tests__/OrganisationProvider.unit.test.tsx +0 -1312
- package/src/providers/__tests__/UnifiedAuthProvider.inactivity.test.tsx +0 -601
- package/src/providers/__tests__/UnifiedAuthProvider.unit.test.tsx +0 -683
- package/src/providers/__tests__/index.unit.test.ts +0 -78
- package/src/rbac/__tests__/PagePermissionGuard.test.tsx +0 -673
- package/src/rbac/__tests__/README.md +0 -170
- package/src/rbac/__tests__/RoleBasedRouter.test.tsx +0 -709
- package/src/rbac/__tests__/TestContext.tsx +0 -72
- package/src/rbac/__tests__/__mocks__/cache.ts +0 -144
- package/src/rbac/__tests__/__mocks__/supabase.ts +0 -152
- package/src/rbac/__tests__/adapters-hooks-comprehensive.test.tsx +0 -782
- package/src/rbac/__tests__/adapters-hooks.test.tsx +0 -561
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +0 -963
- package/src/rbac/__tests__/adapters.test.tsx +0 -444
- package/src/rbac/__tests__/api.test.ts +0 -620
- package/src/rbac/__tests__/audit-observability-comprehensive.test.ts +0 -792
- package/src/rbac/__tests__/audit-observability.test.ts +0 -549
- package/src/rbac/__tests__/audit.test.ts +0 -616
- package/src/rbac/__tests__/build-contract-compliance-simple.test.ts +0 -230
- package/src/rbac/__tests__/cache-invalidation-comprehensive.test.ts +0 -889
- package/src/rbac/__tests__/cache-invalidation.test.ts +0 -457
- package/src/rbac/__tests__/cache.test.ts +0 -458
- package/src/rbac/__tests__/components-navigation-guard.enhanced.test.tsx +0 -859
- package/src/rbac/__tests__/components-navigation-guard.test.tsx +0 -895
- package/src/rbac/__tests__/components-navigation-provider.test.tsx +0 -692
- package/src/rbac/__tests__/components-page-permission-guard.test.tsx +0 -673
- package/src/rbac/__tests__/components-page-permission-provider.test.tsx +0 -614
- package/src/rbac/__tests__/components-permission-enforcer.enhanced.fixed.test.tsx +0 -836
- package/src/rbac/__tests__/components-permission-enforcer.enhanced.test.tsx +0 -837
- package/src/rbac/__tests__/components-permission-enforcer.test.tsx +0 -825
- package/src/rbac/__tests__/components-role-based-router.test.tsx +0 -709
- package/src/rbac/__tests__/components-secure-data-provider.test.tsx +0 -607
- package/src/rbac/__tests__/config.test.ts +0 -583
- package/src/rbac/__tests__/core-logic-unit.test.ts +0 -190
- package/src/rbac/__tests__/core-permission-logic-comprehensive.test.ts +0 -1467
- package/src/rbac/__tests__/core-permission-logic-fixed.test.ts +0 -151
- package/src/rbac/__tests__/core-permission-logic-simple.test.ts +0 -968
- package/src/rbac/__tests__/core-permission-logic.test.ts +0 -966
- package/src/rbac/__tests__/edge-cases-comprehensive.test.ts +0 -988
- package/src/rbac/__tests__/edge-cases.test.ts +0 -654
- package/src/rbac/__tests__/engine.test.ts +0 -361
- package/src/rbac/__tests__/engine.unit.test.ts +0 -361
- package/src/rbac/__tests__/hooks.enhanced.test.tsx +0 -979
- package/src/rbac/__tests__/hooks.fixed.test.tsx +0 -475
- package/src/rbac/__tests__/hooks.test.tsx +0 -385
- package/src/rbac/__tests__/index.test.ts +0 -269
- package/src/rbac/__tests__/integration.enhanced.test.tsx +0 -824
- package/src/rbac/__tests__/page-permission-guard-super-admin.test.tsx +0 -261
- package/src/rbac/__tests__/performance.enhanced.test.tsx +0 -724
- package/src/rbac/__tests__/permissions.test.ts +0 -383
- package/src/rbac/__tests__/requires-event.test.ts +0 -330
- package/src/rbac/__tests__/scope-isolation-comprehensive.test.ts +0 -1349
- package/src/rbac/__tests__/scope-isolation.test.ts +0 -755
- package/src/rbac/__tests__/secure-client-rls-comprehensive.test.ts +0 -592
- package/src/rbac/__tests__/secure-client-rls.test.ts +0 -377
- package/src/rbac/__tests__/security.test.ts +0 -296
- package/src/rbac/__tests__/setup.ts +0 -228
- package/src/rbac/__tests__/test-utils-enhanced.tsx +0 -400
- package/src/rbac/__tests__/types.test.ts +0 -685
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -631
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -667
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -647
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -496
- package/src/rbac/testing/__tests__/index.test.tsx +0 -342
- package/src/rbac/utils/__tests__/eventContext.test.ts +0 -428
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -428
- package/src/styles/__tests__/styles.unit.test.ts +0 -164
- package/src/test-dom-cleanup.test.tsx +0 -38
- package/src/theming/__tests__/README.md +0 -335
- package/src/theming/__tests__/runtime.accessibility.test.ts +0 -474
- package/src/theming/__tests__/runtime.error.test.ts +0 -616
- package/src/theming/__tests__/runtime.integration.test.ts +0 -376
- package/src/theming/__tests__/runtime.performance.test.ts +0 -411
- package/src/theming/__tests__/runtime.unit.test.ts +0 -470
- package/src/types/__tests__/database.unit.test.ts +0 -489
- package/src/types/__tests__/guards.unit.test.ts +0 -146
- package/src/types/__tests__/index.unit.test.ts +0 -77
- package/src/types/__tests__/organisation.unit.test.ts +0 -713
- package/src/types/__tests__/rbac.unit.test.ts +0 -621
- package/src/types/__tests__/security.unit.test.ts +0 -347
- package/src/types/__tests__/supabase.unit.test.ts +0 -658
- package/src/types/__tests__/theme.unit.test.ts +0 -218
- package/src/types/__tests__/unified.unit.test.ts +0 -537
- package/src/types/__tests__/validation.unit.test.ts +0 -616
- package/src/utils/__tests__/appConfig.unit.test.ts +0 -55
- package/src/utils/__tests__/appNameResolver.unit.test.ts +0 -137
- package/src/utils/__tests__/audit.unit.test.ts +0 -69
- package/src/utils/__tests__/auth-utils.unit.test.ts +0 -70
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +0 -317
- package/src/utils/__tests__/cn.unit.test.ts +0 -34
- package/src/utils/__tests__/deviceFingerprint.unit.test.ts +0 -480
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +0 -322
- package/src/utils/__tests__/formatDate.unit.test.ts +0 -109
- package/src/utils/__tests__/formatting.unit.test.ts +0 -66
- package/src/utils/__tests__/index.unit.test.ts +0 -251
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -304
- package/src/utils/__tests__/organisationContext.unit.test.ts +0 -192
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +0 -259
- package/src/utils/__tests__/permissionTypes.unit.test.ts +0 -250
- package/src/utils/__tests__/permissionUtils.unit.test.ts +0 -362
- package/src/utils/__tests__/sanitization.unit.test.ts +0 -346
- package/src/utils/__tests__/schemaUtils.unit.test.ts +0 -441
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -334
- package/src/utils/__tests__/secureErrors.unit.test.ts +0 -377
- package/src/utils/__tests__/secureStorage.unit.test.ts +0 -293
- package/src/utils/__tests__/security.unit.test.ts +0 -127
- package/src/utils/__tests__/securityMonitor.unit.test.ts +0 -280
- package/src/utils/__tests__/sessionTracking.unit.test.ts +0 -370
- package/src/utils/__tests__/validation.unit.test.ts +0 -84
- package/src/utils/__tests__/validationUtils.unit.test.ts +0 -571
- package/src/utils/print/__tests__/PrintDataProcessor.unit.test.ts +0 -219
- package/src/utils/print/__tests__/usePrintOptimization.unit.test.tsx +0 -353
- package/src/utils/storage/__tests__/config.unit.test.ts +0 -206
- package/src/utils/storage/__tests__/helpers.unit.test.ts +0 -648
- package/src/utils/storage/__tests__/index.unit.test.ts +0 -167
- package/src/utils/storage/__tests__/types.unit.test.ts +0 -441
- package/src/validation/__tests__/common.unit.test.ts +0 -101
- package/src/validation/__tests__/csrf.unit.test.ts +0 -302
- package/src/validation/__tests__/passwordSchema.unit.test.ts +0 -98
- package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +0 -466
- /package/dist/{DataTable-EEUDXPE5.js.map → DataTable-GX3XERFJ.js.map} +0 -0
- /package/dist/{chunk-VYG4AXYW.js.map → chunk-5EL3KHOQ.js.map} +0 -0
|
@@ -1,18 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
init_OrganisationProvider,
|
|
3
|
+
useOrganisations
|
|
4
|
+
} from "./chunk-COBPIXXQ.js";
|
|
1
5
|
import {
|
|
2
6
|
init_AuthProvider,
|
|
3
7
|
init_InactivityProvider,
|
|
4
|
-
init_OrganisationProvider,
|
|
5
8
|
init_RBACProvider,
|
|
6
9
|
init_UnifiedAuthProvider,
|
|
7
|
-
useOrganisations,
|
|
8
10
|
useUnifiedAuth
|
|
9
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-6CR3MRZN.js";
|
|
10
12
|
import {
|
|
11
|
-
DebugLogger,
|
|
12
|
-
init_debugLogger,
|
|
13
13
|
init_organisationContext,
|
|
14
14
|
setOrganisationContext
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-OEGRKULD.js";
|
|
16
|
+
import {
|
|
17
|
+
DebugLogger,
|
|
18
|
+
init_debugLogger
|
|
19
|
+
} from "./chunk-OYRY44Q2.js";
|
|
16
20
|
import {
|
|
17
21
|
__esm,
|
|
18
22
|
__export
|
|
@@ -323,4 +327,4 @@ export {
|
|
|
323
327
|
EventProvider_exports,
|
|
324
328
|
init_EventProvider
|
|
325
329
|
};
|
|
326
|
-
//# sourceMappingURL=chunk-
|
|
330
|
+
//# sourceMappingURL=chunk-TGDCLPP2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/appIdResolver.ts","../src/providers/EventProvider.tsx","../src/providers/index.ts"],"sourcesContent":["/**\n * App ID Resolution Utility\n * @package @jmruthers/pace-core\n * @module Utils/AppIdResolver\n * @since 1.0.0\n * \n * This module provides utilities to resolve app names to app IDs for database operations.\n */\n\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport type { Database } from '../types/database';\n\n/**\n * Resolves an app name to its corresponding app ID\n * \n * @param supabase - Supabase client instance\n * @param appName - The app name to resolve\n * @returns Promise resolving to the app ID or null if not found\n */\nexport async function getAppId(\n supabase: SupabaseClient<Database>,\n appName: string\n): Promise<string | null> {\n try {\n const { data, error } = await supabase\n .from('rbac_apps')\n .select('id')\n .ilike('name', appName)\n .eq('is_active', true)\n .single();\n\n if (error) {\n console.error('Failed to resolve app ID for app name:', appName, error);\n return null;\n }\n\n return (data as { id: string } | null)?.id || null;\n } catch (error) {\n console.error('Error resolving app ID for app name:', appName, error);\n return null;\n }\n}\n\n/**\n * Resolves multiple app names to their corresponding app IDs\n * \n * @param supabase - Supabase client instance\n * @param appNames - Array of app names to resolve\n * @returns Promise resolving to a map of app names to app IDs\n */\nexport async function getAppIds(\n supabase: SupabaseClient<Database>,\n appNames: string[]\n): Promise<Record<string, string | null>> {\n try {\n // For case-insensitive matching with multiple values, we need to use OR conditions\n // since PostgreSQL doesn't support case-insensitive IN with ILIKE\n const orConditions = appNames.map(name => `name.ilike.${name}`).join(',');\n \n const { data, error } = await supabase\n .from('rbac_apps')\n .select('id, name')\n .or(orConditions)\n .eq('is_active', true);\n\n if (error) {\n console.error('Failed to resolve app IDs for app names:', appNames, error);\n return {};\n }\n\n const result: Record<string, string | null> = {};\n \n // Initialize all app names with null\n appNames.forEach(name => {\n result[name] = null;\n });\n\n // Set resolved app IDs - match case-insensitively\n (data as { id: string; name: string }[] | null)?.forEach(app => {\n // Find the original app name that matches (case-insensitive)\n const originalName = appNames.find(name => \n name.toLowerCase() === app.name.toLowerCase()\n );\n if (originalName) {\n result[originalName] = app.id;\n }\n });\n\n return result;\n } catch (error) {\n console.error('Error resolving app IDs for app names:', appNames, error);\n return {};\n }\n}\n\n/**\n * Cached app ID resolver with TTL\n */\nclass CachedAppIdResolver {\n private cache = new Map<string, { id: string | null; expires: number }>();\n private ttl = 5 * 60 * 1000; // 5 minutes\n\n async getAppId(\n supabase: SupabaseClient<Database>,\n appName: string\n ): Promise<string | null> {\n const now = Date.now();\n const cached = this.cache.get(appName);\n\n if (cached && cached.expires > now) {\n return cached.id;\n }\n\n const id = await getAppId(supabase, appName);\n this.cache.set(appName, { id, expires: now + this.ttl });\n\n return id;\n }\n\n clearCache(): void {\n this.cache.clear();\n }\n\n clearCacheForApp(appName: string): void {\n this.cache.delete(appName);\n }\n}\n\n// Export singleton instance\nexport const cachedAppIdResolver = new CachedAppIdResolver();\n","import React, {\n createContext,\n useContext,\n useState,\n useEffect,\n useLayoutEffect,\n useCallback,\n useRef,\n} from 'react';\nimport { useUnifiedAuth } from './UnifiedAuthProvider';\nimport { useOrganisations } from './OrganisationProvider';\nimport { setOrganisationContext } from '../utils/organisationContext';\nimport { DebugLogger } from '../utils/debugLogger';\nimport { cachedAppIdResolver } from '../utils/appIdResolver';\n\nimport { Event } from '../types/unified';\n\nexport interface EventContextType {\n events: Event[];\n selectedEvent: Event | null;\n isLoading: boolean;\n error: Error | null;\n setSelectedEvent: (event: Event | null) => void;\n refreshEvents: () => Promise<void>;\n}\n\nconst EventContext = createContext<EventContextType | undefined>(undefined);\n\nexport const useEvents = () => {\n const context = useContext(EventContext);\n if (context === undefined) {\n throw new Error('useEvents must be used within an EventProvider');\n }\n return context;\n};\n\nexport interface EventProviderProps {\n children: React.ReactNode;\n}\n\n// Helper function to get the next event by date\nfunction getNextEventByDate(events: Event[]): Event | null {\n if (!events || events.length === 0) {\n return null;\n }\n\n const now = new Date();\n const futureEvents = events.filter(event => {\n if (!event.event_date) return false;\n const eventDate = new Date(event.event_date);\n return eventDate >= now;\n });\n\n if (futureEvents.length === 0) {\n return null;\n }\n\n // Sort by date (ascending) to get the next event\n const sortedFutureEvents = futureEvents.sort((a, b) => {\n const dateA = new Date(a.event_date!);\n const dateB = new Date(b.event_date!);\n return dateA.getTime() - dateB.getTime();\n });\n\n return sortedFutureEvents[0];\n}\n\nexport function EventProvider({ children }: EventProviderProps) {\n const [events, setEvents] = useState<Event[]>([]);\n const [selectedEvent, setSelectedEventState] = useState<Event | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const { user, session, supabase, appName, setSelectedEventId } = useUnifiedAuth();\n \n // Refs to prevent infinite loops\n const isInitializedRef = useRef(false);\n const isFetchingRef = useRef(false);\n const hasAutoSelectedRef = useRef(false);\n const userClearedEventRef = useRef(false);\n const setSelectedEventIdRef = useRef(setSelectedEventId);\n \n // Try to get organisation context, but don't fail if not available\n let selectedOrganisation = null;\n let ensureOrganisationContext = null;\n \n try {\n const orgContext = useOrganisations();\n selectedOrganisation = orgContext.selectedOrganisation;\n ensureOrganisationContext = orgContext.ensureOrganisationContext;\n } catch (error) {\n console.warn('[EventProvider] Organisation context not available:', error);\n }\n\n // Load persisted event selection with tab-scoped storage\n const loadPersistedEvent = useCallback(async (events: Event[]) => {\n try {\n // Try sessionStorage first (tab-specific)\n let persistedEventId = sessionStorage.getItem('pace-core-selected-event');\n \n // Fallback to localStorage if no sessionStorage value (for new tabs)\n if (!persistedEventId) {\n persistedEventId = localStorage.getItem('pace-core-selected-event');\n // If we found a value in localStorage, also store it in sessionStorage for this tab\n if (persistedEventId) {\n sessionStorage.setItem('pace-core-selected-event', persistedEventId);\n }\n }\n \n if (persistedEventId && events.length > 0) {\n const persistedEvent = events.find(event => event.event_id === persistedEventId);\n if (persistedEvent) {\n DebugLogger.log('EventProvider', 'Restoring persisted event:', persistedEvent.event_name);\n setSelectedEventState(persistedEvent);\n setSelectedEventId(persistedEventId);\n return true;\n }\n }\n } catch (error) {\n console.warn('[EventProvider] Failed to load persisted event:', error);\n }\n return false;\n }, [setSelectedEventId]);\n\n // Persist event selection with tab-scoped storage\n const persistEventSelection = useCallback((eventId: string) => {\n try {\n // Store in sessionStorage for tab-specific persistence\n sessionStorage.setItem('pace-core-selected-event', eventId);\n // Also store in localStorage as fallback for new tabs\n localStorage.setItem('pace-core-selected-event', eventId);\n } catch (error) {\n console.warn('[EventProvider] Failed to persist event selection:', error);\n }\n }, []);\n\n // Auto-select next event\n const autoSelectNextEvent = useCallback((events: Event[]) => {\n const nextEvent = getNextEventByDate(events);\n if (nextEvent) {\n DebugLogger.log('EventProvider', 'Auto-selecting next event:', nextEvent.event_name);\n setSelectedEventState(nextEvent);\n setSelectedEventId(nextEvent.event_id);\n persistEventSelection(nextEvent.event_id);\n }\n }, [setSelectedEventId, persistEventSelection]);\n\n // Main fetch function\n const fetchEvents = useCallback(async () => {\n if (!user || !session || !supabase || !appName || !selectedOrganisation) {\n DebugLogger.log('EventProvider', 'Missing required dependencies, skipping fetch');\n setIsLoading(false);\n return;\n }\n\n // Prevent multiple simultaneous fetches\n if (isFetchingRef.current) {\n DebugLogger.log('EventProvider', 'Already fetching events, skipping');\n return;\n }\n\n DebugLogger.log('EventProvider', 'User and organisation found, fetching events for:', {\n userId: user.id,\n appName: appName,\n organisationId: selectedOrganisation.id,\n organisationName: selectedOrganisation.display_name\n });\n\n isFetchingRef.current = true;\n let isMounted = true;\n\n try {\n // Ensure organisation context is set\n if (ensureOrganisationContext) {\n await ensureOrganisationContext();\n await setOrganisationContext(supabase, selectedOrganisation.id);\n }\n\n // Resolve app name to app ID\n const appId = await cachedAppIdResolver.getAppId(supabase, appName);\n \n if (!appId) {\n throw new Error(`App ID not found for app name: ${appName}`);\n }\n\n // Call the RPC function with app_id\n DebugLogger.log('EventProvider', 'Calling get_pace_user_events RPC with:', {\n user_uuid: user.id,\n app_id: appId,\n p_organisation_id: selectedOrganisation.id\n });\n\n const response = await supabase.rpc('get_pace_user_events', {\n user_uuid: user.id,\n app_id: appId,\n p_organisation_id: selectedOrganisation.id,\n });\n \n const { data, error: rpcError } = response || {};\n\n DebugLogger.log('EventProvider', 'RPC response:', {\n data,\n error: rpcError,\n dataLength: data?.length || 0,\n organisationId: selectedOrganisation.id\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to fetch events');\n }\n\n if (isMounted) {\n const eventsData = data || [];\n setEvents(eventsData);\n setError(null);\n\n // Note: Event colors are now managed by useEventTheme hook based on route and selected event\n // This prevents unwanted color cycling on non-event pages\n\n // Reset auto-selection ref for new events\n hasAutoSelectedRef.current = false;\n\n // Try to restore persisted event first\n await loadPersistedEvent(eventsData);\n }\n } catch (err) {\n console.error('[EventProvider] Error fetching events:', err);\n const _error = err instanceof Error ? err : new Error('Unknown error occurred');\n \n if (isMounted) {\n setError(_error);\n setEvents([]);\n }\n } finally {\n if (isMounted) {\n setIsLoading(false);\n }\n isFetchingRef.current = false;\n }\n\n return () => {\n isMounted = false;\n };\n }, [user, session, supabase, appName, selectedOrganisation, ensureOrganisationContext, loadPersistedEvent, autoSelectNextEvent]);\n\n // Initialize events only once\n useEffect(() => {\n if (!isInitializedRef.current) {\n isInitializedRef.current = true;\n fetchEvents();\n }\n }, [fetchEvents]);\n\n // Update ref when setSelectedEventId changes\n useEffect(() => {\n setSelectedEventIdRef.current = setSelectedEventId;\n }, [setSelectedEventId]);\n\n // Auto-select next event when events are loaded and no event is selected\n useLayoutEffect(() => {\n if (events.length > 0 && !selectedEvent && !hasAutoSelectedRef.current && !userClearedEventRef.current) {\n const nextEvent = getNextEventByDate(events);\n if (nextEvent) {\n DebugLogger.log('EventProvider', 'Auto-selecting next event:', nextEvent.event_name);\n hasAutoSelectedRef.current = true;\n setSelectedEventState(nextEvent);\n setSelectedEventIdRef.current(nextEvent.event_id);\n persistEventSelection(nextEvent.event_id);\n }\n }\n }, [events, selectedEvent]);\n\n const setSelectedEvent = useCallback((event: Event | null) => {\n if (event) {\n // SECURITY: Validate event belongs to current organisation\n try {\n if (selectedOrganisation && event.organisation_id !== selectedOrganisation.id) {\n console.error('[EventProvider] Event organisation_id does not match selected organisation');\n return;\n }\n } catch (error) {\n // Silently handle validation errors\n }\n\n setSelectedEventState(event);\n setSelectedEventId(event.event_id);\n persistEventSelection(event.event_id);\n // Reset the user cleared flag when selecting an event\n userClearedEventRef.current = false;\n } else {\n setSelectedEventState(null);\n setSelectedEventId(null);\n // Clear both sessionStorage and localStorage\n sessionStorage.removeItem('pace-core-selected-event');\n localStorage.removeItem('pace-core-selected-event');\n // Reset the auto-selection flag when clearing the event\n hasAutoSelectedRef.current = false;\n // Mark that user explicitly cleared the event to prevent auto-selection\n userClearedEventRef.current = true;\n }\n }, [selectedOrganisation, setSelectedEventId, persistEventSelection]);\n\n const refreshEvents = useCallback(async () => {\n isInitializedRef.current = false;\n isFetchingRef.current = false;\n // Reset the user cleared flag when refreshing events\n userClearedEventRef.current = false;\n await fetchEvents();\n }, [fetchEvents]);\n\n const contextValue: EventContextType = {\n events,\n selectedEvent,\n isLoading,\n error,\n setSelectedEvent,\n refreshEvents,\n };\n\n return (\n <EventContext.Provider value={contextValue}>\n {children}\n </EventContext.Provider>\n );\n}","/**\n * @file Providers Export\n * @package @jmruthers/pace-core\n * @module Providers\n * @since 0.1.0\n */\n\nexport * from './EventProvider';\nexport * from './OrganisationProvider';\nexport * from './UnifiedAuthProvider';\n\n// Individual providers for advanced usage\nexport * from './AuthProvider';\nexport * from './RBACProvider';\nexport * from './InactivityProvider';\n"],"mappings":"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","names":["error","events"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/appIdResolver.ts","../src/providers/EventProvider.tsx","../src/providers/index.ts"],"sourcesContent":["/**\n * App ID Resolution Utility\n * @package @jmruthers/pace-core\n * @module Utils/AppIdResolver\n * @since 1.0.0\n * \n * This module provides utilities to resolve app names to app IDs for database operations.\n */\n\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport type { Database } from '../types/database';\n\n/**\n * Resolves an app name to its corresponding app ID\n * \n * @param supabase - Supabase client instance\n * @param appName - The app name to resolve\n * @returns Promise resolving to the app ID or null if not found\n */\nexport async function getAppId(\n supabase: SupabaseClient<Database>,\n appName: string\n): Promise<string | null> {\n try {\n const { data, error } = await supabase\n .from('rbac_apps')\n .select('id')\n .ilike('name', appName)\n .eq('is_active', true)\n .single();\n\n if (error) {\n console.error('Failed to resolve app ID for app name:', appName, error);\n return null;\n }\n\n return (data as { id: string } | null)?.id || null;\n } catch (error) {\n console.error('Error resolving app ID for app name:', appName, error);\n return null;\n }\n}\n\n/**\n * Resolves multiple app names to their corresponding app IDs\n * \n * @param supabase - Supabase client instance\n * @param appNames - Array of app names to resolve\n * @returns Promise resolving to a map of app names to app IDs\n */\nexport async function getAppIds(\n supabase: SupabaseClient<Database>,\n appNames: string[]\n): Promise<Record<string, string | null>> {\n try {\n // For case-insensitive matching with multiple values, we need to use OR conditions\n // since PostgreSQL doesn't support case-insensitive IN with ILIKE\n const orConditions = appNames.map(name => `name.ilike.${name}`).join(',');\n \n const { data, error } = await supabase\n .from('rbac_apps')\n .select('id, name')\n .or(orConditions)\n .eq('is_active', true);\n\n if (error) {\n console.error('Failed to resolve app IDs for app names:', appNames, error);\n return {};\n }\n\n const result: Record<string, string | null> = {};\n \n // Initialize all app names with null\n appNames.forEach(name => {\n result[name] = null;\n });\n\n // Set resolved app IDs - match case-insensitively\n (data as { id: string; name: string }[] | null)?.forEach(app => {\n // Find the original app name that matches (case-insensitive)\n const originalName = appNames.find(name => \n name.toLowerCase() === app.name.toLowerCase()\n );\n if (originalName) {\n result[originalName] = app.id;\n }\n });\n\n return result;\n } catch (error) {\n console.error('Error resolving app IDs for app names:', appNames, error);\n return {};\n }\n}\n\n/**\n * Cached app ID resolver with TTL\n */\nclass CachedAppIdResolver {\n private cache = new Map<string, { id: string | null; expires: number }>();\n private ttl = 5 * 60 * 1000; // 5 minutes\n\n async getAppId(\n supabase: SupabaseClient<Database>,\n appName: string\n ): Promise<string | null> {\n const now = Date.now();\n const cached = this.cache.get(appName);\n\n if (cached && cached.expires > now) {\n return cached.id;\n }\n\n const id = await getAppId(supabase, appName);\n this.cache.set(appName, { id, expires: now + this.ttl });\n\n return id;\n }\n\n clearCache(): void {\n this.cache.clear();\n }\n\n clearCacheForApp(appName: string): void {\n this.cache.delete(appName);\n }\n}\n\n// Export singleton instance\nexport const cachedAppIdResolver = new CachedAppIdResolver();\n","import React, {\n createContext,\n useContext,\n useState,\n useEffect,\n useLayoutEffect,\n useCallback,\n useRef,\n} from 'react';\nimport { useUnifiedAuth } from './UnifiedAuthProvider';\nimport { useOrganisations } from './OrganisationProvider';\nimport { setOrganisationContext } from '../utils/organisationContext';\nimport { DebugLogger } from '../utils/debugLogger';\nimport { cachedAppIdResolver } from '../utils/appIdResolver';\n\nimport { Event } from '../types/unified';\n\nexport interface EventContextType {\n events: Event[];\n selectedEvent: Event | null;\n isLoading: boolean;\n error: Error | null;\n setSelectedEvent: (event: Event | null) => void;\n refreshEvents: () => Promise<void>;\n}\n\nconst EventContext = createContext<EventContextType | undefined>(undefined);\n\nexport const useEvents = () => {\n const context = useContext(EventContext);\n if (context === undefined) {\n throw new Error('useEvents must be used within an EventProvider');\n }\n return context;\n};\n\nexport interface EventProviderProps {\n children: React.ReactNode;\n}\n\n// Helper function to get the next event by date\nfunction getNextEventByDate(events: Event[]): Event | null {\n if (!events || events.length === 0) {\n return null;\n }\n\n const now = new Date();\n const futureEvents = events.filter(event => {\n if (!event.event_date) return false;\n const eventDate = new Date(event.event_date);\n return eventDate >= now;\n });\n\n if (futureEvents.length === 0) {\n return null;\n }\n\n // Sort by date (ascending) to get the next event\n const sortedFutureEvents = futureEvents.sort((a, b) => {\n const dateA = new Date(a.event_date!);\n const dateB = new Date(b.event_date!);\n return dateA.getTime() - dateB.getTime();\n });\n\n return sortedFutureEvents[0];\n}\n\nexport function EventProvider({ children }: EventProviderProps) {\n const [events, setEvents] = useState<Event[]>([]);\n const [selectedEvent, setSelectedEventState] = useState<Event | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const { user, session, supabase, appName, setSelectedEventId } = useUnifiedAuth();\n \n // Refs to prevent infinite loops\n const isInitializedRef = useRef(false);\n const isFetchingRef = useRef(false);\n const hasAutoSelectedRef = useRef(false);\n const userClearedEventRef = useRef(false);\n const setSelectedEventIdRef = useRef(setSelectedEventId);\n \n // Try to get organisation context, but don't fail if not available\n let selectedOrganisation = null;\n let ensureOrganisationContext = null;\n \n try {\n const orgContext = useOrganisations();\n selectedOrganisation = orgContext.selectedOrganisation;\n ensureOrganisationContext = orgContext.ensureOrganisationContext;\n } catch (error) {\n console.warn('[EventProvider] Organisation context not available:', error);\n }\n\n // Load persisted event selection with tab-scoped storage\n const loadPersistedEvent = useCallback(async (events: Event[]) => {\n try {\n // Try sessionStorage first (tab-specific)\n let persistedEventId = sessionStorage.getItem('pace-core-selected-event');\n \n // Fallback to localStorage if no sessionStorage value (for new tabs)\n if (!persistedEventId) {\n persistedEventId = localStorage.getItem('pace-core-selected-event');\n // If we found a value in localStorage, also store it in sessionStorage for this tab\n if (persistedEventId) {\n sessionStorage.setItem('pace-core-selected-event', persistedEventId);\n }\n }\n \n if (persistedEventId && events.length > 0) {\n const persistedEvent = events.find(event => event.event_id === persistedEventId);\n if (persistedEvent) {\n DebugLogger.log('EventProvider', 'Restoring persisted event:', persistedEvent.event_name);\n setSelectedEventState(persistedEvent);\n setSelectedEventId(persistedEventId);\n return true;\n }\n }\n } catch (error) {\n console.warn('[EventProvider] Failed to load persisted event:', error);\n }\n return false;\n }, [setSelectedEventId]);\n\n // Persist event selection with tab-scoped storage\n const persistEventSelection = useCallback((eventId: string) => {\n try {\n // Store in sessionStorage for tab-specific persistence\n sessionStorage.setItem('pace-core-selected-event', eventId);\n // Also store in localStorage as fallback for new tabs\n localStorage.setItem('pace-core-selected-event', eventId);\n } catch (error) {\n console.warn('[EventProvider] Failed to persist event selection:', error);\n }\n }, []);\n\n // Auto-select next event\n const autoSelectNextEvent = useCallback((events: Event[]) => {\n const nextEvent = getNextEventByDate(events);\n if (nextEvent) {\n DebugLogger.log('EventProvider', 'Auto-selecting next event:', nextEvent.event_name);\n setSelectedEventState(nextEvent);\n setSelectedEventId(nextEvent.event_id);\n persistEventSelection(nextEvent.event_id);\n }\n }, [setSelectedEventId, persistEventSelection]);\n\n // Main fetch function\n const fetchEvents = useCallback(async () => {\n if (!user || !session || !supabase || !appName || !selectedOrganisation) {\n DebugLogger.log('EventProvider', 'Missing required dependencies, skipping fetch');\n setIsLoading(false);\n return;\n }\n\n // Prevent multiple simultaneous fetches\n if (isFetchingRef.current) {\n DebugLogger.log('EventProvider', 'Already fetching events, skipping');\n return;\n }\n\n DebugLogger.log('EventProvider', 'User and organisation found, fetching events for:', {\n userId: user.id,\n appName: appName,\n organisationId: selectedOrganisation.id,\n organisationName: selectedOrganisation.display_name\n });\n\n isFetchingRef.current = true;\n let isMounted = true;\n\n try {\n // Ensure organisation context is set\n if (ensureOrganisationContext) {\n await ensureOrganisationContext();\n await setOrganisationContext(supabase, selectedOrganisation.id);\n }\n\n // Resolve app name to app ID\n const appId = await cachedAppIdResolver.getAppId(supabase, appName);\n \n if (!appId) {\n throw new Error(`App ID not found for app name: ${appName}`);\n }\n\n // Call the RPC function with app_id\n DebugLogger.log('EventProvider', 'Calling get_pace_user_events RPC with:', {\n user_uuid: user.id,\n app_id: appId,\n p_organisation_id: selectedOrganisation.id\n });\n\n const response = await supabase.rpc('get_pace_user_events', {\n user_uuid: user.id,\n app_id: appId,\n p_organisation_id: selectedOrganisation.id,\n });\n \n const { data, error: rpcError } = response || {};\n\n DebugLogger.log('EventProvider', 'RPC response:', {\n data,\n error: rpcError,\n dataLength: data?.length || 0,\n organisationId: selectedOrganisation.id\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to fetch events');\n }\n\n if (isMounted) {\n const eventsData = data || [];\n setEvents(eventsData);\n setError(null);\n\n // Note: Event colors are now managed by useEventTheme hook based on route and selected event\n // This prevents unwanted color cycling on non-event pages\n\n // Reset auto-selection ref for new events\n hasAutoSelectedRef.current = false;\n\n // Try to restore persisted event first\n await loadPersistedEvent(eventsData);\n }\n } catch (err) {\n console.error('[EventProvider] Error fetching events:', err);\n const _error = err instanceof Error ? err : new Error('Unknown error occurred');\n \n if (isMounted) {\n setError(_error);\n setEvents([]);\n }\n } finally {\n if (isMounted) {\n setIsLoading(false);\n }\n isFetchingRef.current = false;\n }\n\n return () => {\n isMounted = false;\n };\n }, [user, session, supabase, appName, selectedOrganisation, ensureOrganisationContext, loadPersistedEvent, autoSelectNextEvent]);\n\n // Initialize events only once\n useEffect(() => {\n if (!isInitializedRef.current) {\n isInitializedRef.current = true;\n fetchEvents();\n }\n }, [fetchEvents]);\n\n // Update ref when setSelectedEventId changes\n useEffect(() => {\n setSelectedEventIdRef.current = setSelectedEventId;\n }, [setSelectedEventId]);\n\n // Auto-select next event when events are loaded and no event is selected\n useLayoutEffect(() => {\n if (events.length > 0 && !selectedEvent && !hasAutoSelectedRef.current && !userClearedEventRef.current) {\n const nextEvent = getNextEventByDate(events);\n if (nextEvent) {\n DebugLogger.log('EventProvider', 'Auto-selecting next event:', nextEvent.event_name);\n hasAutoSelectedRef.current = true;\n setSelectedEventState(nextEvent);\n setSelectedEventIdRef.current(nextEvent.event_id);\n persistEventSelection(nextEvent.event_id);\n }\n }\n }, [events, selectedEvent]);\n\n const setSelectedEvent = useCallback((event: Event | null) => {\n if (event) {\n // SECURITY: Validate event belongs to current organisation\n try {\n if (selectedOrganisation && event.organisation_id !== selectedOrganisation.id) {\n console.error('[EventProvider] Event organisation_id does not match selected organisation');\n return;\n }\n } catch (error) {\n // Silently handle validation errors\n }\n\n setSelectedEventState(event);\n setSelectedEventId(event.event_id);\n persistEventSelection(event.event_id);\n // Reset the user cleared flag when selecting an event\n userClearedEventRef.current = false;\n } else {\n setSelectedEventState(null);\n setSelectedEventId(null);\n // Clear both sessionStorage and localStorage\n sessionStorage.removeItem('pace-core-selected-event');\n localStorage.removeItem('pace-core-selected-event');\n // Reset the auto-selection flag when clearing the event\n hasAutoSelectedRef.current = false;\n // Mark that user explicitly cleared the event to prevent auto-selection\n userClearedEventRef.current = true;\n }\n }, [selectedOrganisation, setSelectedEventId, persistEventSelection]);\n\n const refreshEvents = useCallback(async () => {\n isInitializedRef.current = false;\n isFetchingRef.current = false;\n // Reset the user cleared flag when refreshing events\n userClearedEventRef.current = false;\n await fetchEvents();\n }, [fetchEvents]);\n\n const contextValue: EventContextType = {\n events,\n selectedEvent,\n isLoading,\n error,\n setSelectedEvent,\n refreshEvents,\n };\n\n return (\n <EventContext.Provider value={contextValue}>\n {children}\n </EventContext.Provider>\n );\n}","/**\n * @file Providers Export\n * @package @jmruthers/pace-core\n * @module Providers\n * @since 0.1.0\n */\n\nexport * from './EventProvider';\nexport * from './OrganisationProvider';\nexport * from './UnifiedAuthProvider';\n\n// Individual providers for advanced usage\nexport * from './AuthProvider';\nexport * from './RBACProvider';\nexport * from './InactivityProvider';\n"],"mappings":"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","names":["error","events"]}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
usePublicPageContext
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-5EL3KHOQ.js";
|
|
4
4
|
import {
|
|
5
5
|
init_OrganisationProvider,
|
|
6
|
+
useOrganisations
|
|
7
|
+
} from "./chunk-COBPIXXQ.js";
|
|
8
|
+
import {
|
|
6
9
|
init_UnifiedAuthProvider,
|
|
7
|
-
useOrganisations,
|
|
8
10
|
useUnifiedAuth
|
|
9
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-6CR3MRZN.js";
|
|
10
12
|
|
|
11
13
|
// src/hooks/useOrganisationPermissions.ts
|
|
12
14
|
init_OrganisationProvider();
|
|
@@ -519,4 +521,4 @@ export {
|
|
|
519
521
|
generatePublicRoutePath,
|
|
520
522
|
extractEventCodeFromPath
|
|
521
523
|
};
|
|
522
|
-
//# sourceMappingURL=chunk-
|
|
524
|
+
//# sourceMappingURL=chunk-U6JDHVC2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useOrganisationPermissions.ts","../src/hooks/useOrganisationSecurity.ts","../src/hooks/public/usePublicEvent.ts","../src/hooks/public/usePublicRouteParams.ts"],"sourcesContent":["/**\n * @file useOrganisationPermissions Hook\n * @package @jmruthers/pace-core\n * @module Hooks/useOrganisationPermissions\n * @since 0.4.0\n *\n * Hook for managing organisation-specific permissions and role validation.\n * Provides secure access to user's role and permissions within organisations.\n *\n * @example\n * ```tsx\n * function OrganisationComponent() {\n * const { \n * isOrgAdmin, \n * canManageMembers,\n * userRole,\n * hasOrganisationAccess\n * } = useOrganisationPermissions();\n * \n * return (\n * <div>\n * {isOrgAdmin && <AdminPanel />}\n * {canManageMembers && <MemberManagement />}\n * <p>Your role: {userRole}</p>\n * </div>\n * );\n * }\n * \n * // For specific organisation\n * function MultiOrgComponent() {\n * const permissions = useOrganisationPermissions('org-123');\n * \n * if (!permissions.hasOrganisationAccess) {\n * return <div>No access to this organisation</div>;\n * }\n * \n * return <div>Role in org-123: {permissions.userRole}</div>;\n * }\n * ```\n *\n * @security\n * - Validates user membership in organisation\n * - Provides role-based permission checks\n * - Ensures secure access to organisation data\n * - Real-time permission validation\n */\n\nimport { useMemo } from 'react';\nimport { useOrganisations } from '../providers/OrganisationProvider';\nimport type { OrganisationRole, OrganisationPermission } from '../types/organisation';\n\nexport interface UseOrganisationPermissionsReturn {\n /** User's role in the organisation */\n userRole: OrganisationRole | 'no_access';\n \n /** Whether user has organisation admin role */\n isOrgAdmin: boolean;\n \n /** Whether user is a super admin */\n isSuperAdmin: boolean;\n \n /** Whether user can moderate content */\n canModerate: boolean;\n \n /** Whether user can manage members */\n canManageMembers: boolean;\n \n /** Whether user can manage organisation settings */\n canManageSettings: boolean;\n \n /** Whether user can manage events */\n canManageEvents: boolean;\n \n /** Whether user has any admin privileges */\n hasAdminPrivileges: boolean;\n \n /** Whether user has access to the organisation */\n hasOrganisationAccess: boolean;\n \n /** Check if user has specific permission */\n hasPermission: (permission: OrganisationPermission) => boolean;\n \n /** Get all permissions for the user */\n getAllPermissions: () => OrganisationPermission[];\n \n /** Organisation ID being checked */\n organisationId: string;\n}\n\n/**\n * Hook to access organisation-specific permissions and roles\n * \n * @param orgId - Optional organisation ID. Defaults to currently selected organisation\n * @returns Organisation permissions and role information\n */\nexport function useOrganisationPermissions(orgId?: string): UseOrganisationPermissionsReturn {\n const { \n selectedOrganisation, \n getUserRole, \n validateOrganisationAccess,\n ensureOrganisationContext\n } = useOrganisations();\n\n const organisationId = useMemo(() => {\n if (orgId) {\n return orgId;\n }\n try {\n const currentOrg = ensureOrganisationContext();\n return currentOrg.id;\n } catch {\n return '';\n }\n }, [orgId, ensureOrganisationContext]);\n\n const userRole = useMemo(() => {\n if (!organisationId) return 'no_access';\n return getUserRole(organisationId) as OrganisationRole | 'no_access';\n }, [organisationId, getUserRole]);\n\n const hasOrganisationAccess = useMemo(() => {\n if (!organisationId) return false;\n return validateOrganisationAccess(organisationId);\n }, [organisationId, validateOrganisationAccess]);\n\n const permissions = useMemo(() => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return {\n isOrgAdmin: false,\n isSuperAdmin: false,\n canModerate: false,\n canManageMembers: false,\n canManageSettings: false,\n canManageEvents: false,\n hasAdminPrivileges: false\n };\n }\n\n const isOrgAdmin = userRole === 'org_admin';\n const isLeader = userRole === 'leader';\n const isMember = userRole === 'member';\n const isSupporter = userRole === 'supporter';\n\n // Super admin is handled separately via user profile context\n // For now, we'll treat org_admin as having super admin privileges within the org\n const isSuperAdmin = isOrgAdmin; // This should be enhanced with actual super admin check\n\n return {\n isOrgAdmin,\n isSuperAdmin,\n canModerate: isSuperAdmin || isOrgAdmin || isLeader,\n canManageMembers: isSuperAdmin || isOrgAdmin,\n canManageSettings: isSuperAdmin || isOrgAdmin,\n canManageEvents: isSuperAdmin || isOrgAdmin || isLeader,\n hasAdminPrivileges: isSuperAdmin || isOrgAdmin\n };\n }, [hasOrganisationAccess, userRole]);\n\n const hasPermission = useMemo(() => {\n return (permission: OrganisationPermission): boolean => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return false;\n }\n\n // Super admin has all permissions (org_admin acts as super admin within org)\n if (userRole === 'org_admin' || permission === '*') {\n return true;\n }\n\n // Map permissions to roles using the defined permissions from organisation types\n const rolePermissions: Record<OrganisationRole, OrganisationPermission[]> = {\n supporter: ['view_basic'],\n member: ['view_basic', 'view_details'],\n leader: ['view_basic', 'view_details', 'moderate_content', 'manage_events'],\n org_admin: ['view_basic', 'view_details', 'moderate_content', 'manage_events', 'manage_members', 'manage_settings']\n };\n\n const userPermissions = rolePermissions[userRole as OrganisationRole] || [];\n return userPermissions.includes(permission) || userPermissions.includes('*');\n };\n }, [hasOrganisationAccess, userRole]);\n\n const getAllPermissions = useMemo(() => {\n return (): OrganisationPermission[] => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return [];\n }\n\n const rolePermissions: Record<OrganisationRole, OrganisationPermission[]> = {\n supporter: ['view_basic'],\n member: ['view_basic', 'view_details'],\n leader: ['view_basic', 'view_details', 'moderate_content', 'manage_events'],\n org_admin: ['view_basic', 'view_details', 'moderate_content', 'manage_events', 'manage_members', 'manage_settings']\n };\n\n return rolePermissions[userRole as OrganisationRole] || [];\n };\n }, [hasOrganisationAccess, userRole]);\n\n return {\n userRole,\n organisationId,\n hasOrganisationAccess,\n hasPermission,\n getAllPermissions,\n ...permissions\n };\n} ","/**\n * @file Organisation Security Hook\n * @package @jmruthers/pace-core\n * @module Hooks/OrganisationSecurity\n * @since 0.4.0\n *\n * Security-focused hook for organisation access validation and super admin functionality.\n * Provides utilities for validating user access to organisations and checking permissions.\n */\n\nimport { useCallback, useMemo } from 'react';\nimport { useUnifiedAuth } from '../providers/UnifiedAuthProvider';\nimport { useOrganisations } from '../providers/OrganisationProvider';\n// Legacy useRBAC hook removed - use new RBAC system instead\nimport type { OrganisationSecurityError, SuperAdminContext } from '../types/organisation';\nimport type { Permission } from '../rbac/types';\n\nexport interface OrganisationSecurityHook {\n // Super admin context\n superAdminContext: SuperAdminContext;\n \n // Access validation\n validateOrganisationAccess: (orgId: string) => Promise<boolean>;\n hasMinimumRole: (minRole: string, orgId?: string) => boolean;\n canAccessChildOrganisations: (orgId?: string) => boolean;\n \n // Permission checks\n hasPermission: (permission: string, orgId?: string) => Promise<boolean>;\n getUserPermissions: (orgId?: string) => Promise<string[]>;\n \n // Audit logging\n logOrganisationAccess: (action: string, details?: any) => Promise<void>;\n \n // Security utilities\n ensureOrganisationAccess: (orgId: string) => Promise<void>;\n validateUserAccess: (userId: string, orgId: string) => Promise<boolean>;\n}\n\nexport const useOrganisationSecurity = (): OrganisationSecurityHook => {\n const { user, session, supabase } = useUnifiedAuth();\n const { selectedOrganisation, getUserRole, validateOrganisationAccess: validateAccess } = useOrganisations();\n // Get global role directly from user metadata\n const globalRole = useMemo(() => {\n if (!user) return null;\n return user.app_metadata?.globalRole === 'super_admin' || \n user.user_metadata?.globalRole === 'super_admin' ? 'super_admin' : null;\n }, [user]);\n\n // Super admin context\n const superAdminContext = useMemo((): SuperAdminContext => {\n const isSuperAdmin = globalRole === 'super_admin';\n return {\n isSuperAdmin,\n hasGlobalAccess: isSuperAdmin,\n canManageAllOrganisations: isSuperAdmin\n };\n }, [globalRole]);\n\n // Validate organisation access with database check\n const validateOrganisationAccess = useCallback(async (orgId: string): Promise<boolean> => {\n if (!user || !session || !supabase) return false;\n \n try {\n // Super admin has access to all organisations\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n // Check organisation membership using consolidated rbac_organisation_roles table\n const { data, error } = await supabase\n .from('rbac_organisation_roles')\n .select('id')\n .eq('user_id', user.id)\n .eq('organisation_id', orgId)\n .eq('status', 'active')\n .is('revoked_at', null)\n .in('role', ['org_admin', 'leader', 'member']) // Only actual members, not supporters\n .single();\n\n if (error) {\n console.error('[useOrganisationSecurity] Error validating organisation access:', error);\n return false;\n }\n\n return !!data;\n } catch (error) {\n console.error('[useOrganisationSecurity] Exception validating organisation access:', error);\n return false;\n }\n }, [user, session, supabase, superAdminContext.isSuperAdmin]);\n\n // Check if user has minimum role\n const hasMinimumRole = useCallback((minRole: string, orgId?: string): boolean => {\n // Super admin has all roles\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId) return false;\n\n const userRole = getUserRole(targetOrgId);\n const roleHierarchy = ['supporter', 'member', 'leader', 'org_admin'];\n \n const userRoleIndex = roleHierarchy.indexOf(userRole);\n const minRoleIndex = roleHierarchy.indexOf(minRole);\n \n return userRoleIndex >= minRoleIndex;\n }, [selectedOrganisation, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Check if user can access child organisations\n const canAccessChildOrganisations = useCallback((orgId?: string): boolean => {\n // Super admin can access all organisations\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId) return false;\n\n const userRole = getUserRole(targetOrgId);\n return userRole === 'org_admin';\n }, [selectedOrganisation, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Check specific permission using the new RBAC system\n const hasPermission = useCallback(async (permission: string, orgId?: string): Promise<boolean> => {\n // Super admin has all permissions\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId || !user) return false;\n\n try {\n // Use the new RBAC system\n const { isPermitted } = await import('../rbac/api');\n \n const scope = {\n organisationId: targetOrgId,\n eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,\n appId: user.user_metadata?.appId || user.app_metadata?.appId,\n };\n\n return await isPermitted({\n userId: user.id,\n scope,\n permission: permission as Permission\n });\n } catch (error) {\n console.error('[useOrganisationSecurity] Exception checking permission:', error);\n return false;\n }\n }, [selectedOrganisation, user, superAdminContext.isSuperAdmin]);\n\n // Get user's permissions for organisation using the new RBAC system\n const getUserPermissions = useCallback(async (orgId?: string): Promise<string[]> => {\n // Super admin has all permissions\n if (superAdminContext.isSuperAdmin) {\n return ['*']; // All permissions\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId || !user) return [];\n\n try {\n // Use the new RBAC system\n const { getPermissionMap } = await import('../rbac/api');\n \n const scope = {\n organisationId: targetOrgId,\n eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,\n appId: user.user_metadata?.appId || user.app_metadata?.appId,\n };\n\n const permissionMap = await getPermissionMap({\n userId: user.id,\n scope\n });\n \n // Flatten all permissions from all pages\n const allPermissions = Object.values(permissionMap).flat();\n return [...new Set(allPermissions)]; // Remove duplicates\n } catch (error) {\n console.error('[useOrganisationSecurity] Exception getting user permissions:', error);\n return [];\n }\n }, [selectedOrganisation, user, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Log organisation access for audit using the new RBAC audit system\n const logOrganisationAccess = useCallback(async (action: string, details?: any): Promise<void> => {\n if (!user || !selectedOrganisation) return;\n\n try {\n // Use the new RBAC audit system - only if we have a valid organisation ID\n if (selectedOrganisation.id) {\n const { emitAuditEvent } = await import('../rbac/audit');\n \n await emitAuditEvent({\n type: 'permission_check',\n userId: user.id,\n organisationId: selectedOrganisation.id,\n permission: action,\n decision: true, // Assume access was granted if we're logging it\n source: 'api',\n duration_ms: 0, // No actual permission check performed here\n metadata: details || {}\n });\n }\n } catch (error) {\n console.error('[useOrganisationSecurity] Error logging organisation access:', error);\n }\n }, [user, selectedOrganisation]);\n\n // Ensure organisation access (throws if no access)\n const ensureOrganisationAccess = useCallback(async (orgId: string): Promise<void> => {\n const hasAccess = await validateOrganisationAccess(orgId);\n \n if (!hasAccess) {\n const error = new Error(`User does not have access to organisation ${orgId}`) as OrganisationSecurityError;\n error.name = 'OrganisationSecurityError';\n error.code = 'ACCESS_DENIED';\n error.organisationId = orgId;\n error.userId = user?.id;\n throw error;\n }\n }, [validateOrganisationAccess, user]);\n\n // Validate user access (for admin functions)\n const validateUserAccess = useCallback(async (userId: string, orgId: string): Promise<boolean> => {\n if (!supabase) return false;\n\n try {\n // Super admin can validate any user\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n // Regular users can only validate their own access\n if (userId !== user?.id) {\n return false;\n }\n\n return await validateOrganisationAccess(orgId);\n } catch (error) {\n console.error('[useOrganisationSecurity] Exception validating user access:', error);\n return false;\n }\n }, [supabase, superAdminContext.isSuperAdmin, user, validateOrganisationAccess]);\n\n return {\n superAdminContext,\n validateOrganisationAccess,\n hasMinimumRole,\n canAccessChildOrganisations,\n hasPermission,\n getUserPermissions,\n logOrganisationAccess,\n ensureOrganisationAccess,\n validateUserAccess\n };\n}; ","/**\n * @file Public Event Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Public\n * @since 1.0.0\n *\n * A React hook for accessing public event data without authentication.\n * Provides event information by event_code for public pages.\n *\n * Features:\n * - No authentication required\n * - Caching for performance\n * - Error handling and loading states\n * - TypeScript support\n * - Automatic refetch capabilities\n *\n * @example\n * ```tsx\n * import { usePublicEvent } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * const { eventCode } = usePublicRouteParams();\n * const { event, isLoading, error, refetch } = usePublicEvent(eventCode);\n *\n * if (isLoading) return <div>Loading event...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!event) return <div>Event not found</div>;\n *\n * return (\n * <div>\n * <h1>{event.event_name}</h1>\n * <p>Date: {event.event_date}</p>\n * <p>Venue: {event.event_venue}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @accessibility\n * - No direct accessibility concerns (hook)\n * - Enables accessible public event display\n * - Supports screen reader friendly loading states\n *\n * @security\n * - Only returns public-safe event data\n * - Validates event_code before querying\n * - No sensitive information exposed\n * - Rate limiting applied at database level\n *\n * @performance\n * - Built-in caching with TTL\n * - Minimal re-renders with stable references\n * - Lazy loading support\n * - Error boundary integration\n *\n * @dependencies\n * - React 18+ - Hooks and effects\n * - @supabase/supabase-js - Database integration\n * - Event types - Type definitions\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport { createClient } from '@supabase/supabase-js';\nimport type { Event } from '../../types/unified';\nimport type { Database } from '../../types/database';\nimport { usePublicPageContext } from '../../components/PublicLayout/PublicPageProvider';\n\n// Simple in-memory cache for public data\nconst publicDataCache = new Map<string, { data: any; timestamp: number; ttl: number }>();\n\nexport interface UsePublicEventReturn {\n /** The event data, null if not loaded or not found */\n event: Event | null;\n /** Whether the data is currently loading */\n isLoading: boolean;\n /** Any error that occurred during loading */\n error: Error | null;\n /** Function to manually refetch the data */\n refetch: () => Promise<void>;\n}\n\nexport interface UsePublicEventOptions {\n /** Cache TTL in milliseconds (default: 5 minutes) */\n cacheTtl?: number;\n /** Whether to enable caching (default: true) */\n enableCache?: boolean;\n}\n\n/**\n * Hook for accessing public event data by event_code\n * \n * This hook provides access to public event information without requiring\n * authentication. It includes caching, error handling, and loading states.\n * \n * @param eventCode - The event code to look up\n * @param options - Configuration options for caching and behavior\n * @returns Object containing event data, loading state, error, and refetch function\n */\nexport function usePublicEvent(\n eventCode: string,\n options: UsePublicEventOptions = {}\n): UsePublicEventReturn {\n const {\n cacheTtl = 5 * 60 * 1000, // 5 minutes\n enableCache = true\n } = options;\n\n const [event, setEvent] = useState<Event | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Get environment variables from public page context or fallback to direct access\n let environment: { supabaseUrl: string | null; supabaseKey: string | null };\n \n try {\n environment = usePublicPageContext().environment;\n } catch {\n // Fallback to direct environment variable access if not in PublicPageProvider\n environment = {\n supabaseUrl: (import.meta as any).env?.VITE_SUPABASE_URL || process.env.VITE_SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL || null,\n supabaseKey: (import.meta as any).env?.VITE_SUPABASE_ANON_KEY || process.env.VITE_SUPABASE_ANON_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || null\n };\n }\n \n // Create a simple Supabase client for public access\n const supabase = useMemo(() => {\n if (typeof window === 'undefined') return null;\n \n if (!environment.supabaseUrl || !environment.supabaseKey) {\n console.warn('[usePublicEvent] Missing Supabase environment variables. Please ensure VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY are set in your environment.');\n return null;\n }\n\n return createClient<Database>(environment.supabaseUrl, environment.supabaseKey);\n }, [environment.supabaseUrl, environment.supabaseKey]);\n\n const fetchEvent = useCallback(async (): Promise<void> => {\n if (!eventCode || !supabase) {\n setError(new Error('Invalid event code or Supabase client not available'));\n setIsLoading(false);\n return;\n }\n\n // Check cache first\n const cacheKey = `public_event_${eventCode}`;\n if (enableCache) {\n const cached = publicDataCache.get(cacheKey);\n if (cached && Date.now() - cached.timestamp < cached.ttl) {\n setEvent(cached.data);\n setIsLoading(false);\n setError(null);\n return;\n }\n }\n\n try {\n setIsLoading(true);\n setError(null);\n\n // Call the public event RPC function\n const { data, error: rpcError } = await (supabase as any).rpc('get_public_event_by_code', {\n event_code_param: eventCode\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to fetch event');\n }\n\n if (!data || data.length === 0 || !data[0]) {\n setEvent(null);\n setError(new Error('Event not found'));\n return;\n }\n\n const eventData = data[0];\n \n // Transform to Event type\n const transformedEvent: Event = {\n id: eventData.event_id,\n event_id: eventData.event_id,\n event_name: eventData.event_name,\n event_code: eventCode,\n event_date: eventData.event_date,\n event_venue: eventData.event_venue,\n event_participants: eventData.event_participants,\n event_logo: eventData.event_logo,\n event_colours: eventData.event_colours,\n organisation_id: eventData.organisation_id,\n is_visible: true,\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n // Legacy compatibility\n name: eventData.event_name,\n start_date: eventData.event_date\n };\n\n setEvent(transformedEvent);\n\n // Cache the result\n if (enableCache) {\n publicDataCache.set(cacheKey, {\n data: transformedEvent,\n timestamp: Date.now(),\n ttl: cacheTtl\n });\n }\n\n } catch (err) {\n console.error('[usePublicEvent] Error fetching event:', err);\n const error = err instanceof Error ? err : new Error('Unknown error occurred');\n setError(error);\n setEvent(null);\n } finally {\n setIsLoading(false);\n }\n }, [eventCode, supabase, cacheTtl, enableCache]);\n\n // Fetch event when eventCode changes\n useEffect(() => {\n fetchEvent();\n }, [fetchEvent]);\n\n const refetch = useCallback(async (): Promise<void> => {\n // Clear cache for this event\n if (enableCache) {\n const cacheKey = `public_event_${eventCode}`;\n publicDataCache.delete(cacheKey);\n }\n await fetchEvent();\n }, [fetchEvent, eventCode, enableCache]);\n\n return {\n event,\n isLoading,\n error,\n refetch\n };\n}\n\n/**\n * Clear all cached public event data\n * Useful for testing or when you need to force refresh all data\n */\nexport function clearPublicEventCache(): void {\n for (const [key] of publicDataCache) {\n if (key.startsWith('public_event_')) {\n publicDataCache.delete(key);\n }\n }\n}\n\n/**\n * Get cache statistics for debugging\n */\nexport function getPublicEventCacheStats(): { size: number; keys: string[] } {\n const keys = Array.from(publicDataCache.keys()).filter(key => key.startsWith('public_event_'));\n return {\n size: keys.length,\n keys\n };\n}\n","/**\n * @file Public Route Params Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Public\n * @since 1.0.0\n *\n * A React hook for extracting and validating public route parameters.\n * Provides event code extraction and validation for public pages.\n *\n * Features:\n * - URL parameter extraction\n * - Event code validation\n * - TypeScript support\n * - Error handling\n * - Route pattern support\n *\n * @example\n * ```tsx\n * import { usePublicRouteParams } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * const { eventCode, eventId, event, error, isLoading } = usePublicRouteParams();\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!event) return <div>Event not found</div>;\n *\n * return (\n * <div>\n * <h1>{event.event_name}</h1>\n * <p>Event Code: {eventCode}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @accessibility\n * - No direct accessibility concerns (hook)\n * - Enables accessible route parameter handling\n * - Supports screen reader friendly error states\n *\n * @security\n * - Validates event codes before processing\n * - Sanitizes URL parameters\n * - No sensitive information exposed\n * - Rate limiting applied at route level\n *\n * @performance\n * - Minimal re-renders with stable references\n * - Efficient parameter extraction\n * - Caching integration\n *\n * @dependencies\n * - React 18+ - Hooks and effects\n * - React Router - URL parameter extraction\n * - Event types - Type definitions\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useParams, useLocation } from 'react-router-dom';\nimport type { Event } from '../../types/unified';\nimport { usePublicEvent } from './usePublicEvent';\n\nexport interface UsePublicRouteParamsReturn {\n /** The event code from the URL */\n eventCode: string | null;\n /** The event ID (resolved from event code) */\n eventId: string | null;\n /** The full event object */\n event: Event | null;\n /** Whether the route parameters are being processed */\n isLoading: boolean;\n /** Any error that occurred during processing */\n error: Error | null;\n /** Function to manually refetch the event data */\n refetch: () => Promise<void>;\n}\n\ninterface UsePublicRouteParamsOptions {\n /** Whether to automatically fetch event data (default: true) */\n fetchEventData?: boolean;\n /** Custom event code parameter name (default: 'eventCode') */\n eventCodeParam?: string;\n /** Whether to validate event code format (default: true) */\n validateEventCode?: boolean;\n}\n\n/**\n * Validate event code format\n * Event codes should be alphanumeric with optional hyphens/underscores\n */\nfunction validateEventCodeFormat(eventCode: string): boolean {\n if (!eventCode || typeof eventCode !== 'string') return false;\n \n // Allow alphanumeric characters, hyphens, and underscores\n // Length between 3 and 50 characters\n const eventCodeRegex = /^[a-zA-Z0-9_-]{3,50}$/;\n return eventCodeRegex.test(eventCode);\n}\n\n/**\n * Hook for extracting and validating public route parameters\n * \n * This hook extracts event codes from URL parameters and optionally\n * fetches the corresponding event data. It provides validation and\n * error handling for public routes.\n * \n * @param options - Configuration options for behavior\n * @returns Object containing route parameters, event data, loading state, error, and refetch function\n */\nexport function usePublicRouteParams(\n options: UsePublicRouteParamsOptions = {}\n): UsePublicRouteParamsReturn {\n const {\n fetchEventData = true,\n eventCodeParam = 'eventCode',\n validateEventCode = true\n } = options;\n\n const params = useParams();\n const location = useLocation();\n \n const [error, setError] = useState<Error | null>(null);\n\n // Extract event code from URL parameters\n const eventCode = useMemo(() => {\n const code = params[eventCodeParam] as string;\n \n if (!code) {\n // Don't set error immediately - let the component handle missing eventCode gracefully\n return null;\n }\n\n // Validate event code format if requested\n if (validateEventCode && !validateEventCodeFormat(code)) {\n setError(new Error(`Invalid event code format: ${code}`));\n return null;\n }\n\n setError(null);\n return code;\n }, [params, eventCodeParam, validateEventCode]);\n\n // Use the public event hook to fetch event data\n const {\n event,\n isLoading: eventLoading,\n error: eventError,\n refetch: refetchEvent\n } = usePublicEvent(eventCode || '', {\n enableCache: true,\n cacheTtl: 5 * 60 * 1000 // 5 minutes\n });\n\n // Determine if we should show loading state\n const isLoading = useMemo(() => {\n if (!fetchEventData) return false;\n return eventLoading;\n }, [fetchEventData, eventLoading]);\n\n // Determine the final error state\n const finalError = useMemo(() => {\n if (error) return error;\n if (eventError) return eventError;\n return null;\n }, [error, eventError]);\n\n // Extract event ID from event data\n const eventId = useMemo(() => {\n if (!event) return null;\n return event.event_id || event.id;\n }, [event]);\n\n // Refetch function\n const refetch = useCallback(async (): Promise<void> => {\n if (!fetchEventData) return;\n await refetchEvent();\n }, [fetchEventData, refetchEvent]);\n\n // Log route access for debugging\n useEffect(() => {\n if (eventCode && event) {\n console.log('[usePublicRouteParams] Public route accessed:', {\n eventCode,\n eventId: event.event_id,\n eventName: event.event_name,\n path: location.pathname\n });\n }\n }, [eventCode, event, location.pathname]);\n\n return {\n eventCode,\n eventId,\n event: fetchEventData ? event : null,\n isLoading,\n error: finalError,\n refetch\n };\n}\n\n/**\n * Hook for extracting just the event code without fetching event data\n * Useful when you only need the event code and will fetch data separately\n */\nexport function usePublicEventCode(\n eventCodeParam: string = 'eventCode'\n): { eventCode: string | null; error: Error | null } {\n const params = useParams();\n \n const eventCode = useMemo(() => {\n const code = params[eventCodeParam] as string;\n \n if (!code) {\n return null;\n }\n\n // Validate event code format\n if (!validateEventCodeFormat(code)) {\n return null;\n }\n\n return code;\n }, [params, eventCodeParam]);\n\n const error = useMemo(() => {\n if (!eventCode) {\n return new Error(`Event code parameter '${eventCodeParam}' not found or invalid`);\n }\n return null;\n }, [eventCode, eventCodeParam]);\n\n return {\n eventCode,\n error\n };\n}\n\n/**\n * Utility function to generate public route paths\n */\nexport function generatePublicRoutePath(\n eventCode: string,\n pageName: string = 'index'\n): string {\n if (!eventCode || !validateEventCodeFormat(eventCode)) {\n throw new Error('Invalid event code for route generation');\n }\n \n return `/public/event/${eventCode}/${pageName}`;\n}\n\n/**\n * Utility function to extract event code from a public route path\n */\nexport function extractEventCodeFromPath(path: string): string | null {\n const match = path.match(/^\\/public\\/event\\/([a-zA-Z0-9_-]{3,50})(?:\\/.*)?$/);\n return match ? match[1] : null;\n}\n"],"mappings":"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","names":["useMemo","useCallback","useMemo","useMemo","useCallback","error","useState","useEffect","useCallback","useMemo","useState","useMemo","useCallback","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useOrganisationPermissions.ts","../src/hooks/useOrganisationSecurity.ts","../src/hooks/public/usePublicEvent.ts","../src/hooks/public/usePublicRouteParams.ts"],"sourcesContent":["/**\n * @file useOrganisationPermissions Hook\n * @package @jmruthers/pace-core\n * @module Hooks/useOrganisationPermissions\n * @since 0.4.0\n *\n * Hook for managing organisation-specific permissions and role validation.\n * Provides secure access to user's role and permissions within organisations.\n *\n * @example\n * ```tsx\n * function OrganisationComponent() {\n * const { \n * isOrgAdmin, \n * canManageMembers,\n * userRole,\n * hasOrganisationAccess\n * } = useOrganisationPermissions();\n * \n * return (\n * <div>\n * {isOrgAdmin && <AdminPanel />}\n * {canManageMembers && <MemberManagement />}\n * <p>Your role: {userRole}</p>\n * </div>\n * );\n * }\n * \n * // For specific organisation\n * function MultiOrgComponent() {\n * const permissions = useOrganisationPermissions('org-123');\n * \n * if (!permissions.hasOrganisationAccess) {\n * return <div>No access to this organisation</div>;\n * }\n * \n * return <div>Role in org-123: {permissions.userRole}</div>;\n * }\n * ```\n *\n * @security\n * - Validates user membership in organisation\n * - Provides role-based permission checks\n * - Ensures secure access to organisation data\n * - Real-time permission validation\n */\n\nimport { useMemo } from 'react';\nimport { useOrganisations } from '../providers/OrganisationProvider';\nimport type { OrganisationRole, OrganisationPermission } from '../types/organisation';\n\nexport interface UseOrganisationPermissionsReturn {\n /** User's role in the organisation */\n userRole: OrganisationRole | 'no_access';\n \n /** Whether user has organisation admin role */\n isOrgAdmin: boolean;\n \n /** Whether user is a super admin */\n isSuperAdmin: boolean;\n \n /** Whether user can moderate content */\n canModerate: boolean;\n \n /** Whether user can manage members */\n canManageMembers: boolean;\n \n /** Whether user can manage organisation settings */\n canManageSettings: boolean;\n \n /** Whether user can manage events */\n canManageEvents: boolean;\n \n /** Whether user has any admin privileges */\n hasAdminPrivileges: boolean;\n \n /** Whether user has access to the organisation */\n hasOrganisationAccess: boolean;\n \n /** Check if user has specific permission */\n hasPermission: (permission: OrganisationPermission) => boolean;\n \n /** Get all permissions for the user */\n getAllPermissions: () => OrganisationPermission[];\n \n /** Organisation ID being checked */\n organisationId: string;\n}\n\n/**\n * Hook to access organisation-specific permissions and roles\n * \n * @param orgId - Optional organisation ID. Defaults to currently selected organisation\n * @returns Organisation permissions and role information\n */\nexport function useOrganisationPermissions(orgId?: string): UseOrganisationPermissionsReturn {\n const { \n selectedOrganisation, \n getUserRole, \n validateOrganisationAccess,\n ensureOrganisationContext\n } = useOrganisations();\n\n const organisationId = useMemo(() => {\n if (orgId) {\n return orgId;\n }\n try {\n const currentOrg = ensureOrganisationContext();\n return currentOrg.id;\n } catch {\n return '';\n }\n }, [orgId, ensureOrganisationContext]);\n\n const userRole = useMemo(() => {\n if (!organisationId) return 'no_access';\n return getUserRole(organisationId) as OrganisationRole | 'no_access';\n }, [organisationId, getUserRole]);\n\n const hasOrganisationAccess = useMemo(() => {\n if (!organisationId) return false;\n return validateOrganisationAccess(organisationId);\n }, [organisationId, validateOrganisationAccess]);\n\n const permissions = useMemo(() => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return {\n isOrgAdmin: false,\n isSuperAdmin: false,\n canModerate: false,\n canManageMembers: false,\n canManageSettings: false,\n canManageEvents: false,\n hasAdminPrivileges: false\n };\n }\n\n const isOrgAdmin = userRole === 'org_admin';\n const isLeader = userRole === 'leader';\n const isMember = userRole === 'member';\n const isSupporter = userRole === 'supporter';\n\n // Super admin is handled separately via user profile context\n // For now, we'll treat org_admin as having super admin privileges within the org\n const isSuperAdmin = isOrgAdmin; // This should be enhanced with actual super admin check\n\n return {\n isOrgAdmin,\n isSuperAdmin,\n canModerate: isSuperAdmin || isOrgAdmin || isLeader,\n canManageMembers: isSuperAdmin || isOrgAdmin,\n canManageSettings: isSuperAdmin || isOrgAdmin,\n canManageEvents: isSuperAdmin || isOrgAdmin || isLeader,\n hasAdminPrivileges: isSuperAdmin || isOrgAdmin\n };\n }, [hasOrganisationAccess, userRole]);\n\n const hasPermission = useMemo(() => {\n return (permission: OrganisationPermission): boolean => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return false;\n }\n\n // Super admin has all permissions (org_admin acts as super admin within org)\n if (userRole === 'org_admin' || permission === '*') {\n return true;\n }\n\n // Map permissions to roles using the defined permissions from organisation types\n const rolePermissions: Record<OrganisationRole, OrganisationPermission[]> = {\n supporter: ['view_basic'],\n member: ['view_basic', 'view_details'],\n leader: ['view_basic', 'view_details', 'moderate_content', 'manage_events'],\n org_admin: ['view_basic', 'view_details', 'moderate_content', 'manage_events', 'manage_members', 'manage_settings']\n };\n\n const userPermissions = rolePermissions[userRole as OrganisationRole] || [];\n return userPermissions.includes(permission) || userPermissions.includes('*');\n };\n }, [hasOrganisationAccess, userRole]);\n\n const getAllPermissions = useMemo(() => {\n return (): OrganisationPermission[] => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return [];\n }\n\n const rolePermissions: Record<OrganisationRole, OrganisationPermission[]> = {\n supporter: ['view_basic'],\n member: ['view_basic', 'view_details'],\n leader: ['view_basic', 'view_details', 'moderate_content', 'manage_events'],\n org_admin: ['view_basic', 'view_details', 'moderate_content', 'manage_events', 'manage_members', 'manage_settings']\n };\n\n return rolePermissions[userRole as OrganisationRole] || [];\n };\n }, [hasOrganisationAccess, userRole]);\n\n return {\n userRole,\n organisationId,\n hasOrganisationAccess,\n hasPermission,\n getAllPermissions,\n ...permissions\n };\n} ","/**\n * @file Organisation Security Hook\n * @package @jmruthers/pace-core\n * @module Hooks/OrganisationSecurity\n * @since 0.4.0\n *\n * Security-focused hook for organisation access validation and super admin functionality.\n * Provides utilities for validating user access to organisations and checking permissions.\n */\n\nimport { useCallback, useMemo } from 'react';\nimport { useUnifiedAuth } from '../providers/UnifiedAuthProvider';\nimport { useOrganisations } from '../providers/OrganisationProvider';\n// Legacy useRBAC hook removed - use new RBAC system instead\nimport type { OrganisationSecurityError, SuperAdminContext } from '../types/organisation';\nimport type { Permission } from '../rbac/types';\n\nexport interface OrganisationSecurityHook {\n // Super admin context\n superAdminContext: SuperAdminContext;\n \n // Access validation\n validateOrganisationAccess: (orgId: string) => Promise<boolean>;\n hasMinimumRole: (minRole: string, orgId?: string) => boolean;\n canAccessChildOrganisations: (orgId?: string) => boolean;\n \n // Permission checks\n hasPermission: (permission: string, orgId?: string) => Promise<boolean>;\n getUserPermissions: (orgId?: string) => Promise<string[]>;\n \n // Audit logging\n logOrganisationAccess: (action: string, details?: any) => Promise<void>;\n \n // Security utilities\n ensureOrganisationAccess: (orgId: string) => Promise<void>;\n validateUserAccess: (userId: string, orgId: string) => Promise<boolean>;\n}\n\nexport const useOrganisationSecurity = (): OrganisationSecurityHook => {\n const { user, session, supabase } = useUnifiedAuth();\n const { selectedOrganisation, getUserRole, validateOrganisationAccess: validateAccess } = useOrganisations();\n // Get global role directly from user metadata\n const globalRole = useMemo(() => {\n if (!user) return null;\n return user.app_metadata?.globalRole === 'super_admin' || \n user.user_metadata?.globalRole === 'super_admin' ? 'super_admin' : null;\n }, [user]);\n\n // Super admin context\n const superAdminContext = useMemo((): SuperAdminContext => {\n const isSuperAdmin = globalRole === 'super_admin';\n return {\n isSuperAdmin,\n hasGlobalAccess: isSuperAdmin,\n canManageAllOrganisations: isSuperAdmin\n };\n }, [globalRole]);\n\n // Validate organisation access with database check\n const validateOrganisationAccess = useCallback(async (orgId: string): Promise<boolean> => {\n if (!user || !session || !supabase) return false;\n \n try {\n // Super admin has access to all organisations\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n // Check organisation membership using consolidated rbac_organisation_roles table\n const { data, error } = await supabase\n .from('rbac_organisation_roles')\n .select('id')\n .eq('user_id', user.id)\n .eq('organisation_id', orgId)\n .eq('status', 'active')\n .is('revoked_at', null)\n .in('role', ['org_admin', 'leader', 'member']) // Only actual members, not supporters\n .single();\n\n if (error) {\n console.error('[useOrganisationSecurity] Error validating organisation access:', error);\n return false;\n }\n\n return !!data;\n } catch (error) {\n console.error('[useOrganisationSecurity] Exception validating organisation access:', error);\n return false;\n }\n }, [user, session, supabase, superAdminContext.isSuperAdmin]);\n\n // Check if user has minimum role\n const hasMinimumRole = useCallback((minRole: string, orgId?: string): boolean => {\n // Super admin has all roles\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId) return false;\n\n const userRole = getUserRole(targetOrgId);\n const roleHierarchy = ['supporter', 'member', 'leader', 'org_admin'];\n \n const userRoleIndex = roleHierarchy.indexOf(userRole);\n const minRoleIndex = roleHierarchy.indexOf(minRole);\n \n return userRoleIndex >= minRoleIndex;\n }, [selectedOrganisation, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Check if user can access child organisations\n const canAccessChildOrganisations = useCallback((orgId?: string): boolean => {\n // Super admin can access all organisations\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId) return false;\n\n const userRole = getUserRole(targetOrgId);\n return userRole === 'org_admin';\n }, [selectedOrganisation, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Check specific permission using the new RBAC system\n const hasPermission = useCallback(async (permission: string, orgId?: string): Promise<boolean> => {\n // Super admin has all permissions\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId || !user) return false;\n\n try {\n // Use the new RBAC system\n const { isPermitted } = await import('../rbac/api');\n \n const scope = {\n organisationId: targetOrgId,\n eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,\n appId: user.user_metadata?.appId || user.app_metadata?.appId,\n };\n\n return await isPermitted({\n userId: user.id,\n scope,\n permission: permission as Permission\n });\n } catch (error) {\n console.error('[useOrganisationSecurity] Exception checking permission:', error);\n return false;\n }\n }, [selectedOrganisation, user, superAdminContext.isSuperAdmin]);\n\n // Get user's permissions for organisation using the new RBAC system\n const getUserPermissions = useCallback(async (orgId?: string): Promise<string[]> => {\n // Super admin has all permissions\n if (superAdminContext.isSuperAdmin) {\n return ['*']; // All permissions\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId || !user) return [];\n\n try {\n // Use the new RBAC system\n const { getPermissionMap } = await import('../rbac/api');\n \n const scope = {\n organisationId: targetOrgId,\n eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,\n appId: user.user_metadata?.appId || user.app_metadata?.appId,\n };\n\n const permissionMap = await getPermissionMap({\n userId: user.id,\n scope\n });\n \n // Flatten all permissions from all pages\n const allPermissions = Object.values(permissionMap).flat();\n return [...new Set(allPermissions)]; // Remove duplicates\n } catch (error) {\n console.error('[useOrganisationSecurity] Exception getting user permissions:', error);\n return [];\n }\n }, [selectedOrganisation, user, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Log organisation access for audit using the new RBAC audit system\n const logOrganisationAccess = useCallback(async (action: string, details?: any): Promise<void> => {\n if (!user || !selectedOrganisation) return;\n\n try {\n // Use the new RBAC audit system - only if we have a valid organisation ID\n if (selectedOrganisation.id) {\n const { emitAuditEvent } = await import('../rbac/audit');\n \n await emitAuditEvent({\n type: 'permission_check',\n userId: user.id,\n organisationId: selectedOrganisation.id,\n permission: action,\n decision: true, // Assume access was granted if we're logging it\n source: 'api',\n duration_ms: 0, // No actual permission check performed here\n metadata: details || {}\n });\n }\n } catch (error) {\n console.error('[useOrganisationSecurity] Error logging organisation access:', error);\n }\n }, [user, selectedOrganisation]);\n\n // Ensure organisation access (throws if no access)\n const ensureOrganisationAccess = useCallback(async (orgId: string): Promise<void> => {\n const hasAccess = await validateOrganisationAccess(orgId);\n \n if (!hasAccess) {\n const error = new Error(`User does not have access to organisation ${orgId}`) as OrganisationSecurityError;\n error.name = 'OrganisationSecurityError';\n error.code = 'ACCESS_DENIED';\n error.organisationId = orgId;\n error.userId = user?.id;\n throw error;\n }\n }, [validateOrganisationAccess, user]);\n\n // Validate user access (for admin functions)\n const validateUserAccess = useCallback(async (userId: string, orgId: string): Promise<boolean> => {\n if (!supabase) return false;\n\n try {\n // Super admin can validate any user\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n // Regular users can only validate their own access\n if (userId !== user?.id) {\n return false;\n }\n\n return await validateOrganisationAccess(orgId);\n } catch (error) {\n console.error('[useOrganisationSecurity] Exception validating user access:', error);\n return false;\n }\n }, [supabase, superAdminContext.isSuperAdmin, user, validateOrganisationAccess]);\n\n return {\n superAdminContext,\n validateOrganisationAccess,\n hasMinimumRole,\n canAccessChildOrganisations,\n hasPermission,\n getUserPermissions,\n logOrganisationAccess,\n ensureOrganisationAccess,\n validateUserAccess\n };\n}; ","/**\n * @file Public Event Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Public\n * @since 1.0.0\n *\n * A React hook for accessing public event data without authentication.\n * Provides event information by event_code for public pages.\n *\n * Features:\n * - No authentication required\n * - Caching for performance\n * - Error handling and loading states\n * - TypeScript support\n * - Automatic refetch capabilities\n *\n * @example\n * ```tsx\n * import { usePublicEvent } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * const { eventCode } = usePublicRouteParams();\n * const { event, isLoading, error, refetch } = usePublicEvent(eventCode);\n *\n * if (isLoading) return <div>Loading event...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!event) return <div>Event not found</div>;\n *\n * return (\n * <div>\n * <h1>{event.event_name}</h1>\n * <p>Date: {event.event_date}</p>\n * <p>Venue: {event.event_venue}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @accessibility\n * - No direct accessibility concerns (hook)\n * - Enables accessible public event display\n * - Supports screen reader friendly loading states\n *\n * @security\n * - Only returns public-safe event data\n * - Validates event_code before querying\n * - No sensitive information exposed\n * - Rate limiting applied at database level\n *\n * @performance\n * - Built-in caching with TTL\n * - Minimal re-renders with stable references\n * - Lazy loading support\n * - Error boundary integration\n *\n * @dependencies\n * - React 18+ - Hooks and effects\n * - @supabase/supabase-js - Database integration\n * - Event types - Type definitions\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport { createClient } from '@supabase/supabase-js';\nimport type { Event } from '../../types/unified';\nimport type { Database } from '../../types/database';\nimport { usePublicPageContext } from '../../components/PublicLayout/PublicPageProvider';\n\n// Simple in-memory cache for public data\nconst publicDataCache = new Map<string, { data: any; timestamp: number; ttl: number }>();\n\nexport interface UsePublicEventReturn {\n /** The event data, null if not loaded or not found */\n event: Event | null;\n /** Whether the data is currently loading */\n isLoading: boolean;\n /** Any error that occurred during loading */\n error: Error | null;\n /** Function to manually refetch the data */\n refetch: () => Promise<void>;\n}\n\nexport interface UsePublicEventOptions {\n /** Cache TTL in milliseconds (default: 5 minutes) */\n cacheTtl?: number;\n /** Whether to enable caching (default: true) */\n enableCache?: boolean;\n}\n\n/**\n * Hook for accessing public event data by event_code\n * \n * This hook provides access to public event information without requiring\n * authentication. It includes caching, error handling, and loading states.\n * \n * @param eventCode - The event code to look up\n * @param options - Configuration options for caching and behavior\n * @returns Object containing event data, loading state, error, and refetch function\n */\nexport function usePublicEvent(\n eventCode: string,\n options: UsePublicEventOptions = {}\n): UsePublicEventReturn {\n const {\n cacheTtl = 5 * 60 * 1000, // 5 minutes\n enableCache = true\n } = options;\n\n const [event, setEvent] = useState<Event | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Get environment variables from public page context or fallback to direct access\n let environment: { supabaseUrl: string | null; supabaseKey: string | null };\n \n try {\n environment = usePublicPageContext().environment;\n } catch {\n // Fallback to direct environment variable access if not in PublicPageProvider\n environment = {\n supabaseUrl: (import.meta as any).env?.VITE_SUPABASE_URL || process.env.VITE_SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL || null,\n supabaseKey: (import.meta as any).env?.VITE_SUPABASE_ANON_KEY || process.env.VITE_SUPABASE_ANON_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || null\n };\n }\n \n // Create a simple Supabase client for public access\n const supabase = useMemo(() => {\n if (typeof window === 'undefined') return null;\n \n if (!environment.supabaseUrl || !environment.supabaseKey) {\n console.warn('[usePublicEvent] Missing Supabase environment variables. Please ensure VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY are set in your environment.');\n return null;\n }\n\n return createClient<Database>(environment.supabaseUrl, environment.supabaseKey);\n }, [environment.supabaseUrl, environment.supabaseKey]);\n\n const fetchEvent = useCallback(async (): Promise<void> => {\n if (!eventCode || !supabase) {\n setError(new Error('Invalid event code or Supabase client not available'));\n setIsLoading(false);\n return;\n }\n\n // Check cache first\n const cacheKey = `public_event_${eventCode}`;\n if (enableCache) {\n const cached = publicDataCache.get(cacheKey);\n if (cached && Date.now() - cached.timestamp < cached.ttl) {\n setEvent(cached.data);\n setIsLoading(false);\n setError(null);\n return;\n }\n }\n\n try {\n setIsLoading(true);\n setError(null);\n\n // Call the public event RPC function\n const { data, error: rpcError } = await (supabase as any).rpc('get_public_event_by_code', {\n event_code_param: eventCode\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to fetch event');\n }\n\n if (!data || data.length === 0 || !data[0]) {\n setEvent(null);\n setError(new Error('Event not found'));\n return;\n }\n\n const eventData = data[0];\n \n // Transform to Event type\n const transformedEvent: Event = {\n id: eventData.event_id,\n event_id: eventData.event_id,\n event_name: eventData.event_name,\n event_code: eventCode,\n event_date: eventData.event_date,\n event_venue: eventData.event_venue,\n event_participants: eventData.event_participants,\n event_logo: eventData.event_logo,\n event_colours: eventData.event_colours,\n organisation_id: eventData.organisation_id,\n is_visible: true,\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n // Legacy compatibility\n name: eventData.event_name,\n start_date: eventData.event_date\n };\n\n setEvent(transformedEvent);\n\n // Cache the result\n if (enableCache) {\n publicDataCache.set(cacheKey, {\n data: transformedEvent,\n timestamp: Date.now(),\n ttl: cacheTtl\n });\n }\n\n } catch (err) {\n console.error('[usePublicEvent] Error fetching event:', err);\n const error = err instanceof Error ? err : new Error('Unknown error occurred');\n setError(error);\n setEvent(null);\n } finally {\n setIsLoading(false);\n }\n }, [eventCode, supabase, cacheTtl, enableCache]);\n\n // Fetch event when eventCode changes\n useEffect(() => {\n fetchEvent();\n }, [fetchEvent]);\n\n const refetch = useCallback(async (): Promise<void> => {\n // Clear cache for this event\n if (enableCache) {\n const cacheKey = `public_event_${eventCode}`;\n publicDataCache.delete(cacheKey);\n }\n await fetchEvent();\n }, [fetchEvent, eventCode, enableCache]);\n\n return {\n event,\n isLoading,\n error,\n refetch\n };\n}\n\n/**\n * Clear all cached public event data\n * Useful for testing or when you need to force refresh all data\n */\nexport function clearPublicEventCache(): void {\n for (const [key] of publicDataCache) {\n if (key.startsWith('public_event_')) {\n publicDataCache.delete(key);\n }\n }\n}\n\n/**\n * Get cache statistics for debugging\n */\nexport function getPublicEventCacheStats(): { size: number; keys: string[] } {\n const keys = Array.from(publicDataCache.keys()).filter(key => key.startsWith('public_event_'));\n return {\n size: keys.length,\n keys\n };\n}\n","/**\n * @file Public Route Params Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Public\n * @since 1.0.0\n *\n * A React hook for extracting and validating public route parameters.\n * Provides event code extraction and validation for public pages.\n *\n * Features:\n * - URL parameter extraction\n * - Event code validation\n * - TypeScript support\n * - Error handling\n * - Route pattern support\n *\n * @example\n * ```tsx\n * import { usePublicRouteParams } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * const { eventCode, eventId, event, error, isLoading } = usePublicRouteParams();\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!event) return <div>Event not found</div>;\n *\n * return (\n * <div>\n * <h1>{event.event_name}</h1>\n * <p>Event Code: {eventCode}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @accessibility\n * - No direct accessibility concerns (hook)\n * - Enables accessible route parameter handling\n * - Supports screen reader friendly error states\n *\n * @security\n * - Validates event codes before processing\n * - Sanitizes URL parameters\n * - No sensitive information exposed\n * - Rate limiting applied at route level\n *\n * @performance\n * - Minimal re-renders with stable references\n * - Efficient parameter extraction\n * - Caching integration\n *\n * @dependencies\n * - React 18+ - Hooks and effects\n * - React Router - URL parameter extraction\n * - Event types - Type definitions\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useParams, useLocation } from 'react-router-dom';\nimport type { Event } from '../../types/unified';\nimport { usePublicEvent } from './usePublicEvent';\n\nexport interface UsePublicRouteParamsReturn {\n /** The event code from the URL */\n eventCode: string | null;\n /** The event ID (resolved from event code) */\n eventId: string | null;\n /** The full event object */\n event: Event | null;\n /** Whether the route parameters are being processed */\n isLoading: boolean;\n /** Any error that occurred during processing */\n error: Error | null;\n /** Function to manually refetch the event data */\n refetch: () => Promise<void>;\n}\n\ninterface UsePublicRouteParamsOptions {\n /** Whether to automatically fetch event data (default: true) */\n fetchEventData?: boolean;\n /** Custom event code parameter name (default: 'eventCode') */\n eventCodeParam?: string;\n /** Whether to validate event code format (default: true) */\n validateEventCode?: boolean;\n}\n\n/**\n * Validate event code format\n * Event codes should be alphanumeric with optional hyphens/underscores\n */\nfunction validateEventCodeFormat(eventCode: string): boolean {\n if (!eventCode || typeof eventCode !== 'string') return false;\n \n // Allow alphanumeric characters, hyphens, and underscores\n // Length between 3 and 50 characters\n const eventCodeRegex = /^[a-zA-Z0-9_-]{3,50}$/;\n return eventCodeRegex.test(eventCode);\n}\n\n/**\n * Hook for extracting and validating public route parameters\n * \n * This hook extracts event codes from URL parameters and optionally\n * fetches the corresponding event data. It provides validation and\n * error handling for public routes.\n * \n * @param options - Configuration options for behavior\n * @returns Object containing route parameters, event data, loading state, error, and refetch function\n */\nexport function usePublicRouteParams(\n options: UsePublicRouteParamsOptions = {}\n): UsePublicRouteParamsReturn {\n const {\n fetchEventData = true,\n eventCodeParam = 'eventCode',\n validateEventCode = true\n } = options;\n\n const params = useParams();\n const location = useLocation();\n \n const [error, setError] = useState<Error | null>(null);\n\n // Extract event code from URL parameters\n const eventCode = useMemo(() => {\n const code = params[eventCodeParam] as string;\n \n if (!code) {\n // Don't set error immediately - let the component handle missing eventCode gracefully\n return null;\n }\n\n // Validate event code format if requested\n if (validateEventCode && !validateEventCodeFormat(code)) {\n setError(new Error(`Invalid event code format: ${code}`));\n return null;\n }\n\n setError(null);\n return code;\n }, [params, eventCodeParam, validateEventCode]);\n\n // Use the public event hook to fetch event data\n const {\n event,\n isLoading: eventLoading,\n error: eventError,\n refetch: refetchEvent\n } = usePublicEvent(eventCode || '', {\n enableCache: true,\n cacheTtl: 5 * 60 * 1000 // 5 minutes\n });\n\n // Determine if we should show loading state\n const isLoading = useMemo(() => {\n if (!fetchEventData) return false;\n return eventLoading;\n }, [fetchEventData, eventLoading]);\n\n // Determine the final error state\n const finalError = useMemo(() => {\n if (error) return error;\n if (eventError) return eventError;\n return null;\n }, [error, eventError]);\n\n // Extract event ID from event data\n const eventId = useMemo(() => {\n if (!event) return null;\n return event.event_id || event.id;\n }, [event]);\n\n // Refetch function\n const refetch = useCallback(async (): Promise<void> => {\n if (!fetchEventData) return;\n await refetchEvent();\n }, [fetchEventData, refetchEvent]);\n\n // Log route access for debugging\n useEffect(() => {\n if (eventCode && event) {\n console.log('[usePublicRouteParams] Public route accessed:', {\n eventCode,\n eventId: event.event_id,\n eventName: event.event_name,\n path: location.pathname\n });\n }\n }, [eventCode, event, location.pathname]);\n\n return {\n eventCode,\n eventId,\n event: fetchEventData ? event : null,\n isLoading,\n error: finalError,\n refetch\n };\n}\n\n/**\n * Hook for extracting just the event code without fetching event data\n * Useful when you only need the event code and will fetch data separately\n */\nexport function usePublicEventCode(\n eventCodeParam: string = 'eventCode'\n): { eventCode: string | null; error: Error | null } {\n const params = useParams();\n \n const eventCode = useMemo(() => {\n const code = params[eventCodeParam] as string;\n \n if (!code) {\n return null;\n }\n\n // Validate event code format\n if (!validateEventCodeFormat(code)) {\n return null;\n }\n\n return code;\n }, [params, eventCodeParam]);\n\n const error = useMemo(() => {\n if (!eventCode) {\n return new Error(`Event code parameter '${eventCodeParam}' not found or invalid`);\n }\n return null;\n }, [eventCode, eventCodeParam]);\n\n return {\n eventCode,\n error\n };\n}\n\n/**\n * Utility function to generate public route paths\n */\nexport function generatePublicRoutePath(\n eventCode: string,\n pageName: string = 'index'\n): string {\n if (!eventCode || !validateEventCodeFormat(eventCode)) {\n throw new Error('Invalid event code for route generation');\n }\n \n return `/public/event/${eventCode}/${pageName}`;\n}\n\n/**\n * Utility function to extract event code from a public route path\n */\nexport function extractEventCodeFromPath(path: string): string | null {\n const match = path.match(/^\\/public\\/event\\/([a-zA-Z0-9_-]{3,50})(?:\\/.*)?$/);\n return match ? match[1] : null;\n}\n"],"mappings":"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","names":["useMemo","useCallback","useMemo","useMemo","useCallback","error","useState","useEffect","useCallback","useMemo","useState","useMemo","useCallback","useEffect"]}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
init_OrganisationProvider,
|
|
3
|
+
useOrganisations
|
|
4
|
+
} from "./chunk-COBPIXXQ.js";
|
|
5
|
+
import {
|
|
3
6
|
init_UnifiedAuthProvider,
|
|
4
|
-
useOrganisations,
|
|
5
7
|
useUnifiedAuth
|
|
6
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-6CR3MRZN.js";
|
|
7
9
|
import {
|
|
8
10
|
init_organisationContext,
|
|
9
11
|
setOrganisationContext
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-OEGRKULD.js";
|
|
11
13
|
|
|
12
14
|
// src/hooks/useSecureDataAccess.ts
|
|
13
15
|
init_UnifiedAuthProvider();
|
|
@@ -379,4 +381,4 @@ function useSecureDataAccess() {
|
|
|
379
381
|
export {
|
|
380
382
|
useSecureDataAccess
|
|
381
383
|
};
|
|
382
|
-
//# sourceMappingURL=chunk-
|
|
384
|
+
//# sourceMappingURL=chunk-XJK2J4N6.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useSecureDataAccess.ts"],"sourcesContent":["/**\n * @file useSecureDataAccess Hook\n * @package @jmruthers/pace-core\n * @module Hooks/useSecureDataAccess\n * @since 0.4.0\n *\n * Hook for secure database operations with mandatory organisation context.\n * Ensures all data access is properly scoped to the user's current organisation.\n *\n * @example\n * ```tsx\n * function DataComponent() {\n * const { secureQuery, secureInsert, secureUpdate, secureDelete } = useSecureDataAccess();\n * \n * const loadData = async () => {\n * try {\n * // Automatically includes organisation_id filter\n * const events = await secureQuery('event', '*', { is_visible: true });\n * console.log('Organisation events:', events);\n * } catch (error) {\n * console.error('Failed to load data:', error);\n * }\n * };\n * \n * const createEvent = async (eventData) => {\n * try {\n * // Automatically sets organisation_id\n * const newEvent = await secureInsert('event', eventData);\n * console.log('Created event:', newEvent);\n * } catch (error) {\n * console.error('Failed to create event:', error);\n * }\n * };\n * \n * return (\n * <div>\n * <button onClick={loadData}>Load Data</button>\n * <button onClick={() => createEvent({ event_name: 'New Event' })}>\n * Create Event\n * </button>\n * </div>\n * );\n * }\n * ```\n *\n * @security\n * - All queries automatically include organisation_id filter\n * - Validates organisation context before any operation\n * - Prevents data leaks between organisations\n * - Error handling for security violations\n * - Type-safe database operations\n */\n\nimport { useCallback, useState } from 'react';\nimport { useUnifiedAuth } from '../providers/UnifiedAuthProvider';\nimport { useOrganisations } from '../providers/OrganisationProvider';\nimport { setOrganisationContext } from '../utils/organisationContext';\nimport type { Permission } from '../rbac/types';\nimport type { OrganisationSecurityError } from '../types/organisation';\n\nexport interface SecureDataAccessReturn {\n /** Execute a secure query with organisation filtering */\n secureQuery: <T = any>(\n table: string,\n columns: string,\n filters?: Record<string, any>,\n options?: {\n orderBy?: string;\n ascending?: boolean;\n limit?: number;\n offset?: number;\n }\n ) => Promise<T[]>;\n \n /** Execute a secure insert with organisation context */\n secureInsert: <T = any>(\n table: string,\n data: Record<string, any>\n ) => Promise<T>;\n \n /** Execute a secure update with organisation filtering */\n secureUpdate: <T = any>(\n table: string,\n data: Record<string, any>,\n filters: Record<string, any>\n ) => Promise<T[]>;\n \n /** Execute a secure delete with organisation filtering */\n secureDelete: (\n table: string,\n filters: Record<string, any>\n ) => Promise<void>;\n \n /** Execute a secure RPC call with organisation context */\n secureRpc: <T = any>(\n functionName: string,\n params?: Record<string, any>\n ) => Promise<T>;\n \n /** Get current organisation ID */\n getCurrentOrganisationId: () => string;\n \n /** Validate organisation context */\n validateContext: () => void;\n \n // NEW: Phase 1 - Enhanced Security Features\n /** Check if data access is allowed for a table and operation */\n isDataAccessAllowed: (table: string, operation: string) => boolean;\n \n /** Get all data access permissions for current user */\n getDataAccessPermissions: () => Record<string, string[]>;\n \n /** Check if strict mode is enabled */\n isStrictMode: boolean;\n \n /** Check if audit logging is enabled */\n isAuditLogEnabled: boolean;\n \n /** Get data access history */\n getDataAccessHistory: () => DataAccessRecord[];\n \n /** Clear data access history */\n clearDataAccessHistory: () => void;\n \n /** Validate data access attempt */\n validateDataAccess: (table: string, operation: string) => boolean;\n}\n\nexport interface DataAccessRecord {\n table: string;\n operation: string;\n userId: string;\n organisationId: string;\n allowed: boolean;\n timestamp: string;\n query?: string;\n filters?: Record<string, any>;\n}\n\n/**\n * Hook for secure data access with automatic organisation filtering\n * \n * All database operations automatically include organisation context:\n * - Queries filter by organisation_id\n * - Inserts include organisation_id\n * - Updates/deletes are scoped to organisation\n * - RPC calls include organisation_id parameter\n */\nexport function useSecureDataAccess(): SecureDataAccessReturn {\n const { supabase, user, session } = useUnifiedAuth();\n const { ensureOrganisationContext } = useOrganisations();\n\n const validateContext = useCallback((): void => {\n if (!supabase) {\n throw new Error('No Supabase client available') as OrganisationSecurityError;\n }\n if (!user || !session) {\n throw new Error('User must be authenticated with valid session') as OrganisationSecurityError;\n }\n \n try {\n ensureOrganisationContext();\n } catch (error) {\n throw new Error('Organisation context is required for data access') as OrganisationSecurityError;\n }\n }, [supabase, user, session, ensureOrganisationContext]);\n\n const getCurrentOrganisationId = useCallback((): string => {\n validateContext();\n const currentOrg = ensureOrganisationContext();\n return currentOrg.id;\n }, [validateContext, ensureOrganisationContext]);\n\n // Set organisation context in database session\n const setOrganisationContextInSession = useCallback(async (organisationId: string): Promise<void> => {\n if (!supabase) {\n throw new Error('No Supabase client available') as OrganisationSecurityError;\n }\n\n await setOrganisationContext(supabase, organisationId);\n }, [supabase]);\n\n const secureQuery = useCallback(async <T = any>(\n table: string,\n columns: string,\n filters: Record<string, any> = {},\n options: {\n orderBy?: string;\n ascending?: boolean;\n limit?: number;\n offset?: number;\n } = {}\n ): Promise<T[]> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n \n console.log('[useSecureDataAccess] Executing secure query:', {\n table,\n organisationId,\n filters\n });\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Build query with organisation filter\n let query = supabase!\n .from(table)\n .select(columns);\n\n // Add organisation filter only if table has organisation_id column\n const tablesWithOrganisation = [\n 'event', 'organisation_settings',\n 'rbac_event_app_roles', 'rbac_organisation_roles',\n // SECURITY: Phase 2 additions - complete organisation table mapping\n 'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',\n // SECURITY: Emergency additions for Phase 1 fixes\n 'cake_meal', 'cake_mealtype', 'pace_person', 'pace_member',\n // SECURITY: Phase 3A additions - medical and personal data\n 'medi_profile', 'medi_condition', 'medi_diet', 'medi_action_plan', 'medi_profile_versions',\n 'pace_consent', 'pace_contact', 'pace_id_documents', 'pace_qualifications',\n 'form_responses', 'form_response_values', 'forms',\n // SECURITY: Phase 3B additions - remaining critical tables\n 'invoice', 'line_item', 'credit_balance', 'payment_method',\n 'form_contexts', 'form_field_config', 'form_fields',\n 'cake_delivery', 'cake_diettype', 'cake_diner', 'cake_dish', 'cake_item', \n 'cake_logistics', 'cake_mealplan', 'cake_package', 'cake_recipe', 'cake_supplier', \n 'cake_supply', 'cake_unit', 'event_app_access', 'base_application', 'base_questions'\n ];\n \n if (tablesWithOrganisation.includes(table)) {\n query = query.eq('organisation_id', organisationId);\n }\n\n // Apply additional filters\n Object.entries(filters).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n // Handle qualified column names (e.g., 'users.role')\n const columnName = key.includes('.') ? key.split('.').pop()! : key;\n query = query.eq(columnName, value);\n }\n });\n\n // Apply options\n if (options.orderBy) {\n // Only use the column name, not a qualified name\n const orderByColumn = options.orderBy.split('.').pop();\n if (orderByColumn) {\n query = query.order(orderByColumn, { ascending: options.ascending ?? true });\n }\n }\n \n if (options.limit) {\n query = query.limit(options.limit);\n }\n \n if (options.offset) {\n query = query.range(options.offset, options.offset + (options.limit || 100) - 1);\n }\n\n const { data, error } = await query;\n \n if (error) {\n console.error('[useSecureDataAccess] Query failed:', error);\n // NEW: Phase 1 - Record failed data access attempt\n recordDataAccess(table, 'read', false, `SELECT ${columns} FROM ${table}`, filters);\n throw error;\n }\n\n console.log('[useSecureDataAccess] Query successful:', {\n table,\n resultCount: data?.length || 0\n });\n\n // NEW: Phase 1 - Record successful data access attempt\n recordDataAccess(table, 'read', true, `SELECT ${columns} FROM ${table}`, filters);\n\n return (data as T[]) || [];\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n const secureInsert = useCallback(async <T = any>(\n table: string,\n data: Record<string, any>\n ): Promise<T> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n \n console.log('[useSecureDataAccess] Executing secure insert:', {\n table,\n organisationId\n });\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Ensure organisation_id is set\n const secureData = {\n ...data,\n organisation_id: organisationId\n };\n\n const { data: insertData, error } = await supabase!\n .from(table)\n .insert(secureData)\n .select()\n .single();\n\n if (error) {\n console.error('[useSecureDataAccess] Insert failed:', error);\n throw error;\n }\n\n console.log('[useSecureDataAccess] Insert successful:', {\n table,\n id: insertData?.id\n });\n\n return insertData as T;\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n const secureUpdate = useCallback(async <T = any>(\n table: string,\n data: Record<string, any>,\n filters: Record<string, any>\n ): Promise<T[]> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n \n console.log('[useSecureDataAccess] Executing secure update:', {\n table,\n organisationId,\n filters\n });\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Build update query with organisation filter\n let query = supabase!\n .from(table)\n .update(data);\n\n // Add organisation filter only if table has organisation_id column\n const tablesWithOrganisation = [\n 'event', 'organisation_settings',\n 'rbac_event_app_roles', 'rbac_organisation_roles',\n // SECURITY: Phase 2 additions - complete organisation table mapping\n 'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',\n // SECURITY: Emergency additions for Phase 1 fixes\n 'cake_meal', 'cake_mealtype', 'pace_person', 'pace_member'\n ];\n \n if (tablesWithOrganisation.includes(table)) {\n query = query.eq('organisation_id', organisationId);\n }\n\n // Apply filters\n Object.entries(filters).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n query = query.eq(key, value);\n }\n });\n\n const { data: updateData, error } = await query.select();\n\n if (error) {\n console.error('[useSecureDataAccess] Update failed:', error);\n throw error;\n }\n\n console.log('[useSecureDataAccess] Update successful:', {\n table,\n updatedCount: updateData?.length || 0\n });\n\n return (updateData as T[]) || [];\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n const secureDelete = useCallback(async (\n table: string,\n filters: Record<string, any>\n ): Promise<void> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n \n console.log('[useSecureDataAccess] Executing secure delete:', {\n table,\n organisationId,\n filters\n });\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Build delete query with organisation filter\n let query = supabase!\n .from(table)\n .delete();\n\n // Add organisation filter only if table has organisation_id column\n const tablesWithOrganisation = [\n 'event', 'organisation_settings',\n 'rbac_event_app_roles', 'rbac_organisation_roles',\n // SECURITY: Phase 2 additions - complete organisation table mapping\n 'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',\n // SECURITY: Emergency additions for Phase 1 fixes\n 'cake_meal', 'cake_mealtype', 'pace_person', 'pace_member',\n // SECURITY: Phase 3A additions - medical and personal data\n 'medi_profile', 'medi_condition', 'medi_diet', 'medi_action_plan', 'medi_profile_versions',\n 'pace_consent', 'pace_contact', 'pace_id_documents', 'pace_qualifications',\n 'form_responses', 'form_response_values', 'forms',\n // SECURITY: Phase 3B additions - remaining critical tables\n 'invoice', 'line_item', 'credit_balance', 'payment_method',\n 'form_contexts', 'form_field_config', 'form_fields',\n 'cake_delivery', 'cake_diettype', 'cake_diner', 'cake_dish', 'cake_item', \n 'cake_logistics', 'cake_mealplan', 'cake_package', 'cake_recipe', 'cake_supplier', \n 'cake_supply', 'cake_unit', 'event_app_access', 'base_application', 'base_questions'\n ];\n \n if (tablesWithOrganisation.includes(table)) {\n query = query.eq('organisation_id', organisationId);\n }\n\n // Apply filters\n Object.entries(filters).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n query = query.eq(key, value);\n }\n });\n\n const { error } = await query;\n\n if (error) {\n console.error('[useSecureDataAccess] Delete failed:', error);\n throw error;\n }\n\n console.log('[useSecureDataAccess] Delete successful:', {\n table\n });\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n const secureRpc = useCallback(async <T = any>(\n functionName: string,\n params: Record<string, any> = {}\n ): Promise<T> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n \n console.log('[useSecureDataAccess] Executing secure RPC:', {\n functionName,\n organisationId\n });\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Include organisation_id in RPC parameters\n const secureParams = {\n ...params,\n organisation_id: organisationId\n };\n\n const { data, error } = await supabase!.rpc(functionName, secureParams);\n\n if (error) {\n console.error('[useSecureDataAccess] RPC failed:', error);\n throw error;\n }\n\n console.log('[useSecureDataAccess] RPC successful:', {\n functionName\n });\n\n return data as T;\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n // NEW: Phase 1 - Enhanced Security Features\n const [dataAccessHistory, setDataAccessHistory] = useState<DataAccessRecord[]>([]);\n const [isStrictMode] = useState(true); // Always enabled in Phase 1\n const [isAuditLogEnabled] = useState(true); // Always enabled in Phase 1\n\n // Check if data access is allowed for a table and operation\n const isDataAccessAllowed = useCallback((table: string, operation: string): boolean => {\n if (!user?.id) return false;\n \n // Use the existing RBAC system to check data access permissions\n // This is a synchronous check for the context - actual permission checking\n // happens in the secure data operations using the RBAC engine\n const permission = `${operation}:data.${table}` as Permission;\n \n // For now, we'll return true and let the secure data operations\n // handle the actual permission checking asynchronously\n // This context is mainly for tracking and audit purposes\n return true;\n }, [user?.id]);\n\n // Get all data access permissions for current user\n const getDataAccessPermissions = useCallback((): Record<string, string[]> => {\n if (!user?.id) return {};\n \n // For now, return empty object - this will be enhanced with actual permission checking\n // when we integrate with the existing RBAC system\n return {};\n }, [user?.id]);\n\n // Get data access history\n const getDataAccessHistory = useCallback((): DataAccessRecord[] => {\n return [...dataAccessHistory];\n }, [dataAccessHistory]);\n\n // Clear data access history\n const clearDataAccessHistory = useCallback(() => {\n setDataAccessHistory([]);\n }, []);\n\n // Validate data access attempt\n const validateDataAccess = useCallback((table: string, operation: string): boolean => {\n if (!user?.id) return false;\n \n // Validate organisation context\n try {\n validateContext();\n } catch (error) {\n console.error(`[useSecureDataAccess] Organisation context validation failed:`, error);\n return false;\n }\n \n return isDataAccessAllowed(table, operation);\n }, [user?.id, validateContext, isDataAccessAllowed]);\n\n // Record data access attempt\n const recordDataAccess = useCallback((\n table: string,\n operation: string,\n allowed: boolean,\n query?: string,\n filters?: Record<string, any>\n ) => {\n if (!isAuditLogEnabled || !user?.id) return;\n \n const record: DataAccessRecord = {\n table,\n operation,\n userId: user.id,\n organisationId: getCurrentOrganisationId(),\n allowed,\n timestamp: new Date().toISOString(),\n query,\n filters\n };\n \n setDataAccessHistory(prev => {\n const newHistory = [record, ...prev];\n return newHistory.slice(0, 1000); // Keep last 1000 records\n });\n \n if (isStrictMode && !allowed) {\n console.error(`[useSecureDataAccess] STRICT MODE VIOLATION: User attempted data access without permission`, {\n table,\n operation,\n userId: user.id,\n organisationId: getCurrentOrganisationId(),\n timestamp: new Date().toISOString()\n });\n }\n }, [isAuditLogEnabled, isStrictMode, user?.id, getCurrentOrganisationId]);\n\n return {\n secureQuery,\n secureInsert,\n secureUpdate,\n secureDelete,\n secureRpc,\n getCurrentOrganisationId,\n validateContext,\n // NEW: Phase 1 - Enhanced Security Features\n isDataAccessAllowed,\n getDataAccessPermissions,\n isStrictMode,\n isAuditLogEnabled,\n getDataAccessHistory,\n clearDataAccessHistory,\n validateDataAccess\n };\n} "],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useSecureDataAccess.ts"],"sourcesContent":["/**\n * @file useSecureDataAccess Hook\n * @package @jmruthers/pace-core\n * @module Hooks/useSecureDataAccess\n * @since 0.4.0\n *\n * Hook for secure database operations with mandatory organisation context.\n * Ensures all data access is properly scoped to the user's current organisation.\n *\n * @example\n * ```tsx\n * function DataComponent() {\n * const { secureQuery, secureInsert, secureUpdate, secureDelete } = useSecureDataAccess();\n * \n * const loadData = async () => {\n * try {\n * // Automatically includes organisation_id filter\n * const events = await secureQuery('event', '*', { is_visible: true });\n * console.log('Organisation events:', events);\n * } catch (error) {\n * console.error('Failed to load data:', error);\n * }\n * };\n * \n * const createEvent = async (eventData) => {\n * try {\n * // Automatically sets organisation_id\n * const newEvent = await secureInsert('event', eventData);\n * console.log('Created event:', newEvent);\n * } catch (error) {\n * console.error('Failed to create event:', error);\n * }\n * };\n * \n * return (\n * <div>\n * <button onClick={loadData}>Load Data</button>\n * <button onClick={() => createEvent({ event_name: 'New Event' })}>\n * Create Event\n * </button>\n * </div>\n * );\n * }\n * ```\n *\n * @security\n * - All queries automatically include organisation_id filter\n * - Validates organisation context before any operation\n * - Prevents data leaks between organisations\n * - Error handling for security violations\n * - Type-safe database operations\n */\n\nimport { useCallback, useState } from 'react';\nimport { useUnifiedAuth } from '../providers/UnifiedAuthProvider';\nimport { useOrganisations } from '../providers/OrganisationProvider';\nimport { setOrganisationContext } from '../utils/organisationContext';\nimport type { Permission } from '../rbac/types';\nimport type { OrganisationSecurityError } from '../types/organisation';\n\nexport interface SecureDataAccessReturn {\n /** Execute a secure query with organisation filtering */\n secureQuery: <T = any>(\n table: string,\n columns: string,\n filters?: Record<string, any>,\n options?: {\n orderBy?: string;\n ascending?: boolean;\n limit?: number;\n offset?: number;\n }\n ) => Promise<T[]>;\n \n /** Execute a secure insert with organisation context */\n secureInsert: <T = any>(\n table: string,\n data: Record<string, any>\n ) => Promise<T>;\n \n /** Execute a secure update with organisation filtering */\n secureUpdate: <T = any>(\n table: string,\n data: Record<string, any>,\n filters: Record<string, any>\n ) => Promise<T[]>;\n \n /** Execute a secure delete with organisation filtering */\n secureDelete: (\n table: string,\n filters: Record<string, any>\n ) => Promise<void>;\n \n /** Execute a secure RPC call with organisation context */\n secureRpc: <T = any>(\n functionName: string,\n params?: Record<string, any>\n ) => Promise<T>;\n \n /** Get current organisation ID */\n getCurrentOrganisationId: () => string;\n \n /** Validate organisation context */\n validateContext: () => void;\n \n // NEW: Phase 1 - Enhanced Security Features\n /** Check if data access is allowed for a table and operation */\n isDataAccessAllowed: (table: string, operation: string) => boolean;\n \n /** Get all data access permissions for current user */\n getDataAccessPermissions: () => Record<string, string[]>;\n \n /** Check if strict mode is enabled */\n isStrictMode: boolean;\n \n /** Check if audit logging is enabled */\n isAuditLogEnabled: boolean;\n \n /** Get data access history */\n getDataAccessHistory: () => DataAccessRecord[];\n \n /** Clear data access history */\n clearDataAccessHistory: () => void;\n \n /** Validate data access attempt */\n validateDataAccess: (table: string, operation: string) => boolean;\n}\n\nexport interface DataAccessRecord {\n table: string;\n operation: string;\n userId: string;\n organisationId: string;\n allowed: boolean;\n timestamp: string;\n query?: string;\n filters?: Record<string, any>;\n}\n\n/**\n * Hook for secure data access with automatic organisation filtering\n * \n * All database operations automatically include organisation context:\n * - Queries filter by organisation_id\n * - Inserts include organisation_id\n * - Updates/deletes are scoped to organisation\n * - RPC calls include organisation_id parameter\n */\nexport function useSecureDataAccess(): SecureDataAccessReturn {\n const { supabase, user, session } = useUnifiedAuth();\n const { ensureOrganisationContext } = useOrganisations();\n\n const validateContext = useCallback((): void => {\n if (!supabase) {\n throw new Error('No Supabase client available') as OrganisationSecurityError;\n }\n if (!user || !session) {\n throw new Error('User must be authenticated with valid session') as OrganisationSecurityError;\n }\n \n try {\n ensureOrganisationContext();\n } catch (error) {\n throw new Error('Organisation context is required for data access') as OrganisationSecurityError;\n }\n }, [supabase, user, session, ensureOrganisationContext]);\n\n const getCurrentOrganisationId = useCallback((): string => {\n validateContext();\n const currentOrg = ensureOrganisationContext();\n return currentOrg.id;\n }, [validateContext, ensureOrganisationContext]);\n\n // Set organisation context in database session\n const setOrganisationContextInSession = useCallback(async (organisationId: string): Promise<void> => {\n if (!supabase) {\n throw new Error('No Supabase client available') as OrganisationSecurityError;\n }\n\n await setOrganisationContext(supabase, organisationId);\n }, [supabase]);\n\n const secureQuery = useCallback(async <T = any>(\n table: string,\n columns: string,\n filters: Record<string, any> = {},\n options: {\n orderBy?: string;\n ascending?: boolean;\n limit?: number;\n offset?: number;\n } = {}\n ): Promise<T[]> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n \n console.log('[useSecureDataAccess] Executing secure query:', {\n table,\n organisationId,\n filters\n });\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Build query with organisation filter\n let query = supabase!\n .from(table)\n .select(columns);\n\n // Add organisation filter only if table has organisation_id column\n const tablesWithOrganisation = [\n 'event', 'organisation_settings',\n 'rbac_event_app_roles', 'rbac_organisation_roles',\n // SECURITY: Phase 2 additions - complete organisation table mapping\n 'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',\n // SECURITY: Emergency additions for Phase 1 fixes\n 'cake_meal', 'cake_mealtype', 'pace_person', 'pace_member',\n // SECURITY: Phase 3A additions - medical and personal data\n 'medi_profile', 'medi_condition', 'medi_diet', 'medi_action_plan', 'medi_profile_versions',\n 'pace_consent', 'pace_contact', 'pace_id_documents', 'pace_qualifications',\n 'form_responses', 'form_response_values', 'forms',\n // SECURITY: Phase 3B additions - remaining critical tables\n 'invoice', 'line_item', 'credit_balance', 'payment_method',\n 'form_contexts', 'form_field_config', 'form_fields',\n 'cake_delivery', 'cake_diettype', 'cake_diner', 'cake_dish', 'cake_item', \n 'cake_logistics', 'cake_mealplan', 'cake_package', 'cake_recipe', 'cake_supplier', \n 'cake_supply', 'cake_unit', 'event_app_access', 'base_application', 'base_questions'\n ];\n \n if (tablesWithOrganisation.includes(table)) {\n query = query.eq('organisation_id', organisationId);\n }\n\n // Apply additional filters\n Object.entries(filters).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n // Handle qualified column names (e.g., 'users.role')\n const columnName = key.includes('.') ? key.split('.').pop()! : key;\n query = query.eq(columnName, value);\n }\n });\n\n // Apply options\n if (options.orderBy) {\n // Only use the column name, not a qualified name\n const orderByColumn = options.orderBy.split('.').pop();\n if (orderByColumn) {\n query = query.order(orderByColumn, { ascending: options.ascending ?? true });\n }\n }\n \n if (options.limit) {\n query = query.limit(options.limit);\n }\n \n if (options.offset) {\n query = query.range(options.offset, options.offset + (options.limit || 100) - 1);\n }\n\n const { data, error } = await query;\n \n if (error) {\n console.error('[useSecureDataAccess] Query failed:', error);\n // NEW: Phase 1 - Record failed data access attempt\n recordDataAccess(table, 'read', false, `SELECT ${columns} FROM ${table}`, filters);\n throw error;\n }\n\n console.log('[useSecureDataAccess] Query successful:', {\n table,\n resultCount: data?.length || 0\n });\n\n // NEW: Phase 1 - Record successful data access attempt\n recordDataAccess(table, 'read', true, `SELECT ${columns} FROM ${table}`, filters);\n\n return (data as T[]) || [];\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n const secureInsert = useCallback(async <T = any>(\n table: string,\n data: Record<string, any>\n ): Promise<T> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n \n console.log('[useSecureDataAccess] Executing secure insert:', {\n table,\n organisationId\n });\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Ensure organisation_id is set\n const secureData = {\n ...data,\n organisation_id: organisationId\n };\n\n const { data: insertData, error } = await supabase!\n .from(table)\n .insert(secureData)\n .select()\n .single();\n\n if (error) {\n console.error('[useSecureDataAccess] Insert failed:', error);\n throw error;\n }\n\n console.log('[useSecureDataAccess] Insert successful:', {\n table,\n id: insertData?.id\n });\n\n return insertData as T;\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n const secureUpdate = useCallback(async <T = any>(\n table: string,\n data: Record<string, any>,\n filters: Record<string, any>\n ): Promise<T[]> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n \n console.log('[useSecureDataAccess] Executing secure update:', {\n table,\n organisationId,\n filters\n });\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Build update query with organisation filter\n let query = supabase!\n .from(table)\n .update(data);\n\n // Add organisation filter only if table has organisation_id column\n const tablesWithOrganisation = [\n 'event', 'organisation_settings',\n 'rbac_event_app_roles', 'rbac_organisation_roles',\n // SECURITY: Phase 2 additions - complete organisation table mapping\n 'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',\n // SECURITY: Emergency additions for Phase 1 fixes\n 'cake_meal', 'cake_mealtype', 'pace_person', 'pace_member'\n ];\n \n if (tablesWithOrganisation.includes(table)) {\n query = query.eq('organisation_id', organisationId);\n }\n\n // Apply filters\n Object.entries(filters).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n query = query.eq(key, value);\n }\n });\n\n const { data: updateData, error } = await query.select();\n\n if (error) {\n console.error('[useSecureDataAccess] Update failed:', error);\n throw error;\n }\n\n console.log('[useSecureDataAccess] Update successful:', {\n table,\n updatedCount: updateData?.length || 0\n });\n\n return (updateData as T[]) || [];\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n const secureDelete = useCallback(async (\n table: string,\n filters: Record<string, any>\n ): Promise<void> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n \n console.log('[useSecureDataAccess] Executing secure delete:', {\n table,\n organisationId,\n filters\n });\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Build delete query with organisation filter\n let query = supabase!\n .from(table)\n .delete();\n\n // Add organisation filter only if table has organisation_id column\n const tablesWithOrganisation = [\n 'event', 'organisation_settings',\n 'rbac_event_app_roles', 'rbac_organisation_roles',\n // SECURITY: Phase 2 additions - complete organisation table mapping\n 'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',\n // SECURITY: Emergency additions for Phase 1 fixes\n 'cake_meal', 'cake_mealtype', 'pace_person', 'pace_member',\n // SECURITY: Phase 3A additions - medical and personal data\n 'medi_profile', 'medi_condition', 'medi_diet', 'medi_action_plan', 'medi_profile_versions',\n 'pace_consent', 'pace_contact', 'pace_id_documents', 'pace_qualifications',\n 'form_responses', 'form_response_values', 'forms',\n // SECURITY: Phase 3B additions - remaining critical tables\n 'invoice', 'line_item', 'credit_balance', 'payment_method',\n 'form_contexts', 'form_field_config', 'form_fields',\n 'cake_delivery', 'cake_diettype', 'cake_diner', 'cake_dish', 'cake_item', \n 'cake_logistics', 'cake_mealplan', 'cake_package', 'cake_recipe', 'cake_supplier', \n 'cake_supply', 'cake_unit', 'event_app_access', 'base_application', 'base_questions'\n ];\n \n if (tablesWithOrganisation.includes(table)) {\n query = query.eq('organisation_id', organisationId);\n }\n\n // Apply filters\n Object.entries(filters).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n query = query.eq(key, value);\n }\n });\n\n const { error } = await query;\n\n if (error) {\n console.error('[useSecureDataAccess] Delete failed:', error);\n throw error;\n }\n\n console.log('[useSecureDataAccess] Delete successful:', {\n table\n });\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n const secureRpc = useCallback(async <T = any>(\n functionName: string,\n params: Record<string, any> = {}\n ): Promise<T> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n \n console.log('[useSecureDataAccess] Executing secure RPC:', {\n functionName,\n organisationId\n });\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Include organisation_id in RPC parameters\n const secureParams = {\n ...params,\n organisation_id: organisationId\n };\n\n const { data, error } = await supabase!.rpc(functionName, secureParams);\n\n if (error) {\n console.error('[useSecureDataAccess] RPC failed:', error);\n throw error;\n }\n\n console.log('[useSecureDataAccess] RPC successful:', {\n functionName\n });\n\n return data as T;\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n // NEW: Phase 1 - Enhanced Security Features\n const [dataAccessHistory, setDataAccessHistory] = useState<DataAccessRecord[]>([]);\n const [isStrictMode] = useState(true); // Always enabled in Phase 1\n const [isAuditLogEnabled] = useState(true); // Always enabled in Phase 1\n\n // Check if data access is allowed for a table and operation\n const isDataAccessAllowed = useCallback((table: string, operation: string): boolean => {\n if (!user?.id) return false;\n \n // Use the existing RBAC system to check data access permissions\n // This is a synchronous check for the context - actual permission checking\n // happens in the secure data operations using the RBAC engine\n const permission = `${operation}:data.${table}` as Permission;\n \n // For now, we'll return true and let the secure data operations\n // handle the actual permission checking asynchronously\n // This context is mainly for tracking and audit purposes\n return true;\n }, [user?.id]);\n\n // Get all data access permissions for current user\n const getDataAccessPermissions = useCallback((): Record<string, string[]> => {\n if (!user?.id) return {};\n \n // For now, return empty object - this will be enhanced with actual permission checking\n // when we integrate with the existing RBAC system\n return {};\n }, [user?.id]);\n\n // Get data access history\n const getDataAccessHistory = useCallback((): DataAccessRecord[] => {\n return [...dataAccessHistory];\n }, [dataAccessHistory]);\n\n // Clear data access history\n const clearDataAccessHistory = useCallback(() => {\n setDataAccessHistory([]);\n }, []);\n\n // Validate data access attempt\n const validateDataAccess = useCallback((table: string, operation: string): boolean => {\n if (!user?.id) return false;\n \n // Validate organisation context\n try {\n validateContext();\n } catch (error) {\n console.error(`[useSecureDataAccess] Organisation context validation failed:`, error);\n return false;\n }\n \n return isDataAccessAllowed(table, operation);\n }, [user?.id, validateContext, isDataAccessAllowed]);\n\n // Record data access attempt\n const recordDataAccess = useCallback((\n table: string,\n operation: string,\n allowed: boolean,\n query?: string,\n filters?: Record<string, any>\n ) => {\n if (!isAuditLogEnabled || !user?.id) return;\n \n const record: DataAccessRecord = {\n table,\n operation,\n userId: user.id,\n organisationId: getCurrentOrganisationId(),\n allowed,\n timestamp: new Date().toISOString(),\n query,\n filters\n };\n \n setDataAccessHistory(prev => {\n const newHistory = [record, ...prev];\n return newHistory.slice(0, 1000); // Keep last 1000 records\n });\n \n if (isStrictMode && !allowed) {\n console.error(`[useSecureDataAccess] STRICT MODE VIOLATION: User attempted data access without permission`, {\n table,\n operation,\n userId: user.id,\n organisationId: getCurrentOrganisationId(),\n timestamp: new Date().toISOString()\n });\n }\n }, [isAuditLogEnabled, isStrictMode, user?.id, getCurrentOrganisationId]);\n\n return {\n secureQuery,\n secureInsert,\n secureUpdate,\n secureDelete,\n secureRpc,\n getCurrentOrganisationId,\n validateContext,\n // NEW: Phase 1 - Enhanced Security Features\n isDataAccessAllowed,\n getDataAccessPermissions,\n isStrictMode,\n isAuditLogEnabled,\n getDataAccessHistory,\n clearDataAccessHistory,\n validateDataAccess\n };\n} "],"mappings":"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","names":[]}
|
package/dist/components.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { b as UnifiedAuthContextType, U as UnifiedAuthProvider, a as UnifiedAuthProviderProps, u as useUnifiedAuth } from './UnifiedAuthProvider-w66zSCUf.js';
|
|
2
2
|
export { A as Alert, r as AlertDescription, q as AlertTitle, s as Avatar, u as AvatarFallback, t as AvatarImage, B as Button, g as ButtonProps, C as Card, m as CardActions, b6 as CardActionsProps, l as CardContent, k as CardDescription, i as CardFooter, h as CardHeader, n as CardProps, j as CardTitle, v as Checkbox, aX as DefaultPublicErrorFallback, D as Dialog, H as DialogBody, z as DialogClose, E as DialogContent, b9 as DialogContentProps, M as DialogDescription, be as DialogDescriptionProps, J as DialogFooter, bc as DialogFooterProps, G as DialogHeader, bb as DialogHeaderProps, x as DialogOverlay, ba as DialogOverlayProps, w as DialogPortal, b7 as DialogProps, bf as DialogSize, K as DialogTitle, bd as DialogTitleProps, y as DialogTrigger, b8 as DialogTriggerProps, aq as ErrorBoundary, bi as ErrorBoundaryProps, bj as ErrorBoundaryState, aS as EventLogo, aT as EventLogoCompact, aU as EventLogoLarge, b2 as EventLogoProps, as as EventSelector, av as FileUpload, aw as FileUploadProps, af as Footer, ag as FooterProps, ab as Form, bg as FormProps, ae as Header, I as Input, o as InputProps, L as Label, p as LabelProps, ar as LoadingSpinner, ac as LoginForm, ad as LoginFormProps, aj as NavigationItem, ah as NavigationMenu, ai as NavigationMenuProps, at as OrganisationSelector, bh as OrganisationSelectorProps, am as PaceAppLayout, an as PaceAppLayoutProps, ao as PaceLoginPage, ap as PaceLoginPageProps, au as PasswordResetForm, P as Progress, aV as PublicErrorBoundary, b3 as PublicErrorBoundaryProps, b4 as PublicErrorBoundaryState, a_ as PublicLoadingSkeleton, aY as PublicLoadingSpinner, aZ as PublicLoadingSpinnerFullPage, b5 as PublicLoadingSpinnerProps, aR as PublicPageContextChecker, aP as PublicPageDebugger, aQ as PublicPageDiagnostic, aO as PublicPageFooter, b1 as PublicPageFooterProps, aK as PublicPageHeader, b0 as PublicPageHeaderProps, aI as PublicPageLayout, a$ as PublicPageLayoutProps, aL as PublicPageProvider, N as Select, T as SelectContent, O as SelectGroup, V as SelectItem, U as SelectLabel, W as SelectSeparator, R as SelectTrigger, Q as SelectValue, az as Table, aB as TableBody, aC as TableCaption, aD as TableCell, aE as TableFooter, aF as TableHead, aA as TableHeader, aG as TableRow, X as Toast, Z as ToastAction, a4 as ToastActionElement, a2 as ToastClose, a1 as ToastDescription, a5 as ToastProps, _ as ToastProvider, a0 as ToastTitle, $ as ToastViewport, Y as Toaster, a6 as Tooltip, a8 as TooltipContent, a9 as TooltipProvider, aa as TooltipRoot, a7 as TooltipTrigger, bk as UseStorageOptions, bl as UseStorageReturn, ak as UserMenu, aW as useErrorBoundary, ay as useFileUpload, aN as useIsPublicPage, aJ as usePublicPageContext, aM as usePublicPageProviderContext, ax as useStorage, a3 as useToast } from './PublicLoadingSpinner-DztrzuJr.js';
|
|
3
|
-
export { D as DataTable, a as DataTableProps } from './DataTable-
|
|
4
|
-
export { A as AggregateConfig, D as DataRecord,
|
|
3
|
+
export { D as DataTable, a as DataTableProps } from './DataTable-ltTFXHS3.js';
|
|
4
|
+
export { A as AggregateConfig, D as DataRecord, f as DataTableAction, a as DataTableColumn, g as DataTableToolbarButton, E as EmptyStateConfig, G as GetRowId } from './types-BRDU7N6w.js';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
6
|
import React__default, { ReactNode, ComponentType } from 'react';
|
|
7
7
|
import { FieldValues, FieldPath, UseFormReturn } from 'react-hook-form';
|